]> git.ipfire.org Git - collecty.git/blame - collecty/plugins/base.py
memory: Update plugin.
[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
49ce926e 25import threading
4ac0cdf0
MT
26import time
27
4ac0cdf0 28from ..constants import *
eed405de
MT
29from ..i18n import _
30
49ce926e 31class Plugin(threading.Thread):
4ac0cdf0
MT
32 # The name of this plugin.
33 name = None
34
35 # A description for this plugin.
36 description = None
37
38 # The schema of the RRD database.
39 rrd_schema = None
40
41 # The default interval of this plugin.
42 default_interval = 60
43
eed405de 44 def __init__(self, collecty, **kwargs):
49ce926e
MT
45 threading.Thread.__init__(self, name=self.description)
46 self.daemon = True
47
eed405de
MT
48 self.collecty = collecty
49
4ac0cdf0
MT
50 # Check if this plugin was configured correctly.
51 assert self.name, "Name of the plugin is not set: %s" % self.name
52 assert self.description, "Description of the plugin is not set: %s" % self.description
53 assert self.rrd_schema
54
55 # Initialize the logger.
56 self.log = logging.getLogger("collecty.plugins.%s" % self.name)
57 self.log.propagate = 1
eed405de
MT
58
59 # Keepalive options
60 self.heartbeat = 2
4ac0cdf0 61 self.running = True
eed405de
MT
62
63 self.data = []
64
4ac0cdf0 65 # Create the database file.
eed405de 66 self.create()
4ac0cdf0
MT
67
68 # Run some custom initialization.
69 self.init()
70
71 self.log.info(_("Successfully initialized."))
eed405de
MT
72
73 def __repr__(self):
4ac0cdf0 74 return "<Plugin %s>" % self.name
eed405de
MT
75
76 def __str__(self):
4ac0cdf0
MT
77 return "Plugin %s %s" % (self.name, self.file)
78
79 @property
80 def interval(self):
81 """
82 Returns the interval in milliseconds, when the read method
83 should be called again.
84 """
85 # XXX read this from the settings
86
87 # Otherwise return the default.
88 return self.default_interval
89
90 @property
91 def file(self):
92 """
93 The absolute path to the RRD file of this plugin.
94 """
95 return os.path.join(DATABASE_DIR, "%s.rrd" % self.name)
eed405de 96
4ac0cdf0
MT
97 def create(self):
98 """
99 Creates an empty RRD file with the desired data structures.
100 """
101 # Skip if the file does already exist.
102 if os.path.exists(self.file):
103 return
eed405de 104
4ac0cdf0
MT
105 dirname = os.path.dirname(self.file)
106 if not os.path.exists(dirname):
107 os.makedirs(dirname)
eed405de 108
4ac0cdf0 109 rrdtool.create(self.file, *self.rrd_schema)
eed405de 110
4ac0cdf0 111 self.log.debug(_("Created RRD file %s.") % self.file)
eed405de 112
4ac0cdf0
MT
113 def info(self):
114 return rrdtool.info(self.file)
eed405de 115
4ac0cdf0
MT
116 ### Basic methods
117
118 def init(self):
119 """
120 Do some custom initialization stuff here.
121 """
122 pass
123
124 def read(self):
125 """
126 Gathers the statistical data, this plugin collects.
127 """
128 raise NotImplementedError
129
130 def submit(self):
131 """
132 Flushes the read data to disk.
133 """
134 # Do nothing in case there is no data to submit.
135 if not self.data:
136 return
137
49ce926e 138 self.log.debug(_("Submitting data to database. %d entries.") % len(self.data))
4ac0cdf0
MT
139 rrdtool.update(self.file, *self.data)
140 self.data = []
eed405de 141
4ac0cdf0
MT
142 def __read(self, *args, **kwargs):
143 """
144 This method catches errors from the read() method and logs them.
145 """
146 try:
147 return self.read(*args, **kwargs)
148
149 # Catch any exceptions, so collecty does not crash.
150 except Exception, e:
151 self.log.critical(_("Unhandled exception in read()!"), exc_info=True)
152
153 def __submit(self, *args, **kwargs):
154 """
155 This method catches errors from the submit() method and logs them.
156 """
157 try:
158 return self.submit(*args, **kwargs)
eed405de 159
4ac0cdf0
MT
160 # Catch any exceptions, so collecty does not crash.
161 except Exception, e:
162 self.log.critical(_("Unhandled exception in submit()!"), exc_info=True)
163
164 def run(self):
165 self.log.debug(_("Started."))
eed405de 166
4ac0cdf0
MT
167 counter = 0
168 while self.running:
169 if counter == 0:
170 self.log.debug(_("Collecting..."))
171 self.__read()
172
173 self.log.debug(_("Sleeping for %.4fs.") % self.interval)
174
175 counter = self.interval / self.heartbeat
176
177 time.sleep(self.heartbeat)
178 counter -= 1
179
180 self.__submit()
181 self.log.debug(_("Stopped."))
182
183 def shutdown(self):
184 self.log.debug(_("Received shutdown signal."))
185 self.running = False
186
187 @property
188 def now(self):
189 """
190 Returns the current timestamp in the UNIX timestamp format (UTC).
191 """
192 return int(time.time())
eed405de
MT
193
194 def graph(self, file, interval=None):
195 args = [ "--imgformat", "PNG",
196 "-w", "580", # Width of the graph
197 "-h", "240", # Height of the graph
198 "--interlaced", "--slope-mode", ]
199
200 intervals = { None : "-3h",
201 "hour" : "-1h",
202 "day" : "-25h",
203 "week" : "-360h" }
204
205 args.append("--start")
206 if intervals.has_key(interval):
207 args.append(intervals[interval])
208 else:
209 args.append(interval)
210
211 info = { "file" : self.file }
212 for item in self._graph:
213 try:
214 args.append(item % info)
215 except TypeError:
216 args.append(item)
217
218 rrdtool.graph(file, *args)