]> git.ipfire.org Git - collecty.git/commitdiff
plugins: Restructure the plugin concept.
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 4 Aug 2012 12:36:08 +0000 (12:36 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 4 Aug 2012 12:36:08 +0000 (12:36 +0000)
collecty/plugins/base.py

index df2a7e53195cb70a01045076056a8725a6d5f074..183e4c5b8e00cefa0d65c7d817a5ba4fbcb0827c 100644 (file)
 #                                                                             #
 ###############################################################################
 
+import logging
+import os
+import rrdtool
+import time
+
 from threading import Thread
 
+from ..constants import *
 from ..i18n import _
 
 class Plugin(Thread):
+       # The name of this plugin.
+       name = None
+
+       # A description for this plugin.
+       description = None
+
+       # The schema of the RRD database.
+       rrd_schema = None
+
+       # The default interval of this plugin.
+       default_interval = 60
+
        def __init__(self, collecty, **kwargs):
                Thread.__init__(self)
                self.collecty = collecty
 
-               self.interval = int(kwargs.get("interval", 60))
+               # Check if this plugin was configured correctly.
+               assert self.name, "Name of the plugin is not set: %s" % self.name
+               assert self.description, "Description of the plugin is not set: %s" % self.description
+               assert self.rrd_schema
+
+               # Initialize the logger.
+               self.log = logging.getLogger("collecty.plugins.%s" % self.name)
+               self.log.propagate = 1
 
                # Keepalive options
                self.heartbeat = 2
-               self.killed = False
-
-               self.wakeup = self.interval / self.heartbeat
-
-               self.file = kwargs.get("file", None)
-               if not self.file.startswith("/"):
-                       self.file = os.path.join("/var/rrd", self.file) 
+               self.running = True
 
                self.data = []
 
+               # Create the database file.
                self.create()
+
+               # Run some custom initialization.
+               self.init()
+
+               self.log.info(_("Successfully initialized."))
        
        def __repr__(self):
-               return "<Plugin %s>" % self._type
+               return "<Plugin %s>" % self.name
        
        def __str__(self):
-               return "Plugin %s %s" % (self._type, self.file)
-       
-       def run(self):
-               self.collecty.debug("%s started..." % self)
-               
-               c = 0
-               while True:
-                       if self.killed:
-                               self.update()
-                               self.collecty.debug("%s stoppped..." % self)
-                               return
+               return "Plugin %s %s" % (self.name, self.file)
+
+       @property
+       def interval(self):
+               """
+                       Returns the interval in milliseconds, when the read method
+                       should be called again.
+               """
+               # XXX read this from the settings
+
+               # Otherwise return the default.
+               return self.default_interval
+
+       @property
+       def file(self):
+               """
+                       The absolute path to the RRD file of this plugin.
+               """
+               return os.path.join(DATABASE_DIR, "%s.rrd" % self.name)
 
-                       if c == 0:
-                               self.data.append(self.collect())
-                               self.collecty.debug("%s collectd: %s..." % (self, self.data[-1]))
+       def create(self):
+               """
+                       Creates an empty RRD file with the desired data structures.
+               """
+               # Skip if the file does already exist.
+               if os.path.exists(self.file):
+                       return
 
-                               self.update()
+               dirname = os.path.dirname(self.file)
+               if not os.path.exists(dirname):
+                       os.makedirs(dirname)
 
-                               c = self.wakeup
+               rrdtool.create(self.file, *self.rrd_schema)
 
-                       c = c - 1
-                       time.sleep(self.heartbeat)
+               self.log.debug(_("Created RRD file %s.") % self.file)
 
-       def shutdown(self):
-               self.killed = True
+       def info(self):
+               return rrdtool.info(self.file)
 
-       def time(self):
-               return int(time.time()) # Should return time as int in UTC
+       ### Basic methods
+
+       def init(self):
+               """
+                       Do some custom initialization stuff here.
+               """
+               pass
+
+       def read(self):
+               """
+                       Gathers the statistical data, this plugin collects.
+               """
+               raise NotImplementedError
+
+       def submit(self):
+               """
+                       Flushes the read data to disk.
+               """
+               # Do nothing in case there is no data to submit.
+               if not self.data:
+                       return
+
+               self.collecty.debug(_("Saving data from %s...") % self)
+               rrdtool.update(self.file, *self.data)
+               self.data = []
 
-       def create(self):
-               if not os.path.exists(self.file):
-                       rrdtool.create(self.file, *self._rrd)
+       def __read(self, *args, **kwargs):
+               """
+                       This method catches errors from the read() method and logs them.
+               """
+               try:
+                       return self.read(*args, **kwargs)
+
+               # Catch any exceptions, so collecty does not crash.
+               except Exception, e:
+                       self.log.critical(_("Unhandled exception in read()!"), exc_info=True)
+
+       def __submit(self, *args, **kwargs):
+               """
+                       This method catches errors from the submit() method and logs them.
+               """
+               try:
+                       return self.submit(*args, **kwargs)
 
-       def update(self):
-               if self.data:
-                       self.collecty.debug("%s saving data..." % self)
-                       rrdtool.update(self.file, *self.data)
-                       self.data = []
+               # Catch any exceptions, so collecty does not crash.
+               except Exception, e:
+                       self.log.critical(_("Unhandled exception in submit()!"), exc_info=True)
+
+       def run(self):
+               self.log.debug(_("Started."))
 
-       def collect(self):
-               raise Exception, "Not implemented"
+               counter = 0
+               while self.running:
+                       if counter == 0:
+                               self.log.debug(_("Collecting..."))
+                               self.__read()
+
+                               self.log.debug(_("Sleeping for %.4fs.") % self.interval)
+
+                               counter = self.interval / self.heartbeat
+
+                       time.sleep(self.heartbeat)
+                       counter -= 1
+
+               self.__submit()
+               self.log.debug(_("Stopped."))
+
+       def shutdown(self):
+               self.log.debug(_("Received shutdown signal."))
+               self.running = False
+
+       @property
+       def now(self):
+               """
+                       Returns the current timestamp in the UNIX timestamp format (UTC).
+               """
+               return int(time.time())
 
        def graph(self, file, interval=None):
                args = [ "--imgformat", "PNG",
@@ -115,7 +215,3 @@ class Plugin(Thread):
                                args.append(item)
 
                        rrdtool.graph(file, *args)
-
-       def info(self):
-               return rrdtool.info(self.file)
-