Code

Replace dashes with underscores in python modules
authorGarret Heaton <powdahound@gmail.com>
Sun, 18 Oct 2009 21:06:22 +0000 (14:06 -0700)
committerFlorian Forster <octo@noris.net>
Wed, 21 Oct 2009 09:29:43 +0000 (11:29 +0200)
It's not possible to import python modules with dashes in the name.
See http://bit.ly/2t7fcy for more information.

contrib/collectd-network.py [deleted file]
contrib/collectd-unixsock.py [deleted file]
contrib/collectd_network.py [new file with mode: 0644]
contrib/collectd_unixsock.py [new file with mode: 0644]

diff --git a/contrib/collectd-network.py b/contrib/collectd-network.py
deleted file mode 100644 (file)
index 445b183..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: utf-8 -*-
-# vim: fileencoding=utf-8
-#
-# Copyright © 2009 Adrian Perez <aperez@igalia.com>
-#
-# Distributed under terms of the GPLv2 license.
-
-"""
-Collectd network protocol implementation.
-"""
-
-import socket
-import struct
-
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-
-from datetime import datetime
-from copy import deepcopy
-
-
-DEFAULT_PORT = 25826
-"""Default port"""
-
-DEFAULT_IPv4_GROUP = "239.192.74.66"
-"""Default IPv4 multicast group"""
-
-DEFAULT_IPv6_GROUP = "ff18::efc0:4a42"
-"""Default IPv6 multicast group"""
-
-
-
-# Message kinds
-TYPE_HOST            = 0x0000
-TYPE_TIME            = 0x0001
-TYPE_PLUGIN          = 0x0002
-TYPE_PLUGIN_INSTANCE = 0x0003
-TYPE_TYPE            = 0x0004
-TYPE_TYPE_INSTANCE   = 0x0005
-TYPE_VALUES          = 0x0006
-TYPE_INTERVAL        = 0x0007
-
-# For notifications
-TYPE_MESSAGE         = 0x0100
-TYPE_SEVERITY        = 0x0101
-
-# DS kinds
-DS_TYPE_COUNTER      = 0
-DS_TYPE_GAUGE        = 1
-
-
-header = struct.Struct("!2H")
-number = struct.Struct("!Q")
-short  = struct.Struct("!H")
-double = struct.Struct("<d")
-
-
-def decode_network_values(ptype, plen, buf):
-    """Decodes a list of DS values in collectd network format
-    """
-    nvalues = short.unpack_from(buf, header.size)[0]
-    off = header.size + short.size + nvalues
-    valskip = double.size
-
-    # Check whether our expected packet size is the reported one
-    assert ((valskip + 1) * nvalues + short.size + header.size) == plen
-    assert double.size == number.size
-
-    result = []
-    for dstype in map(ord, buf[header.size+short.size:off]):
-        if dstype == DS_TYPE_COUNTER:
-            result.append((dstype, number.unpack_from(buf, off)[0]))
-            off += valskip
-        elif dstype == DS_TYPE_GAUGE:
-            result.append((dstype, double.unpack_from(buf, off)[0]))
-            off += valskip
-        else:
-            raise ValueError("DS type %i unsupported" % dstype)
-
-    return result
-
-
-def decode_network_number(ptype, plen, buf):
-    """Decodes a number (64-bit unsigned) in collectd network format.
-    """
-    return number.unpack_from(buf, header.size)[0]
-
-
-def decode_network_string(msgtype, plen, buf):
-    """Decodes a floating point number (64-bit) in collectd network format.
-    """
-    return buf[header.size:plen-1]
-
-
-# Mapping of message types to decoding functions.
-_decoders = {
-    TYPE_VALUES         : decode_network_values,
-    TYPE_TIME           : decode_network_number,
-    TYPE_INTERVAL       : decode_network_number,
-    TYPE_HOST           : decode_network_string,
-    TYPE_PLUGIN         : decode_network_string,
-    TYPE_PLUGIN_INSTANCE: decode_network_string,
-    TYPE_TYPE           : decode_network_string,
-    TYPE_TYPE_INSTANCE  : decode_network_string,
-    TYPE_MESSAGE        : decode_network_string,
-    TYPE_SEVERITY       : decode_network_number,
-}
-
-
-def decode_network_packet(buf):
-    """Decodes a network packet in collectd format.
-    """
-    off = 0
-    blen = len(buf)
-    while off < blen:
-        ptype, plen = header.unpack_from(buf, off)
-
-        if plen > blen - off:
-            raise ValueError("Packet longer than amount of data in buffer")
-
-        if ptype not in _decoders:
-            raise ValueError("Message type %i not recognized" % ptype)
-
-        yield ptype, _decoders[ptype](ptype, plen, buf[off:])
-        off += plen
-
-
-
-
-
-class Data(object):
-    time = 0
-    host = None
-    plugin = None
-    plugininstance = None
-    type = None
-    typeinstance = None
-
-    def __init__(self, **kw):
-        [setattr(self, k, v) for k, v in kw.iteritems()]
-
-    @property
-    def datetime(self):
-        return datetime.fromtimestamp(self.time)
-
-    @property
-    def source(self):
-        buf = StringIO()
-        if self.host:
-            buf.write(self.host)
-        if self.plugin:
-            buf.write("/")
-            buf.write(self.plugin)
-        if self.plugininstance:
-            buf.write("/")
-            buf.write(self.plugininstance)
-        if self.type:
-            buf.write("/")
-            buf.write(self.type)
-        if self.typeinstance:
-            buf.write("/")
-            buf.write(self.typeinstance)
-        return buf.getvalue()
-
-    def __str__(self):
-        return "[%i] %s" % (self.time, self.source)
-
-
-
-class Notification(Data):
-    FAILURE  = 1
-    WARNING  = 2
-    OKAY     = 4
-
-    SEVERITY = {
-        FAILURE: "FAILURE",
-        WARNING: "WARNING",
-        OKAY   : "OKAY",
-    }
-
-    __severity = 0
-    message  = ""
-
-    def __set_severity(self, value):
-        if value in (self.FAILURE, self.WARNING, self.OKAY):
-            self.__severity = value
-
-    severity = property(lambda self: self.__severity, __set_severity)
-
-    @property
-    def severitystring(self):
-        return self.SEVERITY.get(self.severity, "UNKNOWN")
-
-    def __str__(self):
-        return "%s [%s] %s" % (
-                super(Notification, self).__str__(),
-                self.severitystring,
-                self.message)
-
-
-
-class Values(Data, list):
-    def __str__(self):
-        return "%s %s" % (Data.__str__(self), list.__str__(self))
-
-
-
-def interpret_opcodes(iterable):
-    vl = Values()
-    nt = Notification()
-
-    for kind, data in iterable:
-        if kind == TYPE_TIME:
-            vl.time = nt.time = data
-        elif kind == TYPE_INTERVAL:
-            vl.interval = data
-        elif kind == TYPE_HOST:
-            vl.host = nt.host = data
-        elif kind == TYPE_PLUGIN:
-            vl.plugin = nt.plugin = data
-        elif kind == TYPE_PLUGIN_INSTANCE:
-            vl.plugininstance = nt.plugininstance = data
-        elif kind == TYPE_TYPE:
-            vl.type = nt.type = data
-        elif kind == TYPE_TYPE_INSTANCE:
-            vl.typeinstance = nt.typeinstance = data
-        elif kind == TYPE_SEVERITY:
-            nt.severity = data
-        elif kind == TYPE_MESSAGE:
-            nt.message = data
-            yield deepcopy(nt)
-        elif kind == TYPE_VALUES:
-            vl[:] = data
-            yield deepcopy(vl)
-
-
-
-class Reader(object):
-    """Network reader for collectd data.
-
-    Listens on the network in a given address, which can be a multicast
-    group address, and handles reading data when it arrives.
-    """
-    addr = None
-    host = None
-    port = DEFAULT_PORT
-
-    BUFFER_SIZE = 1024
-
-
-    def __init__(self, host=None, port=DEFAULT_PORT, multicast=False):
-        if host is None:
-            multicast = True
-            host = DEFAULT_IPv4_GROUP
-
-        self.host, self.port = host, port
-        self.ipv6 = ":" in self.host
-
-        family, socktype, proto, canonname, sockaddr = socket.getaddrinfo(
-                None if multicast else self.host, self.port,
-                socket.AF_INET6 if self.ipv6 else socket.AF_UNSPEC,
-                socket.SOCK_DGRAM, 0, socket.AI_PASSIVE)[0]
-
-        self._sock = socket.socket(family, socktype, proto)
-        self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        self._sock.bind(sockaddr)
-
-        if multicast:
-            if hasattr(socket, "SO_REUSEPORT"):
-                self._sock.setsockopt(
-                        socket.SOL_SOCKET,
-                        socket.SO_REUSEPORT, 1)
-
-            val = None
-            if family == socket.AF_INET:
-                assert "." in self.host
-                val = struct.pack("4sl",
-                        socket.inet_aton(self.host), socket.INADDR_ANY)
-            elif family == socket.AF_INET6:
-                raise NotImplementedError("IPv6 support not ready yet")
-            else:
-                raise ValueError("Unsupported network address family")
-
-            self._sock.setsockopt(
-                    socket.IPPROTO_IPV6 if self.ipv6 else socket.IPPROTO_IP,
-                    socket.IP_ADD_MEMBERSHIP, val)
-            self._sock.setsockopt(
-                    socket.IPPROTO_IPV6 if self.ipv6 else socket.IPPROTO_IP,
-                    socket.IP_MULTICAST_LOOP, 0)
-
-
-    def receive(self):
-        """Receives a single raw collect network packet.
-        """
-        return self._sock.recv(self.BUFFER_SIZE)
-
-
-    def decode(self, buf=None):
-        """Decodes a given buffer or the next received packet.
-        """
-        if buf is None:
-            buf = self.receive()
-        return decode_network_packet(buf)
-
-
-    def interpret(self, iterable=None):
-        """Interprets a sequence
-        """
-        if iterable is None:
-            iterable = self.decode()
-        if isinstance(iterable, basestring):
-            iterable = self.decode(iterable)
-        return interpret_opcodes(iterable)
-
-
diff --git a/contrib/collectd-unixsock.py b/contrib/collectd-unixsock.py
deleted file mode 100644 (file)
index 2d7430d..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-#-*- coding: ISO-8859-1 -*-
-# collect.py: the python collectd-unixsock module.
-#
-# Requires collectd to be configured with the unixsock plugin, like so:
-#
-# LoadPlugin unixsock
-# <Plugin unixsock>
-#   SocketFile "/var/run/collectd-unixsock"
-#   SocketPerms "0775"
-# </Plugin>
-#
-# Copyright (C) 2008 Clay Loveless <clay@killersoft.com>
-#
-# This software is provided 'as-is', without any express or implied
-# warranty.  In no event will the author be held liable for any damages
-# arising from the use of this software.
-#
-# Permission is granted to anyone to use this software for any purpose,
-# including commercial applications, and to alter it and redistribute it
-# freely, subject to the following restrictions:
-#
-# 1. The origin of this software must not be misrepresented; you must not
-#    claim that you wrote the original software. If you use this software
-#    in a product, an acknowledgment in the product documentation would be
-#    appreciated but is not required.
-# 2. Altered source versions must be plainly marked as such, and must not be
-#    misrepresented as being the original software.
-# 3. This notice may not be removed or altered from any source distribution.
-
-import socket, string
-
-class Collect(object):
-
-    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 list(self):
-        numvalues = self._cmd('LISTVAL')
-        lines = []
-        if numvalues:
-            lines = self._readlines(numvalues)
-        return lines
-        
-    def get(self, val, flush=True):
-        numvalues = self._cmd('GETVAL "' + val + '"')
-        lines = []
-        if numvalues:
-            lines = self._readlines(numvalues)
-        if flush:
-            self._cmd('FLUSH identifier="' + val + '"')
-        return lines
-            
-    def _cmd(self, c):
-        self._sock.send(c + "\n")
-        stat = string.split(self._readline())
-        status = int(stat[0])
-        if status:
-            return status
-        return False
-    
-    '''
-    _readline and _readlines methods borrowed from the _fileobject class 
-    in sockets.py, tweaked a little bit for use in the collectd context.
-    '''
-    def _readline(self):
-        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)
-        
-    def _readlines(self, sizehint=0):
-        total = 0
-        list = []
-        while True:
-            line = self._readline()
-            if not line:
-                break
-            list.append(line)
-            total = len(list)
-            if sizehint and total >= sizehint:
-                break
-        return list
-    
-    def __del__(self):
-        self._sock.close()    
-
-
-
-if __name__ == '__main__':
-    
-    '''
-    Example usage:
-    Collect values from socket and dump to STDOUT.
-    '''
-    
-    c = Collect('/var/run/collectd-unixsock')
-    list = c.list()
-
-    for val in list:
-        stamp, key = string.split(val)
-        glines = c.get(key)
-        print stamp + ' ' + key + ' ' + ', '.join(glines)
-    
diff --git a/contrib/collectd_network.py b/contrib/collectd_network.py
new file mode 100644 (file)
index 0000000..445b183
--- /dev/null
@@ -0,0 +1,318 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim: fileencoding=utf-8
+#
+# Copyright © 2009 Adrian Perez <aperez@igalia.com>
+#
+# Distributed under terms of the GPLv2 license.
+
+"""
+Collectd network protocol implementation.
+"""
+
+import socket
+import struct
+
+try:
+    from cStringIO import StringIO
+except ImportError:
+    from StringIO import StringIO
+
+from datetime import datetime
+from copy import deepcopy
+
+
+DEFAULT_PORT = 25826
+"""Default port"""
+
+DEFAULT_IPv4_GROUP = "239.192.74.66"
+"""Default IPv4 multicast group"""
+
+DEFAULT_IPv6_GROUP = "ff18::efc0:4a42"
+"""Default IPv6 multicast group"""
+
+
+
+# Message kinds
+TYPE_HOST            = 0x0000
+TYPE_TIME            = 0x0001
+TYPE_PLUGIN          = 0x0002
+TYPE_PLUGIN_INSTANCE = 0x0003
+TYPE_TYPE            = 0x0004
+TYPE_TYPE_INSTANCE   = 0x0005
+TYPE_VALUES          = 0x0006
+TYPE_INTERVAL        = 0x0007
+
+# For notifications
+TYPE_MESSAGE         = 0x0100
+TYPE_SEVERITY        = 0x0101
+
+# DS kinds
+DS_TYPE_COUNTER      = 0
+DS_TYPE_GAUGE        = 1
+
+
+header = struct.Struct("!2H")
+number = struct.Struct("!Q")
+short  = struct.Struct("!H")
+double = struct.Struct("<d")
+
+
+def decode_network_values(ptype, plen, buf):
+    """Decodes a list of DS values in collectd network format
+    """
+    nvalues = short.unpack_from(buf, header.size)[0]
+    off = header.size + short.size + nvalues
+    valskip = double.size
+
+    # Check whether our expected packet size is the reported one
+    assert ((valskip + 1) * nvalues + short.size + header.size) == plen
+    assert double.size == number.size
+
+    result = []
+    for dstype in map(ord, buf[header.size+short.size:off]):
+        if dstype == DS_TYPE_COUNTER:
+            result.append((dstype, number.unpack_from(buf, off)[0]))
+            off += valskip
+        elif dstype == DS_TYPE_GAUGE:
+            result.append((dstype, double.unpack_from(buf, off)[0]))
+            off += valskip
+        else:
+            raise ValueError("DS type %i unsupported" % dstype)
+
+    return result
+
+
+def decode_network_number(ptype, plen, buf):
+    """Decodes a number (64-bit unsigned) in collectd network format.
+    """
+    return number.unpack_from(buf, header.size)[0]
+
+
+def decode_network_string(msgtype, plen, buf):
+    """Decodes a floating point number (64-bit) in collectd network format.
+    """
+    return buf[header.size:plen-1]
+
+
+# Mapping of message types to decoding functions.
+_decoders = {
+    TYPE_VALUES         : decode_network_values,
+    TYPE_TIME           : decode_network_number,
+    TYPE_INTERVAL       : decode_network_number,
+    TYPE_HOST           : decode_network_string,
+    TYPE_PLUGIN         : decode_network_string,
+    TYPE_PLUGIN_INSTANCE: decode_network_string,
+    TYPE_TYPE           : decode_network_string,
+    TYPE_TYPE_INSTANCE  : decode_network_string,
+    TYPE_MESSAGE        : decode_network_string,
+    TYPE_SEVERITY       : decode_network_number,
+}
+
+
+def decode_network_packet(buf):
+    """Decodes a network packet in collectd format.
+    """
+    off = 0
+    blen = len(buf)
+    while off < blen:
+        ptype, plen = header.unpack_from(buf, off)
+
+        if plen > blen - off:
+            raise ValueError("Packet longer than amount of data in buffer")
+
+        if ptype not in _decoders:
+            raise ValueError("Message type %i not recognized" % ptype)
+
+        yield ptype, _decoders[ptype](ptype, plen, buf[off:])
+        off += plen
+
+
+
+
+
+class Data(object):
+    time = 0
+    host = None
+    plugin = None
+    plugininstance = None
+    type = None
+    typeinstance = None
+
+    def __init__(self, **kw):
+        [setattr(self, k, v) for k, v in kw.iteritems()]
+
+    @property
+    def datetime(self):
+        return datetime.fromtimestamp(self.time)
+
+    @property
+    def source(self):
+        buf = StringIO()
+        if self.host:
+            buf.write(self.host)
+        if self.plugin:
+            buf.write("/")
+            buf.write(self.plugin)
+        if self.plugininstance:
+            buf.write("/")
+            buf.write(self.plugininstance)
+        if self.type:
+            buf.write("/")
+            buf.write(self.type)
+        if self.typeinstance:
+            buf.write("/")
+            buf.write(self.typeinstance)
+        return buf.getvalue()
+
+    def __str__(self):
+        return "[%i] %s" % (self.time, self.source)
+
+
+
+class Notification(Data):
+    FAILURE  = 1
+    WARNING  = 2
+    OKAY     = 4
+
+    SEVERITY = {
+        FAILURE: "FAILURE",
+        WARNING: "WARNING",
+        OKAY   : "OKAY",
+    }
+
+    __severity = 0
+    message  = ""
+
+    def __set_severity(self, value):
+        if value in (self.FAILURE, self.WARNING, self.OKAY):
+            self.__severity = value
+
+    severity = property(lambda self: self.__severity, __set_severity)
+
+    @property
+    def severitystring(self):
+        return self.SEVERITY.get(self.severity, "UNKNOWN")
+
+    def __str__(self):
+        return "%s [%s] %s" % (
+                super(Notification, self).__str__(),
+                self.severitystring,
+                self.message)
+
+
+
+class Values(Data, list):
+    def __str__(self):
+        return "%s %s" % (Data.__str__(self), list.__str__(self))
+
+
+
+def interpret_opcodes(iterable):
+    vl = Values()
+    nt = Notification()
+
+    for kind, data in iterable:
+        if kind == TYPE_TIME:
+            vl.time = nt.time = data
+        elif kind == TYPE_INTERVAL:
+            vl.interval = data
+        elif kind == TYPE_HOST:
+            vl.host = nt.host = data
+        elif kind == TYPE_PLUGIN:
+            vl.plugin = nt.plugin = data
+        elif kind == TYPE_PLUGIN_INSTANCE:
+            vl.plugininstance = nt.plugininstance = data
+        elif kind == TYPE_TYPE:
+            vl.type = nt.type = data
+        elif kind == TYPE_TYPE_INSTANCE:
+            vl.typeinstance = nt.typeinstance = data
+        elif kind == TYPE_SEVERITY:
+            nt.severity = data
+        elif kind == TYPE_MESSAGE:
+            nt.message = data
+            yield deepcopy(nt)
+        elif kind == TYPE_VALUES:
+            vl[:] = data
+            yield deepcopy(vl)
+
+
+
+class Reader(object):
+    """Network reader for collectd data.
+
+    Listens on the network in a given address, which can be a multicast
+    group address, and handles reading data when it arrives.
+    """
+    addr = None
+    host = None
+    port = DEFAULT_PORT
+
+    BUFFER_SIZE = 1024
+
+
+    def __init__(self, host=None, port=DEFAULT_PORT, multicast=False):
+        if host is None:
+            multicast = True
+            host = DEFAULT_IPv4_GROUP
+
+        self.host, self.port = host, port
+        self.ipv6 = ":" in self.host
+
+        family, socktype, proto, canonname, sockaddr = socket.getaddrinfo(
+                None if multicast else self.host, self.port,
+                socket.AF_INET6 if self.ipv6 else socket.AF_UNSPEC,
+                socket.SOCK_DGRAM, 0, socket.AI_PASSIVE)[0]
+
+        self._sock = socket.socket(family, socktype, proto)
+        self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        self._sock.bind(sockaddr)
+
+        if multicast:
+            if hasattr(socket, "SO_REUSEPORT"):
+                self._sock.setsockopt(
+                        socket.SOL_SOCKET,
+                        socket.SO_REUSEPORT, 1)
+
+            val = None
+            if family == socket.AF_INET:
+                assert "." in self.host
+                val = struct.pack("4sl",
+                        socket.inet_aton(self.host), socket.INADDR_ANY)
+            elif family == socket.AF_INET6:
+                raise NotImplementedError("IPv6 support not ready yet")
+            else:
+                raise ValueError("Unsupported network address family")
+
+            self._sock.setsockopt(
+                    socket.IPPROTO_IPV6 if self.ipv6 else socket.IPPROTO_IP,
+                    socket.IP_ADD_MEMBERSHIP, val)
+            self._sock.setsockopt(
+                    socket.IPPROTO_IPV6 if self.ipv6 else socket.IPPROTO_IP,
+                    socket.IP_MULTICAST_LOOP, 0)
+
+
+    def receive(self):
+        """Receives a single raw collect network packet.
+        """
+        return self._sock.recv(self.BUFFER_SIZE)
+
+
+    def decode(self, buf=None):
+        """Decodes a given buffer or the next received packet.
+        """
+        if buf is None:
+            buf = self.receive()
+        return decode_network_packet(buf)
+
+
+    def interpret(self, iterable=None):
+        """Interprets a sequence
+        """
+        if iterable is None:
+            iterable = self.decode()
+        if isinstance(iterable, basestring):
+            iterable = self.decode(iterable)
+        return interpret_opcodes(iterable)
+
+
diff --git a/contrib/collectd_unixsock.py b/contrib/collectd_unixsock.py
new file mode 100644 (file)
index 0000000..2d7430d
--- /dev/null
@@ -0,0 +1,111 @@
+#-*- coding: ISO-8859-1 -*-
+# collect.py: the python collectd-unixsock module.
+#
+# Requires collectd to be configured with the unixsock plugin, like so:
+#
+# LoadPlugin unixsock
+# <Plugin unixsock>
+#   SocketFile "/var/run/collectd-unixsock"
+#   SocketPerms "0775"
+# </Plugin>
+#
+# Copyright (C) 2008 Clay Loveless <clay@killersoft.com>
+#
+# This software is provided 'as-is', without any express or implied
+# warranty.  In no event will the author be held liable for any damages
+# arising from the use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+#    claim that you wrote the original software. If you use this software
+#    in a product, an acknowledgment in the product documentation would be
+#    appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+#    misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+
+import socket, string
+
+class Collect(object):
+
+    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 list(self):
+        numvalues = self._cmd('LISTVAL')
+        lines = []
+        if numvalues:
+            lines = self._readlines(numvalues)
+        return lines
+        
+    def get(self, val, flush=True):
+        numvalues = self._cmd('GETVAL "' + val + '"')
+        lines = []
+        if numvalues:
+            lines = self._readlines(numvalues)
+        if flush:
+            self._cmd('FLUSH identifier="' + val + '"')
+        return lines
+            
+    def _cmd(self, c):
+        self._sock.send(c + "\n")
+        stat = string.split(self._readline())
+        status = int(stat[0])
+        if status:
+            return status
+        return False
+    
+    '''
+    _readline and _readlines methods borrowed from the _fileobject class 
+    in sockets.py, tweaked a little bit for use in the collectd context.
+    '''
+    def _readline(self):
+        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)
+        
+    def _readlines(self, sizehint=0):
+        total = 0
+        list = []
+        while True:
+            line = self._readline()
+            if not line:
+                break
+            list.append(line)
+            total = len(list)
+            if sizehint and total >= sizehint:
+                break
+        return list
+    
+    def __del__(self):
+        self._sock.close()    
+
+
+
+if __name__ == '__main__':
+    
+    '''
+    Example usage:
+    Collect values from socket and dump to STDOUT.
+    '''
+    
+    c = Collect('/var/run/collectd-unixsock')
+    list = c.list()
+
+    for val in list:
+        stamp, key = string.split(val)
+        glines = c.get(key)
+        print stamp + ' ' + key + ' ' + ', '.join(glines)
+