1d26d2072a6491cdeafc76f13a12c5c934536850
[collectd.git] / bindings / perl / Collectd.pm
1 # collectd - Collectd.pm
2 # Copyright (C) 2007  Sebastian Harl
3 #
4 # This program is free software; you can redistribute it and/or modify it
5 # under the terms of the GNU General Public License as published by the
6 # Free Software Foundation; only version 2 of the License is applicable.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 # General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
16 #
17 # Author:
18 #   Sebastian Harl <sh at tokkee.org>
19
20 package Collectd;
21
22 use strict;
23 use warnings;
24
25 use Config;
26
27 BEGIN {
28         if (! $Config{'useithreads'}) {
29                 die "Perl does not support ithreads!";
30         }
31 }
32
33 require Exporter;
34
35 our @ISA = qw( Exporter );
36
37 our %EXPORT_TAGS = (
38         'plugin' => [ qw(
39                         plugin_register
40                         plugin_unregister
41                         plugin_dispatch_values
42                         plugin_log
43         ) ],
44         'types' => [ qw(
45                         TYPE_INIT
46                         TYPE_READ
47                         TYPE_WRITE
48                         TYPE_SHUTDOWN
49                         TYPE_LOG
50                         TYPE_DATASET
51         ) ],
52         'ds_types' => [ qw(
53                         DS_TYPE_COUNTER
54                         DS_TYPE_GAUGE
55         ) ],
56         'log' => [ qw(
57                         ERROR
58                         WARNING
59                         NOTICE
60                         INFO
61                         DEBUG
62                         LOG_ERR
63                         LOG_WARNING
64                         LOG_NOTICE
65                         LOG_INFO
66                         LOG_DEBUG
67         ) ],
68 );
69
70 {
71         my %seen;
72         push @{$EXPORT_TAGS{'all'}}, grep {! $seen{$_}++ } @{$EXPORT_TAGS{$_}}
73                 foreach keys %EXPORT_TAGS;
74 }
75
76 Exporter::export_ok_tags ('all');
77
78 my @plugins  = ();
79 my @datasets = ();
80
81 my %types = (
82         TYPE_INIT,     "init",
83         TYPE_READ,     "read",
84         TYPE_WRITE,    "write",
85         TYPE_SHUTDOWN, "shutdown",
86         TYPE_LOG,      "log"
87 );
88
89 foreach my $type (keys %types) {
90         $plugins[$type] = {};
91 }
92
93 sub _log {
94         my $caller = shift;
95         my $lvl    = shift;
96         my $msg    = shift;
97
98         if ("Collectd" eq $caller) {
99                 $msg = "perl: $msg";
100         }
101         return plugin_log ($lvl, $msg);
102 }
103
104 sub ERROR   { _log (scalar caller, LOG_ERR,     shift); }
105 sub WARNING { _log (scalar caller, LOG_WARNING, shift); }
106 sub NOTICE  { _log (scalar caller, LOG_NOTICE,  shift); }
107 sub INFO    { _log (scalar caller, LOG_INFO,    shift); }
108 sub DEBUG   { _log (scalar caller, LOG_DEBUG,   shift); }
109
110 sub plugin_call_all {
111         my $type = shift;
112
113         if (! defined $type) {
114                 return;
115         }
116
117         if (TYPE_LOG != $type) {
118                 DEBUG ("Collectd::plugin_call: type = \"$type\", args=\"@_\"");
119         }
120
121         if (! defined $plugins[$type]) {
122                 ERROR ("Collectd::plugin_call: unknown type \"$type\"");
123                 return;
124         }
125
126         foreach my $plugin (keys %{$plugins[$type]}) {
127                 my $p = $plugins[$type]->{$plugin};
128
129                 if ($p->{'wait_left'} > 0) {
130                         # TODO: use interval_g
131                         $p->{'wait_left'} -= 10;
132                 }
133
134                 next if ($p->{'wait_left'} > 0);
135
136                 if (my $status = $p->{'code'}->(@_)) {
137                         $p->{'wait_left'} = 0;
138                         $p->{'wait_time'} = 10;
139                 }
140                 elsif (TYPE_READ == $type) {
141                         $p->{'wait_left'} = $p->{'wait_time'};
142                         $p->{'wait_time'} *= 2;
143
144                         if ($p->{'wait_time'} > 86400) {
145                                 $p->{'wait_time'} = 86400;
146                         }
147
148                         WARNING ("${plugin}->read() failed with status $status. "
149                                 . "Will suspend it for $p->{'wait_left'} seconds.");
150                 }
151                 elsif (TYPE_INIT == $type) {
152                         foreach my $type (keys %types) {
153                                 plugin_unregister ($type, $plugin);
154                         }
155
156                         ERROR ("${plugin}->init() failed with status $status. "
157                                 . "Plugin will be disabled.");
158                 }
159                 elsif (TYPE_LOG != $type) {
160                         WARNING ("${plugin}->$types{$type}() failed with status $status.");
161                 }
162         }
163         return 1;
164 }
165
166 # Collectd::plugin_register (type, name, data).
167 #
168 # type:
169 #   init, read, write, shutdown, data set
170 #
171 # name:
172 #   name of the plugin
173 #
174 # data:
175 #   reference to the plugin's subroutine that does the work or the data set
176 #   definition
177 sub plugin_register {
178         my $type = shift;
179         my $name = shift;
180         my $data = shift;
181
182         DEBUG ("Collectd::plugin_register: "
183                 . "type = \"$type\", name = \"$name\", data = \"$data\"");
184
185         if (! ((defined $type) && (defined $name) && (defined $data))) {
186                 ERROR ("Usage: Collectd::plugin_register (type, name, data)");
187                 return;
188         }
189
190         if ((! defined $plugins[$type]) && (TYPE_DATASET != $type)) {
191                 ERROR ("Collectd::plugin_register: Invalid type \"$type\"");
192                 return;
193         }
194
195         if ((TYPE_DATASET == $type) && ("ARRAY" eq ref $data)) {
196                 return plugin_register_data_set ($name, $data);
197         }
198         elsif ("CODE" eq ref $data) {
199                 # TODO: make interval_g available at configuration time
200                 $plugins[$type]->{$name} = {
201                                 wait_time => 10,
202                                 wait_left => 0,
203                                 code      => $data,
204                 };
205         }
206         else {
207                 ERROR ("Collectd::plugin_register: Invalid data.");
208                 return;
209         }
210         return 1;
211 }
212
213 sub plugin_unregister {
214         my $type = shift;
215         my $name = shift;
216
217         DEBUG ("Collectd::plugin_unregister: type = \"$type\", name = \"$name\"");
218
219         if (! ((defined $type) && (defined $name))) {
220                 ERROR ("Usage: Collectd::plugin_unregister (type, name)");
221                 return;
222         }
223
224         if (TYPE_DATASET == $type) {
225                 return plugin_unregister_data_set ($name);
226         }
227         elsif (defined $plugins[$type]) {
228                 delete $plugins[$type]->{$name};
229         }
230         else {
231                 ERROR ("Collectd::plugin_unregister: Invalid type.");
232                 return;
233         }
234 }
235
236 1;
237
238 # vim: set sw=4 ts=4 tw=78 noexpandtab :
239