1
2
3
4
5
6
7
8
9
10
11 import time
12
13 import logging
14 log = logging.getLogger("zen.RRDView")
15
16 from Acquisition import aq_chain
17
18 from Products.ZenRRD.RRDUtil import convertToRRDTime
19 from Products.ZenUtils import Map
20 from Products.ZenWidgets import messaging
21
22 from Products.ZenModel.ConfigurationError import ConfigurationError
23
24 CACHE_TIME = 60.
25
26 _cache = Map.Locked(Map.Timed({}, CACHE_TIME))
27
34
35
37
38
40 """
41 Mixin to provide hooks to RRD management functions
42 """
43
63
65 """
66 Cache RRD values for up to CACHE_TIME seconds.
67 """
68
69
70
71
72
73
74 filename = self.getRRDFileName(dsname)
75 try:
76 value = _cache[filename]
77 except KeyError:
78 try:
79
80 value = self.getRRDValue(dsname)
81 except Exception, ex:
82
83
84 value = None
85 log.error('Unable to get RRD value for %s: %s', dsname, ex)
86 _cache[filename] = value
87
88 return value if value is not None else default
89
90
91 - def getRRDValue(self, dsname, start=None, end=None, function="LAST",
92 format="%.2lf", extraRpn="", cf="AVERAGE"):
93 """Return a single rrd value from its file using function.
94 """
95 dsnames = (dsname,)
96 results = self.getRRDValues(
97 dsnames, start, end, function, format, extraRpn, cf=cf)
98 if results and dsname in results:
99 return results[dsname]
100
105
108
112
117
118
124
125
126 - def getRRDValues(self, dsnames, start=None, end=None, function="LAST",
127 format="%.2lf", extraRpn="", cf="AVERAGE"):
128 """
129 Return a dict of key value pairs where dsnames are the keys.
130 """
131 try:
132 if not start:
133 start = time.time() - self.defaultDateRange
134 gopts = []
135
136 names = list(dsnames)
137 for dsname in dsnames:
138 dp = next((d for d in self._getRRDDataPointsGen()
139 if dsname in d.name()), None)
140 if dp is None:
141 names.remove(dsname)
142 continue
143 filename = self.getRRDFileName(dp.name())
144 rpn = str(dp.rpn)
145 if rpn:
146 rpn = "," + rpn
147 if extraRpn:
148 rpn = rpn + "," + extraRpn
149
150 gopts.append("DEF:%s_r=%s:ds0:%s" % (dsname,filename,cf))
151 gopts.append("CDEF:%s_c=%s_r%s" % (dsname,dsname,rpn))
152 gopts.append("VDEF:%s=%s_c,%s" % (dsname,dsname,function))
153 gopts.append("PRINT:%s:%s" % (dsname, format))
154 gopts.append("--start=%s" % convertToRRDTime(start))
155 if end:
156 gopts.append("--end=%s" % convertToRRDTime(end))
157 if not names:
158 return {}
159 perfServer = self.device().getPerformanceServer()
160 vals = []
161 if perfServer:
162 vals = perfServer.performanceCustomSummary(gopts)
163 if vals is None:
164 vals = [None] * len(dsnames)
165 def cvt(val):
166 if val is None or val.lower() == "nan":
167 return None
168 return float(val)
169 return dict(zip(names, map(cvt, vals)))
170 except Exception, ex:
171 log.exception("Unable to collect RRD Values for %s" % self.getPrimaryId())
172
173
174
175 - def getRRDSum(self, points, start=None, end=None, function="LAST"):
176 "Return a some of listed datapoints."
177
178 try:
179 if not start:
180 start = time.time() - self.defaultDateRange
181 if not end:
182 end = time.time()
183 gopts = []
184 for name in points:
185 dp = next((dp_ for dp_ in self._getRRDDataPointsGen()
186 if name in dp_.name()), None)
187 if dp is None:
188 raise RRDViewError("Unable to find data point %s" % name)
189
190 filename = self.getRRDFileName(dp.name())
191 rpn = str(dp.rpn)
192 if rpn:
193 rpn = "," + rpn
194 gopts.append("DEF:%s_r=%s:ds0:AVERAGE" % (name, filename))
195 gopts.append("CDEF:%s=%s_r%s" % (name, name, rpn))
196 gopts.append("CDEF:sum=%s%s" % (','.join(points),
197 ',+'*(len(points)-1)))
198 gopts.append("VDEF:agg=sum,%s" % function)
199 gopts.append("PRINT:agg:%.2lf")
200 gopts.append("--start=%d" % start)
201 gopts.append("--end=%d" % end)
202 perfServer = self.device().getPerformanceServer()
203 if perfServer:
204 vals = perfServer.performanceCustomSummary(gopts)
205 if vals is None:
206 return None
207 return float(vals[0])
208 except Exception, ex:
209 log.exception(ex)
210
211
225
226
234
236 """Return the target type name of this component. By default meta_type.
237 Override to create custom type selection.
238 """
239 return self.meta_type
240
241
243 """Look up an rrd file based on its data point name"""
244 nm = next((p.name() for p in self._getRRDDataPointsGen()
245 if p.name().endswith(dsname)), dsname)
246 return '%s/%s.rrd' % (self.rrdPath(), nm)
247
248
251
254
256 """Should this component be monitored for performance using snmp.
257 """
258 return False
259
265
267 try:
268 return self.getRRDTemplates()[0]
269 except IndexError:
270 return None
271
273 "Return the template of the given name."
274 try:
275 return self._getOb(name)
276 except AttributeError:
277 pass
278 for obj in aq_chain(self):
279 try:
280 return obj.rrdTemplates._getOb(name)
281 except AttributeError:
282 pass
283 return None
284
285
287 """Return a dictionary where keys are dsnames and values are thresholds.
288 """
289 result = {}
290 for thresh in templ.thresholds():
291 if not thresh.enabled: continue
292 for dsname in thresh.dsnames:
293 threshdef = result.setdefault(dsname, [])
294 threshdef.append(thresh.getConfig(self))
295 return result
296
299
300
304
305 - def getRRDContextData(self, context):
307
309 from Products.ZenEvents.Exceptions import pythonThresholdException
310 result = []
311 for template in self.getRRDTemplates():
312
313
314 names = set(dp.name() for ds in template.getRRDDataSources(dsType)
315 for dp in ds.datapoints())
316 for threshold in template.thresholds():
317 if not threshold.enabled: continue
318 for ds in threshold.dsnames:
319 if ds in names:
320 try:
321 thresh = threshold.createThresholdInstance(self)
322 result.append(thresh)
323 except pythonThresholdException, ex:
324 log.warn(ex)
325 zem = self.primaryAq().getEventManager()
326 import socket
327 device = socket.gethostname()
328 path = template.absolute_url_path()
329 msg = \
330 "The threshold %s in template %s has caused an exception." % (threshold.id, path)
331 evt = dict(summary=str(ex), severity=3,
332 component='zenhub', message=msg,
333 dedupid='zenhub|' + str(ex),
334 template=path,
335 threshold=threshold.id,
336 device=device, eventClass="/Status/Update",)
337 zem.sendEvent(evt)
338 break
339 return result
340
341
356
357
370
371
374