]> git.ipfire.org Git - collecty.git/blame - collecty/plugins/base.py
plugins: Restructure the plugin concept.
[collecty.git] / collecty / plugins / base.py
CommitLineData
eed405de
MT
1#!/usr/bin/python
2###############################################################################
3# #
4# collecty - A system statistics collection daemon for IPFire #
5# Copyright (C) 2012 IPFire development team #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
4ac0cdf0
MT
22import logging
23import os
24import rrdtool
25import time
26
eed405de
MT
27from threading import Thread
28
4ac0cdf0 29from ..constants import *
eed405de
MT
30from ..i18n import _
31
32class Plugin(Thread):
4ac0cdf0
MT
33 # The name of this plugin.
34 name = None
35
36 # A description for this plugin.
37 description = None
38
39 # The schema of the RRD database.
40 rrd_schema = None
41
42 # The default interval of this plugin.
43 default_interval = 60
44
eed405de
MT
45 def __init__(self, collecty, **kwargs):
46 Thread.__init__(self)
47 self.collecty = collecty
48
4ac0cdf0
MT
49 # Check if this plugin was configured correctly.
50 assert self.name, "Name of the plugin is not set: %s" % self.name
51 assert self.description, "Description of the plugin is not set: %s" % self.description
52 assert self.rrd_schema
53
54 # Initialize the logger.
55 self.log = logging.getLogger("collecty.plugins.%s" % self.name)
56 self.log.propagate = 1
eed405de
MT
57
58 # Keepalive options
59 self.heartbeat = 2
4ac0cdf0 60 self.running = True
eed405de
MT
61
62 self.data = []
63
4ac0cdf0 64 # Create the database file.
eed405de 65 self.create()
4ac0cdf0
MT
66
67 # Run some custom initialization.
68 self.init()
69
70 self.log.info(_("Successfully initialized."))
eed405de
MT
71
72 def __repr__(self):
4ac0cdf0 73 return "<Plugin %s>" % self.name
eed405de
MT
74
75 def __str__(self):
4ac0cdf0
MT
76 return "Plugin %s %s" % (self.name, self.file)
77
78 @property
79 def interval(self):
80 """
81 Returns the interval in milliseconds, when the read method
82 should be called again.
83 """
84 # XXX read this from the settings
85
86 # Otherwise return the default.
87 return self.default_interval
88
89 @property
90 def file(self):
91 """
92 The absolute path to the RRD file of this plugin.
93 """
94 return os.path.join(DATABASE_DIR, "%s.rrd" % self.name)
eed405de 95
4ac0cdf0
MT
96 def create(self):
97 """
98 Creates an empty RRD file with the desired data structures.
99 """
100 # Skip if the file does already exist.
101 if os.path.exists(self.file):
102 return
eed405de 103
4ac0cdf0
MT
104 dirname = os.path.dirname(self.file)
105 if not os.path.exists(dirname):
106 os.makedirs(dirname)
eed405de 107
4ac0cdf0 108 rrdtool.create(self.file, *self.rrd_schema)
eed405de 109
4ac0cdf0 110 self.log.debug(_("Created RRD file %s.") % self.file)
eed405de 111
4ac0cdf0
MT
112 def info(self):
113 return rrdtool.info(self.file)
eed405de 114
4ac0cdf0
MT
115 ### Basic methods
116
117 def init(self):
118 """
119 Do some custom initialization stuff here.
120 """
121 pass
122
123 def read(self):
124 """
125 Gathers the statistical data, this plugin collects.
126 """
127 raise NotImplementedError
128
129 def submit(self):
130 """
131 Flushes the read data to disk.
132 """
133 # Do nothing in case there is no data to submit.
134 if not self.data:
135 return
136
137 self.collecty.debug(_("Saving data from %s...") % self)
138 rrdtool.update(self.file, *self.data)
139 self.data = []
eed405de 140
4ac0cdf0
MT
141 def __read(self, *args, **kwargs):
142 """
143 This method catches errors from the read() method and logs them.
144 """
145 try:
146 return self.read(*args, **kwargs)
147
148 # Catch any exceptions, so collecty does not crash.
149 except Exception, e:
150 self.log.critical(_("Unhandled exception in read()!"), exc_info=True)
151
152 def __submit(self, *args, **kwargs):
153 """
154 This method catches errors from the submit() method and logs them.
155 """
156 try:
157 return self.submit(*args, **kwargs)
eed405de 158
4ac0cdf0
MT
159 # Catch any exceptions, so collecty does not crash.
160 except Exception, e:
161 self.log.critical(_("Unhandled exception in submit()!"), exc_info=True)
162
163 def run(self):
164 self.log.debug(_("Started."))
eed405de 165
4ac0cdf0
MT
166 counter = 0
167 while self.running:
168 if counter == 0:
169 self.log.debug(_("Collecting..."))
170 self.__read()
171
172 self.log.debug(_("Sleeping for %.4fs.") % self.interval)
173
174 counter = self.interval / self.heartbeat
175
176 time.sleep(self.heartbeat)
177 counter -= 1
178
179 self.__submit()
180 self.log.debug(_("Stopped."))
181
182 def shutdown(self):
183 self.log.debug(_("Received shutdown signal."))
184 self.running = False
185
186 @property
187 def now(self):
188 """
189 Returns the current timestamp in the UNIX timestamp format (UTC).
190 """
191 return int(time.time())
eed405de
MT
192
193 def graph(self, file, interval=None):
194 args = [ "--imgformat", "PNG",
195 "-w", "580", # Width of the graph
196 "-h", "240", # Height of the graph
197 "--interlaced", "--slope-mode", ]
198
199 intervals = { None : "-3h",
200 "hour" : "-1h",
201 "day" : "-25h",
202 "week" : "-360h" }
203
204 args.append("--start")
205 if intervals.has_key(interval):
206 args.append(intervals[interval])
207 else:
208 args.append(interval)
209
210 info = { "file" : self.file }
211 for item in self._graph:
212 try:
213 args.append(item % info)
214 except TypeError:
215 args.append(item)
216
217 rrdtool.graph(file, *args)