]> git.ipfire.org Git - collecty.git/blobdiff - src/collecty/plugins/base.py
Add code to localise graph templates
[collecty.git] / src / collecty / plugins / base.py
index 476c134785a7d1dc95e3a4de0f4db646babedecc..c9e815c52d48ebd831af1a5a05f188adc0473df9 100644 (file)
@@ -29,6 +29,7 @@ import threading
 import time
 import unicodedata
 
+from .. import locales
 from ..constants import *
 from ..i18n import _
 
@@ -64,6 +65,41 @@ class Timer(object):
                return self.elapsed > self.timeout
 
 
+class Environment(object):
+       """
+               Sets the correct environment for rrdtool to create
+               localised graphs and graphs in the correct timezone.
+       """
+       def __init__(self, timezone, locale):
+               # Build the new environment
+               self.new_environment = {
+                       "TZ" : timezone or DEFAULT_TIMEZONE,
+               }
+
+               for k in ("LANG", "LC_ALL"):
+                       self.new_environment[k] = locale or DEFAULT_LOCALE
+
+       def __enter__(self):
+               # Save the current environment
+               self.old_environment = {}
+               for k in self.new_environment:
+                       self.old_environment[k] = os.environ.get(k, None)
+
+               # Apply the new one
+               os.environ.update(self.new_environment)
+
+       def __exit__(self, type, value, traceback):
+               # Roll back to the previous environment
+               for k, v in self.old_environment.items():
+                       if v is None:
+                               try:
+                                       del os.environ[k]
+                               except KeyError:
+                                       pass
+                       else:
+                               os.environ[k] = v
+
+
 class PluginRegistration(type):
        plugins = {}
 
@@ -147,8 +183,7 @@ class Plugin(object, metaclass=PluginRegistration):
                        try:
                                result = o.collect()
 
-                               if isinstance(result, tuple) or isinstance(result, list):
-                                       result = ":".join(("%s" % e for e in result))
+                               result = self._format_result(result)
                        except:
                                self.log.warning(_("Unhandled exception in %s.collect()") % o, exc_info=True)
                                continue
@@ -170,6 +205,25 @@ class Plugin(object, metaclass=PluginRegistration):
                if delay >= 60:
                        self.log.warning(_("A worker thread was stalled for %.4fs") % delay)
 
+       @staticmethod
+       def _format_result(result):
+               if not isinstance(result, tuple) and not isinstance(result, list):
+                       return result
+
+               # Replace all Nones by NaN
+               s = []
+
+               for e in result:
+                       if e is None:
+                               e = "NaN"
+
+                       # Format as string
+                       e = "%s" % e
+
+                       s.append(e)
+
+               return ":".join(s)
+
        def get_object(self, id):
                for object in self.objects:
                        if not object.id == id:
@@ -177,15 +231,17 @@ class Plugin(object, metaclass=PluginRegistration):
 
                        return object
 
-       def get_template(self, template_name, object_id):
+       def get_template(self, template_name, object_id, locale=None, timezone=None):
                for template in self.templates:
                        if not template.name == template_name:
                                continue
 
-                       return template(self, object_id)
+                       return template(self, object_id, locale=locale, timezone=timezone)
 
-       def generate_graph(self, template_name, object_id="default", **kwargs):
-               template = self.get_template(template_name, object_id=object_id)
+       def generate_graph(self, template_name, object_id="default",
+                       timezone=None, locale=None, **kwargs):
+               template = self.get_template(template_name, object_id=object_id,
+                       timezone=timezone, locale=locale)
                if not template:
                        raise RuntimeError("Could not find template %s" % template_name)
 
@@ -374,6 +430,7 @@ class GraphTemplate(object):
                None   : "-3h",
                "hour" : "-1h",
                "day"  : "-25h",
+               "month": "-30d",
                "week" : "-360h",
                "year" : "-365d",
        }
@@ -382,9 +439,13 @@ class GraphTemplate(object):
        height = GRAPH_DEFAULT_HEIGHT
        width  = GRAPH_DEFAULT_WIDTH
 
-       def __init__(self, plugin, object_id):
+       def __init__(self, plugin, object_id, locale=None, timezone=None):
                self.plugin = plugin
 
+               # Save localisation parameters
+               self.locale = locales.get(locale)
+               self.timezone = timezone
+
                # Get all required RRD objects
                self.object_id = object_id
 
@@ -434,13 +495,13 @@ class GraphTemplate(object):
                        if self.upper_limit is not None:
                                args += ["--upper-limit", self.upper_limit]
 
-               # Add interval
-               args.append("--start")
-
                try:
-                       args.append(self.intervals[interval])
+                       interval = self.intervals[interval]
                except KeyError:
-                       args.append(str(interval))
+                       interval = "end-%s" % interval
+
+               # Add interval
+               args += ["--start", interval]
 
                return args
 
@@ -483,17 +544,10 @@ class GraphTemplate(object):
 
                        self.log.debug("  %s" % args[-1])
 
-               return self.write_graph(*args)
-
-       def write_graph(self, *args):
-               # Convert all arguments to string
+               # Convert arguments to string
                args = [str(e) for e in args]
 
-               with tempfile.NamedTemporaryFile() as f:
-                       rrdtool.graph(f.name, *args)
-
-                       # Get back to the beginning of the file
-                       f.seek(0)
+               with Environment(self.timezone, self.locale.lang):
+                       graph = rrdtool.graphv("-", *args)
 
-                       # Return all the content
-                       return f.read()
+               return graph.get("image")