← Back to team overview

graphite-dev team mailing list archive

[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