pycollectd

Python interface to collectd-unixsock
git clone https://code.literati.org/pycollectd.git
Log | Files | Refs

collectd.py (4868B)


      1 #!/usr/bin/python
      2 
      3 import sys, socket, re, time
      4 from datetime import datetime
      5 
      6 
      7 class CollectdError(Exception):
      8     pass
      9 
     10 
     11 class Identifier(object):
     12     _name_re = re.compile('(?P<hostname>[^/]+)/'
     13                           '(?P<plugin>[^-/]+)(?:-(?P<plugin_instance>[^/]+))?/'
     14                           '(?P<type>[^-/]+)(?:-(?P<type_instance>[^/]+))?$')
     15     def __init__(self, hostname, plugin, plugin_instance, type, type_instance):
     16         self.hostname = hostname
     17         self.plugin = plugin
     18         self.plugin_instance = plugin_instance
     19         self.type = type
     20         self.type_instance = type_instance
     21 
     22     def __repr__(self):
     23         return '<{0}({1})>'.format(self.__class__.__name__, self.format_name())
     24 
     25     def __str__(self):
     26 	return self.format_name()
     27 
     28     @classmethod
     29     def fromstring(cls, s):
     30         m = cls._name_re.match(s)
     31         return cls(**m.groupdict()) if m else None
     32 
     33     def todict(self):
     34         return self.__dict__
     35 
     36     def totuple(self):
     37         return self.hostname, self.plugin, self.plugin_instance, self.type, self.type_instance
     38 
     39     def format_instance(self, a, b):
     40         return '{0}-{1}'.format(a, b) if b is not None else a
     41 
     42     def format_plugin(self):
     43         return self.format_instance(self.plugin, self.plugin_instance)
     44 
     45     def format_type(self):
     46         return self.format_instance(self.type, self.type_instance)
     47 
     48     def format_name(self):
     49         return '/'.join((self.hostname, self.format_plugin(), self.format_type()))
     50 
     51     def fetch(self):
     52         lines = self.collectd.getval(self.format_name())
     53         return dict((line.split('=') for line in lines))
     54 
     55 
     56 class CollectdBase(object):
     57     def _send(self, data):
     58         raise NotImplementedError
     59 
     60     def _recvline(self):
     61         raise NotImplementedError
     62 
     63     def _recvlines(self):
     64         raise NotImplementedError
     65 
     66     def _check_result(self):
     67         if self.readonly:
     68             return
     69 
     70         result = self._recvline()
     71         status = result.split()[0]
     72         if status != '0':
     73             raise CollectdError, result
     74 
     75     def _format_options(self, options):
     76         """
     77         Format a dictionary of options as a list of key=value pairs
     78         starting with a space.
     79 
     80         """
     81 
     82         return ''.join((' ' + '{0}={1}'.format(k, v) for k, v in options.iteritems()))
     83 
     84     @staticmethod
     85     def _parse_values(lines):
     86         kviter = (line.split('=') for line in lines)
     87         return dict(((k, float(v)) for k, v in kviter))
     88 
     89     @staticmethod
     90     def _parse_line(line):
     91         timestamp, name = line.split(' ', 1)
     92         return datetime.fromtimestamp(float(timestamp)), Identifier.fromstring(name)
     93 
     94     def listval(self):
     95         self._send('LISTVAL\n')
     96         lines = self._recvlines()
     97         return (self._parse_line(line) for line in lines)
     98 
     99     def getval(self, identifier):
    100         self._send('GETVAL {0}\n'.format(identifier))
    101         return self._parse_values(self._recvlines())
    102 
    103     def putval(self, identifier, timestamp, values, **kwargs):
    104         if isinstance(timestamp, datetime):
    105             timestamp = time.mktime(timestamp.timetuple())
    106 
    107         cmd = 'PUTVAL {0}{1} {2}:{3}\n'.format(identifier, self._format_options(kwargs), int(timestamp), ':'.join((str(v) for v in values)))
    108         self._send(cmd)
    109         self._check_result()
    110 
    111     def putnotif(self, timestamp, identifier, severity, message):
    112         if isinstance(timestamp, datetime):
    113             timestamp = time.mktime(timestamp.timetuple())
    114 
    115         self._send('PUTVAL time={0} severity={1}{2} message={3}\n'.format(timestamp, severity, self._format_options(identifier.todict())))
    116         self._check_result()
    117 
    118 
    119 class UnixSock(CollectdBase):
    120     readonly = False
    121     def __init__(self, socket_name='/var/run/collectd-unixsock'):
    122         self._sock = socket.socket(socket.AF_UNIX)
    123         self._sock.connect(socket_name)
    124 
    125     def _send(self, data):
    126         self._sock.sendall(data)
    127 
    128     def _recvline(self):
    129         data = ''
    130         while not data or data[-1] != '\n':
    131             data = data + self._sock.recv(4096)
    132 
    133         return data
    134 
    135     def _recvlines(self):
    136         lines = ['']
    137         while len(lines) == 1 or lines[-1] != '' or lines[0] and len(lines) <= int(lines[0].split()[0]) + 1:
    138             data = self._sock.recv(4096)
    139             if not data:
    140                 continue
    141             new_lines = data.split('\n')
    142             lines[-1] += new_lines[0]
    143             lines.extend(new_lines[1:])
    144 
    145         return lines[1:-1]
    146 
    147 
    148 class Exec(CollectdBase):
    149     readonly = True
    150     def __init__(self, fp=sys.stdout):
    151         self._fp = fp
    152 
    153     def _send(self, data):
    154         self._fp.write(data)
    155 
    156 
    157 def main():
    158     c = UnixSock()
    159     e = Exec()
    160     for timestamp, name in c.listval():
    161         values = c.getval(name)
    162         #print name, timestamp, values
    163         e.putval(name, timestamp, values.values(), interval=10)
    164 
    165 
    166 
    167 if __name__ == '__main__':
    168     main()
    169