Min/max/avg stats printed in or near graphs
Closed this issue · 8 comments
Munin does this in the graph legend; I don't think Graphite is capable of that, but double check. If not, then if we can get a good "graph related stats" dump as mentioned in #13, we can print this info under/next to the graphs via HTML.
Have min/max/avg working now, if simplistically. Need to clean up presentation a bit (both re: HTML and re: format of the numbers themselves.)
HTML slightly better, number units/formatting still needs to be done. Will either copypasta the relatively small bit of code from Graphite which does the same job for in-graph number text (need to figure out how it generates the "step" parameter though) or tweak our version of graphite to expose that as a simple Web hook.
Possibly including the stats I generate myself -- sort of a "give me the stats for this metric instead of / in addition to the raw numbers" version of rawData=true
. Probably a much easier road to go down.
Notes on how Graphite renders a graph (which is when it infers the scale/unit of the Y axes):
- In
render/views.py:renderView()
, line 166, is what actually renders the image- via
doImageRender(graphClass, graph_options)
- which instantiates
graphClass
, an instance of somerender/glyph.py:Graph
subclass, asks it to render itself onto a StringIO, then returns that StringIO'sgetvalue
(i.e. it's working around the requirement for a file-like object)
- which instantiates
- The resulting image data gets passed to
buildResponse
which just sets up animage/png
response obj and returns it.
- via
- So the minimum work needed to take the same args this view does and return the Y-axis unit, would be:
- Update
Graph
so it's capable of returning that Y-axis unit info as a method call- it generates the graph in
__init__
, so all that should be necessary isGraph(opts).my_new_method()
- it generates the graph in
- Make new view that instantiates, calls new method, returns as JSON/whatever
- Update
- However, I definitely think it'd be best to make some sort of "combined" version of
render
that returns:- the graph image (if possible, need a memory refresh)
- maybe the sub-metric paths, i.e. the same work we do inside Fullerene now; if Graphite has no native way to do what we're doing (I think it probably does) then move it in here instead
- min/max/mean stats, again like what Fullerene does; with the right unit (as per above)
- anything else?
N.B. Another solution could be just to do a Munin style tabular legend with min/max/etc, but going by the current Graphite legend implementation, I don't think that fits well -- it has other things like 2 Y-axes and a focus on shortening/hiding the legend in some situations, which would complicate a tabular/very wide layout.
Updating logic to handle another option overriding those concerns and forcing tabular layout would also be a little funky.
Will revisit this if implementing the previous comment's ideas turns out to be too hard.
Definitely think the ideal way to handle this is adding the calculated values to the json
view (which I am now using in my own stats generation as of the last few commits.) Only problem becomes that of the actual graph related calculations (e.g. the Y-axis units) because normally, /render/?format=json
(or raw
) skips actual graph rendering.
If I can find a good way to wrench out the unit-related stuff so it can be run without actually performing the full graph render, that'd be ideal. But perhaps start out by just rendering and not returning the graph, and work backwards from that. (Again, truly ideally, return both at the same time, but it doesn't look like Requests, and maybe Django either, support multipart response objects.)
Introspecting some live LineGraph
objects on monitor2
, based on instantiating requestOptions['graphClass'](**graphOptions)
near bottom of render()
(so, should be able to do the same inside the JSON response part which is shortly above, assuming graphOptions
is filled out well before.):
yBottom
,yTop
,yStep
: the Y-axis bounds & the step it's drawn atparams['yUnitSystem']
- they key used forglyph.UnitSystems
, i.e. either"si"
or"binary"
.- With just those two, I could conceivably call
glyph.format_units(value, step, system)
on my existing min/max/mean values.
N.B. the data series objects themselves (TimeSeries
) do not appear to define min/max/mean; would've been nice, but no biggie. Just making sure we're not duplicating work.
Graphite's JSON view now returns the stats we were generating ourselves, and with 'correctly' formatted versions alongside (with K/M/G etc suffixes). Requires the master branch of my Graphite fork.
Time to work on #8.