Package ZenModel :: Module RRDGraph
[hide private]
[frames] | no frames]

Source Code for Module ZenModel.RRDGraph

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 as published by 
  8  # the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13   
 14  __doc__="""RRDGraph 
 15   
 16  RRDGraph defines the global options for an rrdtool graph. 
 17  """ 
 18   
 19  ########################################################################### 
 20  # 
 21  # RRDGraph is deprecated.  GraphDefinition is now used in its place. 
 22  # RRDGraph.py can be removed from zenoss post 2.1 
 23  # 
 24  ########################################################################### 
 25   
 26  import os 
 27  import re 
 28  import time 
 29   
 30  from Globals import DTMLFile 
 31  from Globals import InitializeClass 
 32  from AccessControl import ClassSecurityInfo, Permissions 
 33   
 34  from Products.ZenRelations.RelSchema import * 
 35  from Products.ZenUtils.ZenTales import talesEval 
 36   
 37  from ZenModelRM import ZenModelRM 
 38   
 39   
40 -def manage_addRRDGraph(context, id, REQUEST = None):
41 """make a RRDGraph""" 42 graph = RRDGraph(id) 43 context._setObject(graph.id, graph) 44 if REQUEST is not None: 45 REQUEST['RESPONSE'].redirect(context.absolute_url()+'/manage_main')
46 47 48 addRRDGraph = DTMLFile('dtml/addRRDGraph',globals()) 49 50
51 -class RRDGraph(ZenModelRM):
52 53 meta_type = 'RRDGraph' 54 55 security = ClassSecurityInfo() 56 57 dsnames = [] 58 sequence = 0 59 height = 100 60 width = 500 61 threshmap = [] 62 units = "" 63 log = False 64 linewidth = 1 65 base = False 66 stacked = False 67 summary = True 68 miny = -1 69 maxy = -1 70 custom = "" 71 hasSummary = True 72 73 74 _properties = ( 75 {'id':'dsnames', 'type':'lines', 'mode':'w'}, 76 {'id':'sequence', 'type':'int', 'mode':'w'}, 77 {'id':'height', 'type':'int', 'mode':'w'}, 78 {'id':'width', 'type':'int', 'mode':'w'}, 79 {'id':'units', 'type':'string', 'mode':'w'}, 80 {'id':'linewidth', 'type':'int', 'mode':'w'}, 81 {'id':'log', 'type':'boolean', 'mode':'w'}, 82 {'id':'base', 'type':'boolean', 'mode':'w'}, 83 {'id':'stacked', 'type':'boolean', 'mode':'w'}, 84 {'id':'summary', 'type':'boolean', 'mode':'w'}, 85 {'id':'miny', 'type':'int', 'mode':'w'}, 86 {'id':'maxy', 'type':'int', 'mode':'w'}, 87 {'id':'colors', 'type':'lines', 'mode':'w'}, 88 {'id':'custom', 'type':'text', 'mode':'w'}, 89 {'id':'hasSummary', 'type':'boolean', 'mode':'w'}, 90 ) 91 92 _relations = ( 93 ("rrdTemplate", ToOne(ToManyCont,"Products.ZenModel.RRDTemplate", "graphs")), 94 ) 95 96 colors = ( 97 '#00cc00', '#0000ff', '#00ffff', '#ff0000', 98 '#ffff00', '#cc0000', '#0000cc', '#0080c0', 99 '#8080c0', '#ff0080', '#800080', '#0000a0', 100 '#408080', '#808000', '#000000', '#00ff00', 101 '#fb31fb', '#0080ff', '#ff8000', '#800000', 102 ) 103 104 # Screen action bindings (and tab definitions) 105 factory_type_information = ( 106 { 107 'immediate_view' : 'editRRDGraph', 108 'actions' : 109 ( 110 { 'id' : 'edit' 111 , 'name' : 'Graph' 112 , 'action' : 'editRRDGraph' 113 , 'permissions' : ( Permissions.view, ) 114 }, 115 ) 116 }, 117 ) 118
119 - def breadCrumbs(self, terminator='dmd'):
120 """Return the breadcrumb links for this object add ActionRules list. 121 [('url','id'), ...] 122 """ 123 from RRDTemplate import crumbspath 124 crumbs = super(RRDGraph, self).breadCrumbs(terminator) 125 return crumbspath(self.rrdTemplate(), crumbs, -2)
126 127
128 - def getGraphCmds(self, context, rrdfile, template):
129 """build the graph opts for a single rrdfile""" 130 cmds = self.graphsetup() 131 if self.custom: 132 cmds = self.buildCustomDS(cmds, rrdfile, template) 133 res = talesEval("string:"+self.custom, context) 134 cmds.extend(res.split("\n")) 135 if self.hasSummary: 136 cmds = self.addSummary(cmds) 137 else: 138 cmds = self.buildDS(cmds, rrdfile, template, self.summary) 139 cmds = self.thresholds(cmds, context, template) 140 return cmds
141 142
143 - def graphsetup(self):
144 """Setup global graph parameters. 145 """ 146 gopts = ['-F', '-E'] 147 if self.height: 148 gopts.append('--height=%d' % self.height) 149 if self.width: 150 gopts.append('--width=%d' % self.width) 151 if self.log: 152 gopts.append('--logarithmic') 153 if self.maxy > -1: 154 gopts.append('--upper-limit=%d' % self.maxy) 155 gopts.append('--rigid') 156 if self.miny > -1: 157 gopts.append('--lower-limit=%d' % self.miny) 158 gopts.append('--rigid') 159 if self.units: 160 gopts.append('--vertical-label=%s' % self.units) 161 if self.units == 'percentage': 162 if not self.maxy > -1: 163 gopts.append('--upper-limit=100') 164 if not self.miny > -1: 165 gopts.append('--lower-limit=0') 166 if self.base: 167 gopts.append('--base=1024') 168 return gopts
169 170
171 - def buildCustomDS(self, gopts, rrdfile, template):
172 """Build a list of DEF statements for the dsnames in this graph. 173 Their variable name will be dsname. These can then be used in a 174 custom statement. 175 """ 176 for dsname in self.dsnames: 177 dp = template.getRRDDataPoint(dsname) 178 if dp is None: continue 179 myfile = os.path.join(rrdfile, dp.name()) + ".rrd" 180 gopts.append('DEF:%s=%s:ds0:AVERAGE' % (dp.name(), myfile)) 181 return gopts
182 183
184 - def buildDS(self, gopts, rrdfile, template, summary,multiid=-1):
185 """Add commands to draw data sources in this graph. 186 """ 187 for dsindex, dsname in enumerate(self.dsnames): 188 dp = template.getRRDDataPoint(dsname) 189 dp.setIndex(dsindex) 190 defcolor = self.colors[dsindex] 191 deftype = self.gettype(dsindex) 192 gopts += dp.graphOpts(rrdfile, defcolor, deftype, summary, multiid) 193 return gopts
194
195 - def thresholds(self, gopts, context, template):
196 """Add the hrule commands for any thresholds in this graph. 197 """ 198 self._v_threshidx = len(self.colors) 199 threshs = [] 200 for thresh in template.thresholds(): 201 if not thresh.canGraph(self): continue 202 for dsname in thresh.dsnames: 203 if dsname in self.dsnames: 204 threshs.append(thresh) 205 break 206 if threshs: gopts.append("COMMENT:Data Thresholds\j") 207 for i, thresh in enumerate(threshs): 208 t = thresh.createThresholdInstance(context) 209 color = self.getthreshcolor() 210 gopts = t.getGraphElements(template, gopts, 'thresh%d' % i, color) 211 import logging 212 log = logging.getLogger("debug") 213 log.error('%r' % gopts) 214 return gopts
215 216 217 gelement = re.compile("^LINE|^AREA|^STACK", re.I).search
218 - def addSummary(self, gopts):
219 """Add summary labels for all graphed elements in gopts. 220 """ 221 vars = [o.split(":",2)[1].split("#")[0] for o in gopts if self.gelement(o)] 222 223 pad = max([len(v) for v in vars] + [0]) 224 for var in vars: 225 gopts = self.dataSourceSum(gopts, var, pad=pad) 226 return gopts
227 228
229 - def dataSourceSum(self, gopts, src, pad=0, format="%0.2lf%s", ongraph=1):
230 """Add the standard summary opts to a graph for variable src. 231 VDEF:src_last=src,LAST 232 GPRINT:src_last:cur\:%0.2lf%s 233 VDEF:src_avg=src,AVERAGE 234 GPRINT:src_avg:avg\:%0.2lf%s 235 VDEF:src_max=src,MAXIMUM 236 GPRINT:src_max:max\:%0.2lf%s\j 237 """ 238 funcs = (("cur\:", "LAST"), ("avg\:", "AVERAGE"), ("max\:", "MAXIMUM")) 239 for tag, func in funcs: 240 label = "%s%s" % (tag, format) 241 #if pad: label = label.ljust(pad) 242 vdef = "%s_%s" % (src,func.lower()) 243 gopts.append("VDEF:%s=%s,%s" % (vdef,src,func)) 244 opt = ongraph and "GPRINT" or "PRINT" 245 gopts.append("%s:%s:%s" % (opt, vdef, label)) 246 gopts[-1] += "\j" 247 return gopts
248 249
250 - def getthreshcolor(self):
251 """get a threshold color by working backwards down the color list""" 252 self._v_threshidx -= 1 253 a= self.colors[self._v_threshidx] 254 return a
255 256
257 - def gettype(self, idx):
258 """Return the default graph type for a data source 259 first is area rest are lines 260 """ 261 if idx == 0: 262 return "AREA" 263 elif self.stacked: 264 return "STACK" 265 else: 266 return "LINE%d" % self.linewidth
267 268 InitializeClass(RRDGraph) 269