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

Source Code for Module ZenModel.MinMaxThreshold

  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  import rrdtool 
 14  from AccessControl import Permissions 
 15   
 16  from Globals import InitializeClass 
 17  from ThresholdClass import ThresholdClass 
 18  from ThresholdInstance import ThresholdInstance, ThresholdContext 
 19  from Products.ZenModel.PerformanceConf import performancePath 
 20  from Products.ZenEvents import Event 
 21  from Products.ZenEvents.ZenEventClasses import Perf_Snmp, Clear 
 22  from Products.ZenUtils.ZenTales import talesEval 
 23   
 24  import logging 
 25  log = logging.getLogger('zen.MinMaxCheck') 
 26   
 27  from sets import Set 
 28   
29 -def rpneval(value, rpn):
30 """totally bogus rpn valuation only works with one level stack""" 31 if value is None: return value 32 operators = ('+','-','*','/') 33 rpn = rpn.split(',') 34 operator = '' 35 for i in range(len(rpn)): 36 symbol = rpn.pop() 37 symbol = symbol.strip() 38 if symbol in operators: 39 operator = symbol 40 else: 41 expr = str(value) + operator + symbol 42 value = eval(expr) 43 return value
44 45
46 -class MinMaxThreshold(ThresholdClass):
47 48 minval = "" 49 maxval = "" 50 eventClass = Perf_Snmp 51 severity = 3 52 escalateCount = 0 53 54 _properties = ThresholdClass._properties + ( 55 {'id':'minval', 'type':'string', 'mode':'w'}, 56 {'id':'maxval', 'type':'string', 'mode':'w'}, 57 {'id':'eventClass', 'type':'string', 'mode':'w'}, 58 {'id':'severity', 'type':'int', 'mode':'w'}, 59 {'id':'escalateCount', 'type':'int', 'mode':'w'}, 60 ) 61 62 factory_type_information = ( 63 { 64 'immediate_view' : 'editRRDThreshold', 65 'actions' : 66 ( 67 { 'id' : 'edit' 68 , 'name' : 'Min/Max Threshold' 69 , 'action' : 'editRRDThreshold' 70 , 'permissions' : ( Permissions.view, ) 71 }, 72 ) 73 }, 74 ) 75
76 - def createThresholdInstance(self, context):
77 """Return the config used by the collector to process simple min/max 78 thresholds. (id, minval, maxval, severity, escalateCount) 79 """ 80 mmt = MinMaxThresholdInstance(self.id, 81 ThresholdContext(context), 82 self.dsnames, 83 minval=self.getMinval(context), 84 maxval=self.getMaxval(context), 85 eventClass=self.eventClass, 86 severity=self.severity, 87 escalateCount=self.escalateCount) 88 return mmt
89
90 - def getMinval(self, context):
91 """Build the min value for this threshold. 92 """ 93 minval = None 94 if self.minval: 95 minval = talesEval("python:"+self.minval, context) 96 return minval
97 98
99 - def getMaxval(self, context):
100 """Build the max value for this threshold. 101 """ 102 maxval = None 103 if self.maxval: 104 maxval = talesEval("python:"+self.maxval, context) 105 return maxval
106 107 InitializeClass(MinMaxThreshold) 108 MinMaxThresholdClass = MinMaxThreshold 109
110 -class MinMaxThresholdInstance(ThresholdInstance):
111
112 - def __init__(self, id, context, dpNames, 113 minval, maxval, eventClass, severity, escalateCount):
114 self._context = context 115 self.id = id 116 self.minimum = minval 117 self.maximum = maxval 118 self.eventClass = eventClass 119 self.severity = severity 120 self.escalateCount = escalateCount 121 self.dataPointNames = dpNames 122 self._rrdInfoCache = {}
123
124 - def name(self):
125 "return the name of this threshold (from the ThresholdClass)" 126 return self.id
127
128 - def context(self):
129 "Return an identifying context (device, or device and component)" 130 return self._context
131
132 - def dataPoints(self):
133 "Returns the names of the datapoints used to compute the threshold" 134 return self.dataPointNames
135
136 - def rrdInfoCache(self, dp):
137 if dp in self._rrdInfoCache: 138 return self._rrdInfoCache[dp] 139 data = rrdtool.info(self.context().path(dp)) 140 value = data['step'], data['ds']['ds0']['type'] 141 self._rrdInfoCache[dp] = value 142 return value
143
144 - def check(self, dataPoints):
145 """The given datapoints have been updated, so re-evaluate. 146 returns events or an empty sequence""" 147 result = [] 148 for dp in self.dataPointNames: 149 cycleTime, rrdType = self.rrdInfoCache(dp) 150 startStop, names, values = \ 151 rrdtool.fetch(self.context().path(dp), 'AVERAGE', 152 '-s', 'now-%d' % (cycleTime*2), 153 '-e', 'now') 154 value = values[0][0] 155 result.extend(self.checkRange(dp, value)) 156 return result
157
158 - def checkRaw(self, dataPoint, timeOf, value):
159 """A new datapoint has been collected, use the given _raw_ 160 value to re-evalue the threshold.""" 161 result = [] 162 if value is None: return result 163 try: 164 cycleTime, rrdType = self.rrdInfoCache(dataPoint) 165 except Exception: 166 log.error('Unable to read RRD file for %s' % dataPoint) 167 return result 168 if rrdType != 'GAUGE': 169 startStop, names, values = \ 170 rrdtool.fetch(self.context().path(dataPoint), 'AVERAGE', 171 '-s', 'now-%d' % (cycleTime*2), 172 '-e', 'now') 173 value = values[0][0] 174 result.extend(self.checkRange(dataPoint, value)) 175 return result
176
177 - def checkRange(self, dp, value):
178 'Check the value for min/max thresholds' 179 log.debug("Checking %s %s against min %s and max %s", 180 dp, value, self.minimum, self.maximum) 181 if value is None: 182 return [] 183 thresh = None 184 if self.maximum is not None and value > self.maximum: 185 thresh = self.maximum 186 how = 'exceeded' 187 if self.minimum is not None and value < self.minimum: 188 thresh = self.minimum 189 how = 'not met' 190 label = self.context().componentName or '' 191 if thresh is not None: 192 self.count = (self.count or 0) + 1 193 severity = self.severity 194 if self.escalateCount and self.count >= self.escalateCount: 195 severity = max(severity + 1, 5) 196 summary = '%s %s threshold of %s %s: current value %.2f' % ( 197 self.context().deviceName, label, self.name(), how, float(value)) 198 return [dict(device=self.context().deviceName, 199 summary=summary, 200 eventClass=self.eventClass, 201 component=self.context().componentName, 202 severity=severity)] 203 else: 204 if self.count != 0 and self.count is not None: 205 summary = '%s %s threshold restored current value: %.2f' % ( 206 self.context().deviceName, label, value) 207 self.count = 0 208 return [dict(device=self.context().deviceName, 209 summary=summary, 210 eventClass=self.eventClass, 211 component=self.context().componentName, 212 severity=Event.Clear)] 213 return []
214 215
216 - def getGraphElements(self, template, gopts, namespace, color, relatedGps):
217 """Produce a visual indication on the graph of where the 218 threshold applies.""" 219 if not color.startswith('#'): 220 color = '#%s' % color 221 ns = namespace 222 n = self.minimum 223 x = self.maximum 224 gp = relatedGps[self.dataPointNames[0]] 225 if getattr(gp, 'rpn', ''): 226 n = rpneval(n, gp.rpn) 227 x = rpneval(x, gp.rpn) 228 result = [] 229 if n: 230 result += [ 231 "HRULE:%s%s:%s\\j" % (n, color, self.getMinLabel(n)), 232 ] 233 if x: 234 result += [ 235 "HRULE:%s%s:%s\\j" % (x, color, self.getMaxLabel(x)) 236 ] 237 return gopts + result
238 239
240 - def getMinLabel(self, minval):
241 """build a label for a min threshold""" 242 return "%s < %s" % (self.getNames(), self.setPower(minval))
243 244
245 - def getMaxLabel(self, maxval):
246 """build a label for a max threshold""" 247 return "%s > %s" % (self.getNames(),self.setPower(maxval))
248
249 - def getNames(self):
250 names = list(Set([x.split('_', 1)[1] for x in self.dataPointNames])) 251 names.sort() 252 return ', '.join(names)
253 254
255 - def setPower(self, number):
256 powers = ("k", "M", "G") 257 if number < 1000: return number 258 for power in powers: 259 number = number / 1000 260 if number < 1000: 261 return "%0.2f%s" % (number, power) 262 return "%.2f%s" % (number, powers[-1])
263 264 from twisted.spread import pb 265 pb.setUnjellyableForClass(MinMaxThresholdInstance, MinMaxThresholdInstance) 266