X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=contrib%2Fcollectd_unixsock.py;h=5cd4ab8ee6de5d7ba3ebadd83418765dea9d39e5;hp=f8355f80028923e26f11cb3e4e5739193ead0aa0;hb=2bc8f11d9c7182e24fb62a6efefa3e0b74ac0afb;hpb=ef868b32154b2711850f70832ab0cd895f431376 diff --git a/contrib/collectd_unixsock.py b/contrib/collectd_unixsock.py index f8355f80..5cd4ab8e 100644 --- a/contrib/collectd_unixsock.py +++ b/contrib/collectd_unixsock.py @@ -28,52 +28,177 @@ # 3. This notice may not be removed or altered from any source distribution. import socket -import string +import sys -class Collect(object): +class Collectd(): - def __init__(self, path='/var/run/collectd-unixsock'): - self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self._path = path - self._sock.connect(self._path) + def __init__(self, path='/var/run/collectd-unixsock', noisy=False): + self.noisy = noisy + self.path = path + self._sock = self._connect() - def list(self): - numvalues = self._cmd('LISTVAL') + def flush(self, timeout=None, plugins=[], identifiers=[]): + """Send a FLUSH command. + + Full documentation: + http://collectd.org/wiki/index.php/Plain_text_protocol#FLUSH + + """ + # have to pass at least one plugin or identifier + if not plugins and not identifiers: + return None + args = [] + if timeout: + args.append("timeout=%s" % timeout) + if plugins: + plugin_args = map(lambda x: "plugin=%s" % x, plugins) + args.extend(plugin_args) + if identifiers: + identifier_args = map(lambda x: "identifier=%s" % x, identifiers) + args.extend(identifier_args) + return self._cmd('FLUSH %s' % ' '.join(args)) + + def getthreshold(self, identifier): + """Send a GETTHRESHOLD command. + + Full documentation: + http://collectd.org/wiki/index.php/Plain_text_protocol#GETTHRESHOLD + + """ + numvalues = self._cmd('GETTHRESHOLD "%s"' % identifier) lines = [] - if numvalues: - lines = self._readlines(numvalues) + if not numvalues or numvalues < 0: + raise KeyError("Identifier '%s' not found" % identifier) + lines = self._readlines(numvalues) return lines - def get(self, val, flush=True): - numvalues = self._cmd('GETVAL "' + val + '"') + def getval(self, identifier, flush_after=True): + """Send a GETVAL command. + + Also flushes the identifier if flush_after is True. + + Full documentation: + http://collectd.org/wiki/index.php/Plain_text_protocol#GETVAL + + """ + numvalues = self._cmd('GETVAL "%s"' % identifier) + lines = [] + if not numvalues or numvalues < 0: + raise KeyError("Identifier '%s' not found" % identifier) + lines = self._readlines(numvalues) + if flush_after: + self.flush(identifiers=[identifier]) + return lines + + def listval(self): + """Send a LISTVAL command. + + Full documentation: + http://collectd.org/wiki/index.php/Plain_text_protocol#LISTVAL + + """ + numvalues = self._cmd('LISTVAL') lines = [] if numvalues: lines = self._readlines(numvalues) - if flush: - self._cmd('FLUSH identifier="' + val + '"') return lines + def putnotif(self, message, options={}): + """Send a PUTNOTIF command. + + Options must be passed as a Python dictionary. Example: + options={'severity': 'failure', 'host': 'example.com'} + + Full documentation: + http://collectd.org/wiki/index.php/Plain_text_protocol#PUTNOTIF + + """ + args = [] + if options: + options_args = map(lambda x: "%s=%s" % (x, options[x]), options) + args.extend(options_args) + args.append('message="%s"' % message) + return self._cmd('PUTNOTIF %s' % ' '.join(args)) + + def putval(self, identifier, values, options={}): + """Send a PUTVAL command. + + Options must be passed as a Python dictionary. Example: + options={'interval': 10} + + Full documentation: + http://collectd.org/wiki/index.php/Plain_text_protocol#PUTVAL + + """ + args = [] + args.append('"%s"' % identifier) + if options: + options_args = map(lambda x: "%s=%s" % (x, options[x]), options) + args.extend(options_args) + values = map(str, values) + args.append(':'.join(values)) + return self._cmd('PUTVAL %s' % ' '.join(args)) + def _cmd(self, c): + try: + return self._cmdattempt(c) + except socket.error, (errno, errstr): + sys.stderr.write("[error] Sending to socket failed: [%d] %s\n" + % (errno, errstr)) + self._sock = self._connect() + return self._cmdattempt(c) + + def _cmdattempt(self, c): + if self.noisy: + print "[send] %s" % c + if not self._sock: + sys.stderr.write("[error] Socket unavailable. Can not send.") + return False self._sock.send(c + "\n") - stat = string.split(self._readline()) - status = int(stat[0]) - if status: - return status + status_message = self._readline() + if self.noisy: + print "[receive] %s" % status_message + if not status_message: + return None + code, message = status_message.split(' ', 1) + if int(code): + return int(code) return False + def _connect(self): + try: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.path) + if self.noisy: + print "[socket] connected to %s" % self.path + return sock + except socket.error, (errno, errstr): + sys.stderr.write("[error] Connecting to socket failed: [%d] %s" + % (errno, errstr)) + return None + def _readline(self): """Read single line from socket""" - data = '' - buf = [] - recv = self._sock.recv - while data != "\n": - data = recv(1) - if not data: - break - if data != "\n": - buf.append(data) - return ''.join(buf) + if not self._sock: + sys.stderr.write("[error] Socket unavailable. Can not read.") + return None + try: + data = '' + buf = [] + recv = self._sock.recv + while data != "\n": + data = recv(1) + if not data: + break + if data != "\n": + buf.append(data) + return ''.join(buf) + except socket.error, (errno, errstr): + sys.stderr.write("[error] Reading from socket failed: [%d] %s" + % (errno, errstr)) + self._sock = self._connect() + return None def _readlines(self, sizehint=0): """Read multiple lines from socket""" @@ -90,16 +215,29 @@ class Collect(object): return list def __del__(self): - self._sock.close() + if not self._sock: + return + try: + self._sock.close() + except socket.error, (errno, errstr): + sys.stderr.write("[error] Closing socket failed: [%d] %s" + % (errno, errstr)) if __name__ == '__main__': """Collect values from socket and dump to STDOUT""" - c = Collect('/var/run/collectd-unixsock') - list = c.list() - + c = Collectd('/var/run/collectd-unixsock', noisy=True) + list = c.listval() for val in list: - stamp, key = string.split(val) - glines = c.get(key) - print stamp + ' ' + key + ' ' + ', '.join(glines) + stamp, identifier = val.split() + print "\n%s" % identifier + print "\tUpdate time: %s" % stamp + + values = c.getval(identifier) + print "\tValue list: %s" % ', '.join(values) + + # don't fetch thresholds by default because collectd will crash + # if there is no treshold for the given identifier + #thresholds = c.getthreshold(identifier) + #print "\tThresholds: %s" % ', '.join(thresholds)