graphite-dev team mailing list archive
-
graphite-dev team
-
Mailing list archive
-
Message #01255
[Merge] lp:~magec/graphite/stacked-experiment into lp:graphite
magec has proposed merging lp:~magec/graphite/stacked-experiment into lp:graphite.
Requested reviews:
graphite-dev (graphite-dev)
For more details, see:
https://code.launchpad.net/~magec/graphite/stacked-experiment/+merge/73033
Currently there is no way of mixin stacked metrics with non stacked ones. The areaMode is set globally, but in certain situations a more fine-grained control could be neccessary. In order to allow that I implemented a new Special function called "stacked" when a given metric is stacked it will add its values to the current stacked metrics, so the mixin could be possible.
--
https://code.launchpad.net/~magec/graphite/stacked-experiment/+merge/73033
Your team graphite-dev is requested to review the proposed merge of lp:~magec/graphite/stacked-experiment into lp:graphite.
=== modified file 'webapp/content/js/composer_widgets.js'
--- webapp/content/js/composer_widgets.js 2011-07-30 03:25:38 +0000
+++ webapp/content/js/composer_widgets.js 2011-08-26 12:33:35 +0000
@@ -939,6 +939,7 @@
{text: 'Keep Last Value', handler: applyFuncToEach('keepLastValue')},
{text: 'Substring', handler: applyFuncToEachWithInput('substr', 'Enter a starting position')},
{text: 'Add Threshold Line', handler: applyFuncToEachWithInput('threshold', 'Enter a threshold value')},
+ {text: 'Draw Stacked', handler: applyFuncToEach('stacked')},
{text: 'Draw in Second Y Axis', handler: applyFuncToEach('secondYAxis')}
]
}
=== modified file 'webapp/graphite/render/datalib.py'
--- webapp/graphite/render/datalib.py 2011-08-15 22:11:02 +0000
+++ webapp/graphite/render/datalib.py 2011-08-26 12:33:35 +0000
@@ -27,6 +27,10 @@
class TimeSeries(list):
+
+ # This is used to calculate the values when using the stacked function
+ totalStack = []
+
def __init__(self, name, start, end, step, values, consolidate='average'):
self.name = name
self.start = start
=== modified file 'webapp/graphite/render/functions.py'
--- webapp/graphite/render/functions.py 2011-08-24 07:06:40 +0000
+++ webapp/graphite/render/functions.py 2011-08-26 12:33:35 +0000
@@ -556,6 +556,40 @@
return results
+def stacked(requestContext,seriesLists):
+ """
+ Takes one metric or a wildcard seriesList and change them so they are
+ stacked. This is a way of stacking just a couple of metrics without having
+ to use the stacked area mode (that stacks everything). By means of this a mixed
+ stacked and non stacked graph can be made
+
+ Example:
+
+ .. code-block:: none
+
+ &target=stacked(company.server.application01.ifconfig.TXPackets)
+
+ """
+ results = []
+ totalStack = TimeSeries.totalStack;
+ for series in seriesLists:
+ newValues = []
+ for i in range(len(series)):
+ if len(totalStack) <= i: totalStack.append(0)
+
+ if series[i] is not None:
+ totalStack[i] += series[i]
+ newValues.append(totalStack[i])
+ else:
+ newValues.append(None)
+
+ newName = "stacked(%s)" % series.name
+ newSeries = TimeSeries(newName, series.start, series.end, series.step, newValues)
+ newSeries.options['stacked'] = True
+ newSeries.pathExpression = newName
+ results.append(newSeries)
+ return results
+
def alias(requestContext, seriesList, newName):
"""
@@ -1577,6 +1611,7 @@
'group' : group,
'exclude' : exclude,
'constantLine' : constantLine,
+ 'stacked' : stacked,
'threshold' : threshold,
# test functions
=== modified file 'webapp/graphite/render/glyph.py'
--- webapp/graphite/render/glyph.py 2011-08-20 05:55:27 +0000
+++ webapp/graphite/render/glyph.py 2011-08-26 12:33:35 +0000
@@ -420,6 +420,10 @@
validPieModes = ('maximum', 'minimum', 'average')
def drawGraph(self,**params):
+ # Initialization of the totakStack values
+ for i in range(len(TimeSeries.totalStack)):
+ TimeSeries.totalStack[i] = 0
+
#API compatibilty hacks first
if params.get('graphOnly',False):
params['hideLegend'] = True
@@ -626,6 +630,13 @@
self.data = reverse_sort(self.data)
+ # Check whether there is an stacked metric
+ singleStacked = False;
+ for series in self.data:
+ if series.options.has_key("stacked"):
+ singleStacked = True
+ if singleStacked: self.data = reverse_sort_stacked(self.data)
+
# setup the clip region
self.ctx.set_line_width(1.0)
self.ctx.rectangle(self.area['xmin'], self.area['ymin'], self.area['xmax'] - self.area['xmin'], self.area['ymax'] - self.area['ymin'])
@@ -663,7 +674,7 @@
value = 0.0
if value is None:
- if not fromNone and self.areaMode != 'none': #Close off and fill area before unknown interval
+ if not fromNone and self.areaMode != 'none' or series.options.has_key('stacked'): #Close off and fill area before unknown interval
self.ctx.line_to(x, self.area['ymax'])
self.ctx.close_path()
self.ctx.fill()
@@ -707,7 +718,7 @@
elif self.lineMode == 'slope':
if fromNone:
- if self.areaMode != 'none':
+ if self.areaMode != 'none' or series.options.has_key('stacked'):
self.ctx.move_to(x, self.area['ymax'])
self.ctx.line_to(x, y)
else:
@@ -1378,6 +1389,22 @@
aux_list.reverse()
return aux_list
+def reverse_sort_stacked(args):
+ # There should be a better way of doing so, but my python is not so good
+ result = []
+ stacked = []
+ nonStacked = []
+ for arg in args:
+ if arg.options.has_key("stacked"):
+ stacked.append(arg)
+ else:
+ nonStacked.append(arg)
+ stacked.reverse()
+ for series in stacked:
+ result.append(series)
+ for series in nonStacked:
+ result.append(series)
+ return result
def format_units(v, step, system="si"):
"""Format the given value in standardized units.
Follow ups