pycollectd

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

commit 9a62dcab4c218c9458cada58016f9bdd3f0b7e7f
Author: Sean Lynch <seanl@literati.org>
Date:   Mon, 11 Jan 2010 23:12:24 +0000

Initial commit

Diffstat:
Apycollectd/__init__.py | 4++++
Apycollectd/collectd.py | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apycollectd/collectdb.py | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 203 insertions(+), 0 deletions(-)

diff --git a/pycollectd/__init__.py b/pycollectd/__init__.py @@ -0,0 +1,4 @@ +from collectd import UnixSock, Identifier + +__all__ = ['UnixSock', 'Identifier'] + diff --git a/pycollectd/collectd.py b/pycollectd/collectd.py @@ -0,0 +1,127 @@ +#!/usr/bin/python + +import sys, socket, re +from datetime import datetime + + +class Identifier(object): + _name_re = re.compile('(?P<hostname>[^/]+)/' + '(?P<plugin>[^-/]+)(?:-(?P<plugin_instance>[^/]+))?/' + '(?P<type>[^-/]+)(?:-(?P<type_instance>[^/]+))?$') + def __init__(self, hostname, plugin, plugin_instance, type, type_instance): + self.hostname = hostname + self.plugin = plugin + self.plugin_instance = plugin_instance + self.type = type + self.type_instance = type_instance + + def __repr__(self): + return '<{0}({1})>'.format(self.__class__.__name__, self.format_name()) + + def __str__(self): + return self.format_name() + + @classmethod + def fromstring(cls, s): + m = cls._name_re.match(s) + return cls(**m.groupdict()) if m else None + + def todict(self): + return self.__dict__ + + def totuple(self): + return self.hostname, self.plugin, self.plugin_instance, self.type, self.type_instance + + def format_instance(self, a, b): + return '{0}-{1}'.format(a, b) if b is not None else a + + def format_plugin(self): + return self.format_instance(self.plugin, self.plugin_instance) + + def format_type(self): + return self.format_instance(self.type, self.type_instance) + + def format_name(self): + return '/'.join((self.hostname, self.format_plugin(), self.format_type())) + + def fetch(self): + lines = self.collectd.getval(self.format_name()) + return dict((line.split('=') for line in lines)) + + +class UnixSock(object): + def __init__(self, socket_name): + self._sock = socket.socket(socket.AF_UNIX) + self._sock.connect(socket_name) + + def _send(self, data): + self._sock.sendall(data) + + def _recvline(self): + data = '' + while data[-1] != '\n': + data = data + self._sock.recv(4096) + + return data + + def _recvlines(self): + lines = [''] + while len(lines) == 1 or lines[-1] != '' or lines[0] and len(lines) <= int(lines[0].split()[0]) + 1: + data = self._sock.recv(4096) + if not data: + continue + new_lines = data.split('\n') + lines[-1] += new_lines[0] + lines.extend(new_lines[1:]) + + return lines[1:-1] + + def _format_options(self, options): + """ + Format a dictionary of options as a list of key=value pairs + starting with a space. + + """ + + return ''.join((' ' + '='.join(k, str(v)) for k, v in options.iteritems())) + + @staticmethod + def _parse_values(lines): + kviter = (line.split('=') for line in lines) + return dict(((k, float(v)) for k, v in kviter)) + + @staticmethod + def _parse_line(line): + timestamp, name = line.split(' ', 1) + return datetime.fromtimestamp(float(timestamp)), Identifier.fromstring(name) + + def listval(self): + self._send('LISTVAL\n') + lines = self._recvlines() + return (self._parse_line(line) for line in lines) + + def getval(self, name): + self._send('GETVAL {0}\n'.format(name)) + return self._parse_values(self._recvlines()) + + def putval(self, name, values, **kwargs): + self._send('PUTVAL {0}{1} {2}\n'.format(name, ':'.join((str(v) for v in values)), + self._format_options(kwargs))) + return int(self._recvline().split()[0]) + + def putnotif(self, time, name, severity, message): + if not isinstance(name, Identifier): + name = Identifier.fromstring(name) + + self._send('PUTVAL time={0} severity={1}{2} message={3}'.format(time, severity, self._format_options(name.todict()))) + + +def main(): + c = UnixSock('/var/run/collectd-unixsock') + for timestamp, name in c.listval(): + print name, c.getval(name) + + +if __name__ == '__main__': + main() + diff --git a/pycollectd/collectdb.py b/pycollectd/collectdb.py @@ -0,0 +1,72 @@ +#!/usr/bin/python +# Python built-in stuff +import sqlite3, time + + +class CollectDB(object): + def __init__(self, filename=':memory:', names=[]): + self._db = sqlite3.connect(filename) + c = self._db.cursor() + c.execute("""create table data (id integer primary key, + timestamp integer not null, + hostname text not null, + plugin text not null, + plugin_instance text, + type text not null, + type_instance text) + """) + c.execute('create index hostname on data (hostname)') + c.execute('create index plugin on data (plugin)') + c.execute('create index hostname_plugin on data (hostname, plugin)') + c.execute('create index plugin_type on data (plugin, type)') + c.execute('create unique index full on data (hostname, plugin, plugin_instance, type, type_instance)') + + + def clear(self): + c = self._db.cursor() + c.execute('delete from data') + self._db.commit() + + def add_values(self, values): + c = self._db.cursor() + c.executemany("""insert or replace into data (timestamp, + hostname, + plugin, + plugin_instance, + type, + type_instance) + values (?, ?, ?, ?, ?, ?) + """, ((time.mktime(timestamp.timetuple()),) + name.totuple() for timestamp, name in values)) + self._db.commit() + + def get_hostnames(self): + c = self._db.cursor() + c.execute("select distinct hostname from data") + return [ r[0] for r in c ] + + def get_plugins(self, hostname=None): + c = self._db.cursor() + if hostname: + where = ' where hostname=?' + data = (hostname,) + else: + where = '' + data = () + + c.execute("select distinct plugin from data{0}".format(where), data) + return [ r[0] for r in c ] + + +def main(): + import collectd + db = CollectDB() + c = collectd.Collectd('/var/run/collectd-unixsock') + db.add_values(c.listval()) + for hostname in db.get_hostnames(): + print hostname, + print db.get_plugins(hostname) + + +if __name__ == '__main__': + main() +