From: Michael Tremer Date: Sat, 25 Aug 2012 11:22:31 +0000 (+0000) Subject: Add CollectyClient to generate graph images. X-Git-Tag: 0.0.2~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=73db5226e4d042ee0810e639f62b3092507c29c9;p=collecty.git Add CollectyClient to generate graph images. --- diff --git a/collecty-client b/collecty-client new file mode 100755 index 0000000..9251bf8 --- /dev/null +++ b/collecty-client @@ -0,0 +1,28 @@ +#!/usr/bin/python +############################################################################### +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2012 IPFire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +import collecty + +client = collecty.CollectyClient() + +for type in ("cpu", "entropy", "memory", "loadavg"): + for interval in ("day", "week", "year"): + client.graph(type, "%s-%s.png" % (type, interval), interval) diff --git a/collecty/__init__.py b/collecty/__init__.py index afae3f5..187f6ab 100644 --- a/collecty/__init__.py +++ b/collecty/__init__.py @@ -19,15 +19,6 @@ # # ############################################################################### -import signal -import time - -import ConfigParser as configparser - -import plugins - -from i18n import _ - # Initialize logging. import logging log = logging.getLogger("collecty") @@ -40,126 +31,5 @@ log.handlers.append(handler) formatter = logging.Formatter("%(asctime)s | %(name)-20s - %(levelname)-6s | %(message)s") handler.setFormatter(formatter) -class ConfigError(Exception): - pass - -class Collecty(object): - # The default interval, when all data is written to disk. - SUBMIT_INTERVAL = 300 - - def __init__(self): - self.config = configparser.ConfigParser() - self.instances = [] - - # Indicates whether this process should be running or not. - self.running = True - self.timer = plugins.Timer(self.SUBMIT_INTERVAL, heartbeat=2) - - # Add all automatic plugins. - self.add_autocreate_plugins() - - log.info(_("Collecty successfully initialized.")) - - def add_autocreate_plugins(self): - for plugin in plugins.registered_plugins: - if not hasattr(plugin, "autocreate"): - continue - - ret = plugin.autocreate(self) - if not ret: - continue - - if not type(ret) == type([]): - ret = [ret,] - - log.debug(_("Plugin '%(name)s' registered %(number)s instance(s).") % \ - { "name" : plugin.name, "number" : len(ret) }) - - self.instances += ret - - def read_config(self, config): - self.config.read(config) - - for section in self.config.sections(): - try: - plugin = self.config.get(section, "plugin") - plugin = plugins.find(plugin) - except configparser.NoOptionError: - raise ConfigError, "Syntax error in configuration: plugin option is missing." - except: - raise Exception, "Plugin configuration error: Maybe plugin wasn't found? %s" % plugin - - kwargs = {} - for (key, value) in self.config.items(section): - if key == "plugin": - continue - - kwargs[key] = value - kwargs["file"] = section - - i = plugin(self, **kwargs) - self.instances.append(i) - - def run(self): - # Register signal handlers. - self.register_signal_handler() - - # Start all plugin instances. - for i in self.instances: - i.start() - - # Regularly submit all data to disk. - while self.running: - if self.timer.wait(): - self.submit_all() - - # Wait until all instances are finished. - while self.instances: - for instance in self.instances[:]: - if not instance.isAlive(): - log.debug(_("%s is not alive anymore. Removing.") % instance) - self.instances.remove(instance) - - # Wait a bit. - time.sleep(0.1) - - log.debug(_("No thread running. Exiting main thread.")) - - def submit_all(self): - """ - Submit all data right now. - """ - log.debug(_("Submitting all data in memory")) - for i in self.instances: - i._submit() - - # Schedule the next submit. - self.timer.reset() - - def shutdown(self): - log.debug(_("Received shutdown signal")) - - self.running = False - if self.timer: - self.timer.cancel() - - # Propagating shutdown to all threads. - for i in self.instances: - i.shutdown() - - def register_signal_handler(self): - for s in (signal.SIGTERM, signal.SIGINT, signal.SIGUSR1): - log.debug(_("Registering signal %d") % s) - - signal.signal(s, self.signal_handler) - - def signal_handler(self, sig, *args, **kwargs): - log.info(_("Caught signal %d") % sig) - - if sig in (signal.SIGTERM, signal.SIGINT): - # Shutdown this application. - self.shutdown() - - elif sig == signal.SIGUSR1: - # Submit all data. - self.submit_all() +from client import CollectyClient +from daemon import Collecty diff --git a/collecty/client.py b/collecty/client.py new file mode 100644 index 0000000..9ac640b --- /dev/null +++ b/collecty/client.py @@ -0,0 +1,46 @@ +#!/usr/bin/python +############################################################################### +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2012 IPFire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +import daemon + +import logging +log = logging.getLogger("collectly.client") + +class CollectyClient(object): + def __init__(self, **settings): + self.collecty = daemon.Collecty(**settings) + + @property + def instances(self): + return self.collecty.instances + + def get_instance_by_id(self, id): + for instance in self.instances: + if not instance.id == id: + continue + + return instance + + def graph(self, id, filename, interval=None, **kwargs): + instance = self.get_instance_by_id(id) + assert instance, "Could not find instance: %s" % id + + instance.graph(filename, interval=interval, **kwargs) diff --git a/collecty/constants.py b/collecty/constants.py index 969a083..20bdc35 100644 --- a/collecty/constants.py +++ b/collecty/constants.py @@ -19,4 +19,30 @@ # # ############################################################################### +from i18n import _ + DATABASE_DIR = "/var/lib/collecty" + +GRAPH_DEFAULT_ARGUMENTS = [ + # Always generate graphs in PNG format. + "--imgformat", "PNG", + + # Disable the border around the image. + "--border", "0", + + # Let's width and height define the size of + # the entire image. + "--full-size-mode", + + # Gives the curves a more organic look. + "--slope-mode", + + # Show nicer labels. + "--dynamic-labels", + + # Brand all generated graphs. + "--watermark", _("Created by collecty"), +] + +GRAPH_DEFAULT_WIDTH = 768 +GRAPH_DEFAULT_HEIGHT = 480 diff --git a/collecty/daemon.py b/collecty/daemon.py new file mode 100644 index 0000000..c736364 --- /dev/null +++ b/collecty/daemon.py @@ -0,0 +1,157 @@ +#!/usr/bin/python +############################################################################### +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2012 IPFire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +import signal + +import ConfigParser as configparser + +import plugins + +from constants import * +from i18n import _ + +import logging +log = logging.getLogger("collecty") + +class Collecty(object): + # The default interval, when all data is written to disk. + SUBMIT_INTERVAL = 300 + + def __init__(self, debug=False): + self.config = configparser.ConfigParser() + self.instances = [] + + # Indicates whether this process should be running or not. + self.running = True + self.timer = plugins.Timer(self.SUBMIT_INTERVAL, heartbeat=2) + + # Add all automatic plugins. + self.add_autocreate_plugins() + + log.info(_("Collecty successfully initialized.")) + + def add_autocreate_plugins(self): + for plugin in plugins.registered_plugins: + if not hasattr(plugin, "autocreate"): + continue + + ret = plugin.autocreate(self) + if not ret: + continue + + if not type(ret) == type([]): + ret = [ret,] + + log.debug(_("Plugin '%(name)s' registered %(number)s instance(s).") % \ + { "name" : plugin.name, "number" : len(ret) }) + + self.instances += ret + + def read_config(self, config): + self.config.read(config) + + for section in self.config.sections(): + try: + plugin = self.config.get(section, "plugin") + plugin = plugins.find(plugin) + except configparser.NoOptionError: + raise ConfigError, "Syntax error in configuration: plugin option is missing." + except: + raise Exception, "Plugin configuration error: Maybe plugin wasn't found? %s" % plugin + + kwargs = {} + for (key, value) in self.config.items(section): + if key == "plugin": + continue + + kwargs[key] = value + kwargs["file"] = section + + i = plugin(self, **kwargs) + self.instances.append(i) + + def run(self): + # Register signal handlers. + self.register_signal_handler() + + # Start all plugin instances. + for i in self.instances: + i.start() + + # Regularly submit all data to disk. + while self.running: + if self.timer.wait(): + self.submit_all() + + # Wait until all instances are finished. + while self.instances: + for instance in self.instances[:]: + if not instance.isAlive(): + log.debug(_("%s is not alive anymore. Removing.") % instance) + self.instances.remove(instance) + + # Wait a bit. + time.sleep(0.1) + + log.debug(_("No thread running. Exiting main thread.")) + + def submit_all(self): + """ + Submit all data right now. + """ + log.debug(_("Submitting all data in memory")) + for i in self.instances: + i._submit() + + # Schedule the next submit. + self.timer.reset() + + def shutdown(self): + log.debug(_("Received shutdown signal")) + + self.running = False + if self.timer: + self.timer.cancel() + + # Propagating shutdown to all threads. + for i in self.instances: + i.shutdown() + + def register_signal_handler(self): + for s in (signal.SIGTERM, signal.SIGINT, signal.SIGUSR1): + log.debug(_("Registering signal %d") % s) + + signal.signal(s, self.signal_handler) + + def signal_handler(self, sig, *args, **kwargs): + log.info(_("Caught signal %d") % sig) + + if sig in (signal.SIGTERM, signal.SIGINT): + # Shutdown this application. + self.shutdown() + + elif sig == signal.SIGUSR1: + # Submit all data. + self.submit_all() + + @property + def graph_default_arguments(self): + return GRAPH_DEFAULT_ARGUMENTS diff --git a/collecty/errors.py b/collecty/errors.py new file mode 100644 index 0000000..084af78 --- /dev/null +++ b/collecty/errors.py @@ -0,0 +1,26 @@ +#!/usr/bin/python +############################################################################### +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2012 IPFire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +class CollectyError(Exception): + pass + +class ConfigError(CollectyError): + pass diff --git a/collecty/plugins/base.py b/collecty/plugins/base.py index e85653e..76ac1cc 100644 --- a/collecty/plugins/base.py +++ b/collecty/plugins/base.py @@ -66,6 +66,12 @@ class Plugin(threading.Thread): # The schema of the RRD database. rrd_schema = None + # Instructions how to create the graph. + rrd_graph = None + + # Extra arguments passed to rrdgraph. + rrd_graph_args = [] + # The default interval of this plugin. default_interval = 60 @@ -104,6 +110,13 @@ class Plugin(threading.Thread): def __str__(self): return "Plugin %s %s" % (self.name, self.file) + @property + def id(self): + """ + A unique ID of the plugin instance. + """ + return self.name + @property def interval(self): """ @@ -219,16 +232,23 @@ class Plugin(threading.Thread): """ return int(time.time()) - def graph(self, file, interval=None): - args = [ "--imgformat", "PNG", - "-w", "580", # Width of the graph - "-h", "240", # Height of the graph - "--interlaced", "--slope-mode", ] + def graph(self, file, interval=None, + width=GRAPH_DEFAULT_WIDTH, height=GRAPH_DEFAULT_HEIGHT): + + args = [ + "--width", "%d" % width, + "--height", "%d" % height, + ] + args += self.collecty.graph_default_arguments + args += self.rrd_graph_args - intervals = { None : "-3h", - "hour" : "-1h", - "day" : "-25h", - "week" : "-360h" } + intervals = { + None : "-3h", + "hour" : "-1h", + "day" : "-25h", + "week" : "-360h", + "year" : "-365d", + } args.append("--start") if intervals.has_key(interval): @@ -237,10 +257,10 @@ class Plugin(threading.Thread): args.append(interval) info = { "file" : self.file } - for item in self._graph: + for item in self.rrd_graph: try: args.append(item % info) except TypeError: args.append(item) - rrdtool.graph(file, *args) + rrdtool.graph(file, *args) diff --git a/collecty/plugins/cpu.py b/collecty/plugins/cpu.py index bd21242..fc95fda 100644 --- a/collecty/plugins/cpu.py +++ b/collecty/plugins/cpu.py @@ -43,54 +43,79 @@ class PluginCPU(base.Plugin): "RRA:AVERAGE:0.5:60:8760", ] - _graph = [ "DEF:user=%(file)s:user:AVERAGE", - "DEF:nice=%(file)s:nice:AVERAGE", - "DEF:sys=%(file)s:sys:AVERAGE", - "DEF:idle=%(file)s:idle:AVERAGE", - "DEF:wait=%(file)s:wait:AVERAGE", - "DEF:interrupt=%(file)s:interrupt:AVERAGE", - "AREA:user#ff0000:%-15s" % _("User"), - "VDEF:usermin=user,MINIMUM", - "VDEF:usermax=user,MAXIMUM", - "VDEF:useravg=user,AVERAGE", - "GPRINT:usermax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:usermin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:useravg:%12s\:" % _("Average") + " %6.2lf\\n", - "STACK:nice#ff3300:%-15s" % _("Nice"), - "VDEF:nicemin=nice,MINIMUM", - "VDEF:nicemax=nice,MAXIMUM", - "VDEF:niceavg=nice,AVERAGE", - "GPRINT:nicemax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:nicemin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:niceavg:%12s\:" % _("Average") + " %6.2lf\\n", - "STACK:sys#ff6600:%-15s" % _("System"), - "VDEF:sysmin=sys,MINIMUM", - "VDEF:sysmax=sys,MAXIMUM", - "VDEF:sysavg=sys,AVERAGE", - "GPRINT:sysmax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:sysmin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:sysavg:%12s\:" % _("Average") + " %6.2lf\\n", - "STACK:wait#ff9900:%-15s" % _("Wait"), - "VDEF:waitmin=wait,MINIMUM", - "VDEF:waitmax=wait,MAXIMUM", - "VDEF:waitavg=wait,AVERAGE", - "GPRINT:waitmax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:waitmin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:waitavg:%12s\:" % _("Average") + " %6.2lf\\n", - "STACK:interrupt#ffcc00:%-15s" % _("Interrupt"), - "VDEF:interruptmin=interrupt,MINIMUM", - "VDEF:interruptmax=interrupt,MAXIMUM", - "VDEF:interruptavg=interrupt,AVERAGE", - "GPRINT:interruptmax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:interruptmin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:interruptavg:%12s\:" % _("Average") + " %6.2lf\\n", - "STACK:idle#ffff00:%-15s" % _("Idle"), - "VDEF:idlemin=idle,MINIMUM", - "VDEF:idlemax=idle,MAXIMUM", - "VDEF:idleavg=idle,AVERAGE", - "GPRINT:idlemax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:idlemin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:idleavg:%12s\:" % _("Average") + " %6.2lf\\n", ] + rrd_graph = [ + "DEF:user=%(file)s:user:AVERAGE", + "DEF:nice=%(file)s:nice:AVERAGE", + "DEF:sys=%(file)s:sys:AVERAGE", + "DEF:idle=%(file)s:idle:AVERAGE", + "DEF:wait=%(file)s:wait:AVERAGE", + "DEF:irq=%(file)s:irq:AVERAGE", + "DEF:sirq=%(file)s:sirq:AVERAGE", + + "AREA:user#90EE90:%-15s" % _("User"), + "VDEF:usermin=user,MINIMUM", + "VDEF:usermax=user,MAXIMUM", + "VDEF:useravg=user,AVERAGE", + "GPRINT:usermax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:usermin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:useravg:%12s\:" % _("Average") + " %6.2lf\\n", + + "STACK:nice#4169E1:%-15s" % _("Nice"), + "VDEF:nicemin=nice,MINIMUM", + "VDEF:nicemax=nice,MAXIMUM", + "VDEF:niceavg=nice,AVERAGE", + "GPRINT:nicemax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:nicemin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:niceavg:%12s\:" % _("Average") + " %6.2lf\\n", + + "STACK:sys#DC143C:%-15s" % _("System"), + "VDEF:sysmin=sys,MINIMUM", + "VDEF:sysmax=sys,MAXIMUM", + "VDEF:sysavg=sys,AVERAGE", + "GPRINT:sysmax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:sysmin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:sysavg:%12s\:" % _("Average") + " %6.2lf\\n", + + "STACK:wait#483D8B:%-15s" % _("Wait"), + "VDEF:waitmin=wait,MINIMUM", + "VDEF:waitmax=wait,MAXIMUM", + "VDEF:waitavg=wait,AVERAGE", + "GPRINT:waitmax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:waitmin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:waitavg:%12s\:" % _("Average") + " %6.2lf\\n", + + "STACK:irq#DAA520:%-15s" % _("Interrupt"), + "VDEF:irqmin=irq,MINIMUM", + "VDEF:irqmax=irq,MAXIMUM", + "VDEF:irqavg=irq,AVERAGE", + "GPRINT:irqmax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:irqmin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:irqavg:%12s\:" % _("Average") + " %6.2lf\\n", + + "STACK:sirq#FFD700:%-15s" % _("Soft interrupt"), + "VDEF:sirqmin=sirq,MINIMUM", + "VDEF:sirqmax=sirq,MAXIMUM", + "VDEF:sirqavg=sirq,AVERAGE", + "GPRINT:sirqmax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:sirqmin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:sirqavg:%12s\:" % _("Average") + " %6.2lf\\n", + +# "STACK:idle#ffff00:%-15s" % _("Idle"), +# "VDEF:idlemin=idle,MINIMUM", +# "VDEF:idlemax=idle,MAXIMUM", +# "VDEF:idleavg=idle,AVERAGE", +# "GPRINT:idlemax:%12s\:" % _("Maximum") + " %6.2lf" , +# "GPRINT:idlemin:%12s\:" % _("Minimum") + " %6.2lf", +# "GPRINT:idleavg:%12s\:" % _("Average") + " %6.2lf\\n", + ] + + rrd_graph_args = [ + "--title", _("CPU usage"), + "--vertical-label", _("Percent"), + + # This can never be more than 100 percent. + #"--lower-limit", "0", "--upper-limit", "100", + ] @classmethod def autocreate(cls, collecty, **kwargs): diff --git a/collecty/plugins/entropy.py b/collecty/plugins/entropy.py index 5aa77ec..7d588d6 100644 --- a/collecty/plugins/entropy.py +++ b/collecty/plugins/entropy.py @@ -23,6 +23,8 @@ import os import base +from ..i18n import _ + ENTROPY_FILE = "/proc/sys/kernel/random/entropy_avail" class PluginEntropy(base.Plugin): @@ -37,6 +39,27 @@ class PluginEntropy(base.Plugin): "RRA:AVERAGE:0.5:60:8760", ] + rrd_graph = [ + "DEF:entropy=%(file)s:entropy:AVERAGE", + "CDEF:entropytrend=entropy,43200,TREND", + + "LINE3:entropy#ff0000:%-15s" % _("Available entropy"), + "VDEF:entrmin=entropy,MINIMUM", + "VDEF:entrmax=entropy,MAXIMUM", + "VDEF:entravg=entropy,AVERAGE", + "GPRINT:entrmax:%12s\:" % _("Maximum") + " %5.0lf", + "GPRINT:entrmin:%12s\:" % _("Minimum") + " %5.0lf", + "GPRINT:entravg:%12s\:" % _("Average") + " %5.0lf\\n", + + "LINE3:entropytrend#000000", + ] + rrd_graph_args = [ + "--title", _("Available entropy"), + "--vertical-label", _("Bits"), + + "--lower-limit", "0", "--rigid", + ] + @classmethod def autocreate(cls, collecty, **kwargs): if not os.path.exists(ENTROPY_FILE): diff --git a/collecty/plugins/loadavg.py b/collecty/plugins/loadavg.py index 119c535..9b56e13 100644 --- a/collecty/plugins/loadavg.py +++ b/collecty/plugins/loadavg.py @@ -39,32 +39,44 @@ class PluginLoadAvg(base.Plugin): "RRA:AVERAGE:0.5:60:8760", ] - _graph = [ "DEF:load1=%(file)s:load1:AVERAGE", - "DEF:load5=%(file)s:load5:AVERAGE", - "DEF:load15=%(file)s:load15:AVERAGE", - "AREA:load1#ff0000:%s" % _("Load average 1m"), - "VDEF:load1min=load1,MINIMUM", - "VDEF:load1max=load1,MAXIMUM", - "VDEF:load1avg=load1,AVERAGE", - "GPRINT:load1max:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:load1min:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:load1avg:%12s\:" % _("Average") + " %6.2lf\\n", - "AREA:load5#ff9900:%s" % _("Load average 5m"), - "VDEF:load5min=load5,MINIMUM", - "VDEF:load5max=load5,MAXIMUM", - "VDEF:load5avg=load5,AVERAGE", - "GPRINT:load5max:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:load5min:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:load5avg:%12s\:" % _("Average") + " %6.2lf\\n", - "AREA:load15#ffff00:%s" % _("Load average 15m"), - "VDEF:load15min=load15,MINIMUM", - "VDEF:load15max=load15,MAXIMUM", - "VDEF:load15avg=load15,AVERAGE", - "GPRINT:load15max:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:load15min:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:load15avg:%12s\:" % _("Average") + " %6.2lf\\n", - "LINE:load5#dd8800", - "LINE:load1#dd0000", ] + rrd_graph = [ + "DEF:load1=%(file)s:load1:AVERAGE", + "DEF:load5=%(file)s:load5:AVERAGE", + "DEF:load15=%(file)s:load15:AVERAGE", + + "AREA:load1#ff0000:%s" % _("Load average 1m"), + "VDEF:load1min=load1,MINIMUM", + "VDEF:load1max=load1,MAXIMUM", + "VDEF:load1avg=load1,AVERAGE", + "GPRINT:load1max:%12s\:" % _("Maximum") + " %6.2lf", + "GPRINT:load1min:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:load1avg:%12s\:" % _("Average") + " %6.2lf\\n", + + "AREA:load5#ff9900:%s" % _("Load average 5m"), + "VDEF:load5min=load5,MINIMUM", + "VDEF:load5max=load5,MAXIMUM", + "VDEF:load5avg=load5,AVERAGE", + "GPRINT:load5max:%12s\:" % _("Maximum") + " %6.2lf", + "GPRINT:load5min:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:load5avg:%12s\:" % _("Average") + " %6.2lf\\n", + + "AREA:load15#ffff00:%s" % _("Load average 15m"), + "VDEF:load15min=load15,MINIMUM", + "VDEF:load15max=load15,MAXIMUM", + "VDEF:load15avg=load15,AVERAGE", + "GPRINT:load15max:%12s\:" % _("Maximum") + " %6.2lf", + "GPRINT:load15min:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:load15avg:%12s\:" % _("Average") + " %6.2lf\\n", + + "LINE:load5#dd8800", + "LINE:load1#dd0000", + ] + rrd_graph_args = [ + "--title", _("Load average"), + "--vertical-label", _("Load"), + + "--lower-limit", "0", "--rigid", + ] @classmethod def autocreate(cls, collecty, **kwargs): diff --git a/collecty/plugins/memory.py b/collecty/plugins/memory.py index 2c20201..952442a 100644 --- a/collecty/plugins/memory.py +++ b/collecty/plugins/memory.py @@ -41,46 +41,62 @@ class PluginMemory(base.Plugin): "RRA:AVERAGE:0.5:60:8760", ] - _graph = [ "DEF:used=%(file)s:used:AVERAGE", - "DEF:cached=%(file)s:cached:AVERAGE", - "DEF:buffered=%(file)s:buffered:AVERAGE", - "DEF:free=%(file)s:free:AVERAGE", - "DEF:swap=%(file)s:swap:AVERAGE", - "AREA:used#0000ee:%-15s" % _("Used memory"), - "VDEF:usedmin=used,MINIMUM", - "VDEF:usedmax=used,MAXIMUM", - "VDEF:usedavg=used,AVERAGE", - "GPRINT:usedmax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:usedmin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:usedavg:%12s\:" % _("Average") + " %6.2lf\\n", - "STACK:cached#0099ee:%-15s" % _("Cached data"), - "VDEF:cachedmin=cached,MINIMUM", - "VDEF:cachedmax=cached,MAXIMUM", - "VDEF:cachedavg=cached,AVERAGE", - "GPRINT:cachedmax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:cachedmin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:cachedavg:%12s\:" % _("Average") + " %6.2lf\\n", - "STACK:buffered#4499ff:%-15s" % _("Buffered data"), - "VDEF:bufferedmin=buffered,MINIMUM", - "VDEF:bufferedmax=buffered,MAXIMUM", - "VDEF:bufferedavg=buffered,AVERAGE", - "GPRINT:bufferedmax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:bufferedmin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:bufferedavg:%12s\:" % _("Average") + " %6.2lf\\n", - "STACK:free#7799ff:%-15s" % _("Free memory"), - "VDEF:freemin=free,MINIMUM", - "VDEF:freemax=free,MAXIMUM", - "VDEF:freeavg=free,AVERAGE", - "GPRINT:freemax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:freemin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:freeavg:%12s\:" % _("Average") + " %6.2lf\\n", - "LINE3:swap#ff0000:%-15s" % _("Used Swap space"), - "VDEF:swapmin=swap,MINIMUM", - "VDEF:swapmax=swap,MAXIMUM", - "VDEF:swapavg=swap,AVERAGE", - "GPRINT:swapmax:%12s\:" % _("Maximum") + " %6.2lf" , - "GPRINT:swapmin:%12s\:" % _("Minimum") + " %6.2lf", - "GPRINT:swapavg:%12s\:" % _("Average") + " %6.2lf\\n", ] + rrd_graph = [ + "DEF:used=%(file)s:used:AVERAGE", + "DEF:cached=%(file)s:cached:AVERAGE", + "DEF:buffered=%(file)s:buffered:AVERAGE", + "DEF:free=%(file)s:free:AVERAGE", + "DEF:swap=%(file)s:swap:AVERAGE", + + "AREA:used#90EE90:%-15s" % _("Used memory"), + "VDEF:usedmin=used,MINIMUM", + "VDEF:usedmax=used,MAXIMUM", + "VDEF:usedavg=used,AVERAGE", + "GPRINT:usedmax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:usedmin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:usedavg:%12s\:" % _("Average") + " %6.2lf\\n", + + "STACK:buffered#4169E1:%-15s" % _("Buffered data"), + "VDEF:bufferedmin=buffered,MINIMUM", + "VDEF:bufferedmax=buffered,MAXIMUM", + "VDEF:bufferedavg=buffered,AVERAGE", + "GPRINT:bufferedmax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:bufferedmin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:bufferedavg:%12s\:" % _("Average") + " %6.2lf\\n", + + "STACK:cached#FFD700:%-15s" % _("Cached data"), + "VDEF:cachedmin=cached,MINIMUM", + "VDEF:cachedmax=cached,MAXIMUM", + "VDEF:cachedavg=cached,AVERAGE", + "GPRINT:cachedmax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:cachedmin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:cachedavg:%12s\:" % _("Average") + " %6.2lf\\n", + +# "STACK:free#7799ff:%-15s" % _("Free memory"), +# "VDEF:freemin=free,MINIMUM", +# "VDEF:freemax=free,MAXIMUM", +# "VDEF:freeavg=free,AVERAGE", +# "GPRINT:freemax:%12s\:" % _("Maximum") + " %6.2lf" , +# "GPRINT:freemin:%12s\:" % _("Minimum") + " %6.2lf", +# "GPRINT:freeavg:%12s\:" % _("Average") + " %6.2lf\\n", + + "LINE3:swap#ff0000:%-15s" % _("Used Swap space"), + "VDEF:swapmin=swap,MINIMUM", + "VDEF:swapmax=swap,MAXIMUM", + "VDEF:swapavg=swap,AVERAGE", + "GPRINT:swapmax:%12s\:" % _("Maximum") + " %6.2lf" , + "GPRINT:swapmin:%12s\:" % _("Minimum") + " %6.2lf", + "GPRINT:swapavg:%12s\:" % _("Average") + " %6.2lf\\n", + ] + rrd_graph_args = [ + "--title", _("Memory Usage"), + "--vertical-label", _("Percent"), + + # Limit y axis. + "--upper-limit", "100", + "--lower-limit", "0", + "--rigid", + ] @classmethod def autocreate(cls, collecty, **kwargs): diff --git a/collectyd b/collectyd index a90e5de..32caafa 100755 --- a/collectyd +++ b/collectyd @@ -32,7 +32,7 @@ op.add_option("-d", "--debug", action="store_true", default=False, # Initialize the settings for this Collecty instance. settings = { - debug : options.debug, + "debug" : options.debug, } # Initialize the application. diff --git a/po/collecty.pot b/po/collecty.pot index 4cf4a7d..67e180c 100644 --- a/po/collecty.pot +++ b/po/collecty.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-08 08:55+0000\n" +"POT-Creation-Date: 2012-08-25 11:22+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,166 +17,202 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: collecty/__init__.py:61 +#. Brand all generated graphs. +#: collecty/constants.py:44 +msgid "Created by collecty" +msgstr "" + +#: collecty/daemon.py:49 msgid "Collecty successfully initialized." msgstr "" -#: collecty/__init__.py:75 +#: collecty/daemon.py:63 #, python-format msgid "Plugin '%(name)s' registered %(number)s instance(s)." msgstr "" -#: collecty/__init__.py:120 +#: collecty/daemon.py:108 #, python-format msgid "%s is not alive anymore. Removing." msgstr "" -#: collecty/__init__.py:126 +#: collecty/daemon.py:114 msgid "No thread running. Exiting main thread." msgstr "" -#: collecty/__init__.py:132 +#: collecty/daemon.py:120 msgid "Submitting all data in memory" msgstr "" -#: collecty/__init__.py:140 +#: collecty/daemon.py:128 msgid "Received shutdown signal" msgstr "" -#: collecty/__init__.py:152 +#: collecty/daemon.py:140 #, python-format msgid "Registering signal %d" msgstr "" -#: collecty/__init__.py:157 +#: collecty/daemon.py:145 #, python-format msgid "Caught signal %d" msgstr "" -#: collecty/plugins/base.py:99 +#: collecty/plugins/base.py:105 msgid "Successfully initialized." msgstr "" -#: collecty/plugins/base.py:139 +#: collecty/plugins/base.py:152 #, python-format msgid "Created RRD file %s." msgstr "" -#: collecty/plugins/base.py:166 +#: collecty/plugins/base.py:179 #, python-format msgid "Submitting data to database. %d entries." msgstr "" -#: collecty/plugins/base.py:179 +#: collecty/plugins/base.py:192 msgid "Unhandled exception in read()!" msgstr "" -#: collecty/plugins/base.py:190 +#: collecty/plugins/base.py:203 msgid "Unhandled exception in submit()!" msgstr "" -#: collecty/plugins/base.py:193 +#: collecty/plugins/base.py:206 msgid "Started." msgstr "" -#: collecty/plugins/base.py:201 +#: collecty/plugins/base.py:214 msgid "Collecting..." msgstr "" -#: collecty/plugins/base.py:205 +#: collecty/plugins/base.py:218 msgid "Stopped." msgstr "" -#: collecty/plugins/base.py:208 +#: collecty/plugins/base.py:221 msgid "Received shutdown signal." msgstr "" -#: collecty/plugins/cpu.py:52 +#: collecty/plugins/cpu.py:55 msgid "User" msgstr "" -#: collecty/plugins/cpu.py:56 collecty/plugins/cpu.py:63 -#: collecty/plugins/cpu.py:70 collecty/plugins/cpu.py:77 -#: collecty/plugins/cpu.py:84 collecty/plugins/cpu.py:91 -#: collecty/plugins/loadavg.py:49 collecty/plugins/loadavg.py:56 -#: collecty/plugins/loadavg.py:63 collecty/plugins/memory.py:53 -#: collecty/plugins/memory.py:60 collecty/plugins/memory.py:67 -#: collecty/plugins/memory.py:74 collecty/plugins/memory.py:81 +#: collecty/plugins/cpu.py:59 collecty/plugins/cpu.py:67 +#: collecty/plugins/cpu.py:75 collecty/plugins/cpu.py:83 +#: collecty/plugins/cpu.py:91 collecty/plugins/cpu.py:99 +#: collecty/plugins/entropy.py:50 collecty/plugins/loadavg.py:51 +#: collecty/plugins/loadavg.py:59 collecty/plugins/loadavg.py:67 +#: collecty/plugins/memory.py:55 collecty/plugins/memory.py:63 +#: collecty/plugins/memory.py:71 collecty/plugins/memory.py:87 msgid "Maximum" msgstr "" -#: collecty/plugins/cpu.py:57 collecty/plugins/cpu.py:64 -#: collecty/plugins/cpu.py:71 collecty/plugins/cpu.py:78 -#: collecty/plugins/cpu.py:85 collecty/plugins/cpu.py:92 -#: collecty/plugins/loadavg.py:50 collecty/plugins/loadavg.py:57 -#: collecty/plugins/loadavg.py:64 collecty/plugins/memory.py:54 -#: collecty/plugins/memory.py:61 collecty/plugins/memory.py:68 -#: collecty/plugins/memory.py:75 collecty/plugins/memory.py:82 +#: collecty/plugins/cpu.py:60 collecty/plugins/cpu.py:68 +#: collecty/plugins/cpu.py:76 collecty/plugins/cpu.py:84 +#: collecty/plugins/cpu.py:92 collecty/plugins/cpu.py:100 +#: collecty/plugins/entropy.py:51 collecty/plugins/loadavg.py:52 +#: collecty/plugins/loadavg.py:60 collecty/plugins/loadavg.py:68 +#: collecty/plugins/memory.py:56 collecty/plugins/memory.py:64 +#: collecty/plugins/memory.py:72 collecty/plugins/memory.py:88 msgid "Minimum" msgstr "" -#: collecty/plugins/cpu.py:58 collecty/plugins/cpu.py:65 -#: collecty/plugins/cpu.py:72 collecty/plugins/cpu.py:79 -#: collecty/plugins/cpu.py:86 collecty/plugins/cpu.py:93 -#: collecty/plugins/loadavg.py:51 collecty/plugins/loadavg.py:58 -#: collecty/plugins/loadavg.py:65 collecty/plugins/memory.py:55 -#: collecty/plugins/memory.py:62 collecty/plugins/memory.py:69 -#: collecty/plugins/memory.py:76 collecty/plugins/memory.py:83 +#: collecty/plugins/cpu.py:61 collecty/plugins/cpu.py:69 +#: collecty/plugins/cpu.py:77 collecty/plugins/cpu.py:85 +#: collecty/plugins/cpu.py:93 collecty/plugins/cpu.py:101 +#: collecty/plugins/entropy.py:52 collecty/plugins/loadavg.py:53 +#: collecty/plugins/loadavg.py:61 collecty/plugins/loadavg.py:69 +#: collecty/plugins/memory.py:57 collecty/plugins/memory.py:65 +#: collecty/plugins/memory.py:73 collecty/plugins/memory.py:89 msgid "Average" msgstr "" -#: collecty/plugins/cpu.py:59 +#: collecty/plugins/cpu.py:63 msgid "Nice" msgstr "" -#: collecty/plugins/cpu.py:66 +#: collecty/plugins/cpu.py:71 msgid "System" msgstr "" -#: collecty/plugins/cpu.py:73 +#: collecty/plugins/cpu.py:79 msgid "Wait" msgstr "" -#: collecty/plugins/cpu.py:80 +#: collecty/plugins/cpu.py:87 msgid "Interrupt" msgstr "" -#: collecty/plugins/cpu.py:87 -msgid "Idle" +#: collecty/plugins/cpu.py:95 +msgid "Soft interrupt" +msgstr "" + +#: collecty/plugins/cpu.py:113 +msgid "CPU usage" +msgstr "" + +#: collecty/plugins/cpu.py:114 collecty/plugins/memory.py:93 +msgid "Percent" +msgstr "" + +#: collecty/plugins/entropy.py:46 collecty/plugins/entropy.py:57 +msgid "Available entropy" +msgstr "" + +#: collecty/plugins/entropy.py:58 +msgid "Bits" msgstr "" -#: collecty/plugins/entropy.py:43 +#: collecty/plugins/entropy.py:66 msgid "Entropy kernel interface does not exist." msgstr "" -#: collecty/plugins/loadavg.py:45 +#: collecty/plugins/loadavg.py:47 msgid "Load average 1m" msgstr "" -#: collecty/plugins/loadavg.py:52 +#: collecty/plugins/loadavg.py:55 msgid "Load average 5m" msgstr "" -#: collecty/plugins/loadavg.py:59 +#: collecty/plugins/loadavg.py:63 msgid "Load average 15m" msgstr "" -#: collecty/plugins/memory.py:49 -msgid "Used memory" +#: collecty/plugins/loadavg.py:75 +msgid "Load average" msgstr "" -#: collecty/plugins/memory.py:56 -msgid "Cached data" +#: collecty/plugins/loadavg.py:76 +msgid "Load" msgstr "" -#: collecty/plugins/memory.py:63 +#: collecty/plugins/memory.py:51 +msgid "Used memory" +msgstr "" + +#: collecty/plugins/memory.py:59 msgid "Buffered data" msgstr "" -#: collecty/plugins/memory.py:70 -msgid "Free memory" +#: collecty/plugins/memory.py:67 +msgid "Cached data" msgstr "" -#: collecty/plugins/memory.py:77 +#. "STACK:free#7799ff:%-15s" % _("Free memory"), +#. "VDEF:freemin=free,MINIMUM", +#. "VDEF:freemax=free,MAXIMUM", +#. "VDEF:freeavg=free,AVERAGE", +#. "GPRINT:freemax:%12s\:" % _("Maximum") + " %6.2lf" , +#. "GPRINT:freemin:%12s\:" % _("Minimum") + " %6.2lf", +#. "GPRINT:freeavg:%12s\:" % _("Average") + " %6.2lf\\n", +#: collecty/plugins/memory.py:83 msgid "Used Swap space" msgstr "" + +#: collecty/plugins/memory.py:92 +msgid "Memory Usage" +msgstr ""