1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__="""RRDGraph
15
16 RRDGraph defines the global options for an rrdtool graph.
17 """
18
19
20
21
22
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
46
47
48 addRRDGraph = DTMLFile('dtml/addRRDGraph',globals())
49
50
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
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
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
141
142
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
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
215
216
217 gelement = re.compile("^LINE|^AREA|^STACK", re.I).search
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
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
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
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