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

# Source Code for Module Products.ZenHub.services.RRDImpl

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