Package Products :: Package ZenHub :: Package services :: Module RRDImpl
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenHub.services.RRDImpl

  1  ############################################################################## 
  2  #  
  3  # Copyright (C) Zenoss, Inc. 2007, all rights reserved. 
  4  #  
  5  # This content is made available according to terms specified in 
  6  # License.zenoss under the directory where your Zenoss product is installed. 
  7  #  
  8  ############################################################################## 
  9   
 10   
 11  __doc__ = """RRDImpl 
 12   
 13  Implementation of basic RRD services for zenhub 
 14  """ 
 15   
 16  import os.path 
 17  import logging 
 18  import time 
 19   
 20  from Products.ZenRRD.RRDUtil import RRDUtil 
 21  from Products.ZenEvents.ZenEventClasses import Critical, Status_Perf 
 22   
 23   
 24  log = logging.getLogger("zenhub") 
 25   
 26   
 27   
28 -class RRDImpl(object):
29 """ 30 RRDUtil wrapper class for zenhub 31 """ 32 33 # list of RRD types that only accept long or integer values (no floats!) 34 LONG_RRD_TYPES = ['COUNTER', 'DERIVE'] 35
36 - def __init__(self, dmd):
37 """ 38 Initializer 39 40 @param dmd: Device Management Database (DMD) reference 41 @type dmd: dmd object 42 """ 43 # RRD is a dictionary of RRDUtil instances, keyed by (device,datapoint) tuples 44 self.rrd = {} 45 # counts is a dictionary of integers tracking how many times 46 # each threshold has been exceeded sequentially. 47 self.counts = {} 48 49 self.dmd = dmd 50 self.zem = dmd.ZenEventManager
51 52
53 - def writeRRD(self, devId, compType, compId, dpName, value):
54 """ 55 Write the given data to its RRD file. 56 Also check any thresholds and send events if value is out of bounds. 57 Note that if the write does not succeed, a None value is returned. 58 59 @param devId: device name (as known by DMD) 60 @type devId: string 61 @param compType: component type (found in objects meta_type field) 62 @type compType: string 63 @param compId: name of the component 64 @type compId: string 65 @param dpName: name of the data point 66 @type dpName: string 67 @param value: performance metric to store 68 @type value: number 69 @return: valid value (ie long or float) or None 70 @rtype: number or None 71 """ 72 log.debug('Writing %s %s' % (dpName, value)) 73 dev = self.getDeviceOrComponent(devId, compType, compId) 74 dp = dev.getRRDDataPoint(dpName) 75 if not dp: 76 log.warn('Did not find datapoint %s on device %s', dpName, devId) 77 return None 78 rrdKey = (dev.getPrimaryPath(), dp.getPrimaryPath()) 79 rrdCreateCmd = None 80 if rrdKey in self.rrd: 81 rrd = self.rrd[rrdKey] 82 else: 83 rrdCreateCmd = dp.createCmd or self.getDefaultRRDCreateCommand(dev) 84 rrd = RRDUtil(rrdCreateCmd, dp.datasource.cycletime) 85 self.rrd[rrdKey] = rrd 86 87 # convert value to a long if our data point uses a long type 88 if dp.rrdtype in RRDImpl.LONG_RRD_TYPES: 89 try: 90 value = long(value) 91 except ValueError: 92 log.warn("Value '%s' received for data point '%s' that " \ 93 "could not be converted to a long" % \ 94 (value, dp.rrdtype)) 95 96 # see if there are any thresholds defined for this datapoint, so we can 97 # choose a more optimal RRD storage method if there aren't any 98 dp_has_threshold = self.hasThreshold(dp) 99 if dp_has_threshold: 100 rrd_write_fn = rrd.save 101 else: 102 rrd_write_fn = rrd.put 103 104 path = os.path.join(dev.rrdPath(), dp.name()) 105 try: 106 value = rrd_write_fn( path, 107 value, 108 dp.rrdtype, 109 rrdCreateCmd, 110 dp.datasource.cycletime, 111 dp.rrdmin, 112 dp.rrdmax) 113 114 except Exception, ex: 115 summary= "Unable to save data in zenhub for RRD %s" % \ 116 path 117 log.critical( summary ) 118 119 message= "Data was value= %s, type=%s, min=%s, max=%s" % \ 120 ( value, dp.rrdtype, dp.rrdmin, dp.rrdmax, ) 121 log.critical( message ) 122 log.exception( ex ) 123 124 import traceback 125 trace_info= traceback.format_exc() 126 127 evid= self.zem.sendEvent(dict( 128 dedupid="%s|%s" % (devId, 'RRD write failure'), 129 severity=Critical, 130 device=devId, 131 eventClass=Status_Perf, 132 component="RRD", 133 compType=compType, 134 compId=compId, 135 datapoint=dpName, 136 message=message, 137 traceback=trace_info, 138 summary=summary)) 139 140 # Skip thresholds 141 return 142 143 if dp_has_threshold: 144 self.checkThresholds(dev, dp, value) 145 return value
146 147
148 - def getDefaultRRDCreateCommand(self, device):
149 """ 150 Get the overridable create command for new RRD files. 151 152 @param device: device object from in DMD 153 @type device: device object 154 @return: RRD create command 155 @rtype: string 156 """ 157 return device.perfServer().getDefaultRRDCreateCommand()
158 159
160 - def getDeviceOrComponent(self, devId, compId, compType):
161 """ 162 If a compId is given then try to return that component. If unable 163 to find it or if compId is not specified then try to return the 164 given device. If unable to find then return None. 165 166 @param devId: device name (as known by DMD) 167 @type devId: string 168 @param compId: name of the component 169 @type compId: string 170 @param compType: component type (found in objects meta_type field) 171 @type compType: string 172 @return: device or component object 173 @rtype: object 174 """ 175 retobj = None 176 device = self.dmd.Devices.findDevice(devId) 177 if device: 178 if compId: 179 retobj = next((comp for comp in device.getDeviceComponents() 180 if comp.meta_type == compType and comp.id == compId), 181 None) 182 183 else: 184 retobj = device 185 return retobj
186
187 - def hasThreshold(self, dp):
188 dp_name = dp.name() 189 return any(thresh.enabled and dp_name in thresh.dsnames 190 for thresh in dp.datasource.rrdTemplate.thresholds())
191
192 - def checkThresholds(self, dev, dp, value):
193 """ 194 Check the given value against any thresholds. Count the number of 195 times a dp has exceeded a given threshold in self.counts. Send events 196 as appropriate. 197 198 @param dev: device or component object 199 @type dev: object 200 @param dp: datapoint 201 @type dp: RRD datapoint object 202 @param value: performance metric to compare 203 @type value: number 204 """ 205 if value is None: 206 return 207 208 # Loop through the enabled thresholds on the template containing 209 # this datapoint. 210 dp_name = dp.name() 211 for t in [t for t in dp.datasource.rrdTemplate.thresholds() 212 if t.enabled and dp_name in t.dsnames]: 213 log.debug('Checking %s value of %s against threshold %s: %s:%s' % 214 (dp_name, value, t.id, t.getMinval(dev), t.getMaxval(dev))) 215 inst = t.createThresholdInstance(dev) 216 # storing the count external to the instances is a little 217 # broken, but I don't want to cache the instances 218 countKey = inst.countKey('dp_ds') 219 inst.count[countKey] = self.counts.get(countKey, None) 220 for evt in inst.checkRaw(dp.name(), time.time(), value): 221 self.zem.sendEvent(evt) 222 self.counts[countKey] = inst.countKey('dp_ds')
223