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