Add stub for config handling wrt. data providers.
[collection4.git] / src / dp_rrdtool.c
1 /**
2  * collection4 - data_provider.h
3  * Copyright (C) 2010  Florian octo Forster
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  * 
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors:
21  *   Florian octo Forster <ff at octo.it>
22  **/
23
24 #include "graph_types.h"
25 #include "graph_ident.h"
26 #include "graph_list.h"
27 #include "data_provider.h"
28 #include "filesystem.h"
29 #include "oconfig.h"
30 #include "common.h"
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <limits.h>
36 #include <errno.h>
37 #include <assert.h>
38
39 #include <rrd.h>
40
41 struct dp_rrdtool_s
42 {
43   char *data_dir;
44 };
45 typedef struct dp_rrdtool_s dp_rrdtool_t;
46
47 struct dp_get_idents_data_s
48 { /* {{{ */
49   graph_ident_t *ident;
50   dp_get_idents_callback callback;
51   void *user_data;
52 }; /* }}} */
53 typedef struct dp_get_idents_data_s dp_get_idents_data_t;
54
55 static int scan_type_cb (__attribute__((unused)) const char *base_dir,
56     const char *sub_dir, void *ud)
57 { /* {{{ */
58   dp_get_idents_data_t *data = ud;
59   size_t sub_dir_len;
60   char type_copy[1024];
61   char *type_inst;
62
63   sub_dir_len = strlen (sub_dir);
64   if (sub_dir_len < 5)
65     return (0);
66
67   /* Ignore files that don't end in ".rrd". */
68   if (strcasecmp (".rrd", sub_dir + (sub_dir_len - 4)) != 0)
69     return (0);
70
71   strncpy (type_copy, sub_dir, sizeof (type_copy));
72   type_copy[sub_dir_len - 4] = 0;
73
74   type_inst = strchr (type_copy, '-');
75   if (type_inst != NULL)
76   {
77     *type_inst = 0;
78     type_inst++;
79   }
80   else
81   {
82     type_inst = "";
83   }
84
85   ident_set_type (data->ident, type_copy);
86   ident_set_type_instance (data->ident, type_inst);
87
88   return (data->callback (data->ident, data->user_data));
89 } /* }}} int scan_type_cb */
90
91 static int scan_plugin_cb (const char *base_dir,
92     const char *sub_dir, void *ud)
93 { /* {{{ */
94   char plugin_copy[1024];
95   char *plugin_inst;
96
97   dp_get_idents_data_t *data = ud;
98   char abs_dir[PATH_MAX + 1];
99
100   strncpy (plugin_copy, sub_dir, sizeof (plugin_copy));
101   plugin_copy[sizeof (plugin_copy) - 1] = 0;
102
103   plugin_inst = strchr (plugin_copy, '-');
104   if (plugin_inst != NULL)
105   {
106     *plugin_inst = 0;
107     plugin_inst++;
108   }
109   else
110   {
111     plugin_inst = "";
112   }
113
114   ident_set_plugin (data->ident, plugin_copy);
115   ident_set_plugin_instance (data->ident, plugin_inst);
116
117   snprintf (abs_dir, sizeof (abs_dir), "%s/%s", base_dir, sub_dir);
118   abs_dir[sizeof (abs_dir) - 1] = 0;
119
120   return (fs_foreach_file (abs_dir, scan_type_cb, data));
121 } /* }}} int scan_host_cb */
122
123 static int scan_host_cb (const char *base_dir,
124     const char *sub_dir, void *ud)
125 { /* {{{ */
126   dp_get_idents_data_t *data = ud;
127   char abs_dir[PATH_MAX + 1];
128
129   ident_set_host (data->ident, sub_dir);
130
131   snprintf (abs_dir, sizeof (abs_dir), "%s/%s", base_dir, sub_dir);
132   abs_dir[sizeof (abs_dir) - 1] = 0;
133
134   return (fs_foreach_dir (abs_dir, scan_plugin_cb, data));
135 } /* }}} int scan_host_cb */
136
137 static int ident_to_rrdfile (const graph_ident_t *ident, /* {{{ */
138     dp_rrdtool_t *config,
139     char *buffer, size_t buffer_size)
140 {
141   const char *plugin_instance;
142   const char *type_instance;
143
144   plugin_instance = ident_get_plugin_instance (ident);
145   if ((plugin_instance != NULL) && (plugin_instance[0] == 0))
146     plugin_instance = NULL;
147
148   type_instance = ident_get_type_instance (ident);
149   if ((type_instance != NULL) && (type_instance[0] == 0))
150     type_instance = NULL;
151
152   buffer[0] = 0;
153
154   strlcat (buffer, config->data_dir, buffer_size);
155   strlcat (buffer, "/", buffer_size);
156
157   strlcat (buffer, ident_get_host (ident), buffer_size);
158   strlcat (buffer, "/", buffer_size);
159   strlcat (buffer, ident_get_plugin (ident), buffer_size);
160   if (plugin_instance != NULL)
161   {
162     strlcat (buffer, "-", buffer_size);
163     strlcat (buffer, plugin_instance, buffer_size);
164   }
165   strlcat (buffer, "/", buffer_size);
166   strlcat (buffer, ident_get_type (ident), buffer_size);
167   if (type_instance != NULL)
168   {
169     strlcat (buffer, "-", buffer_size);
170     strlcat (buffer, type_instance, buffer_size);
171   }
172
173   strlcat (buffer, ".rrd", buffer_size);
174
175   return (0);
176 } /* }}} int ident_to_rrdfile */
177
178 /*
179  * Callback functions
180  */
181 static int get_idents (void *priv,
182     dp_get_idents_callback cb, void *ud)
183 { /* {{{ */
184   dp_rrdtool_t *config = priv;
185   dp_get_idents_data_t data;
186   int status;
187
188   data.ident = ident_create ("", "", "", "", "");
189   if (data.ident == NULL)
190     return (ENOMEM);
191   data.callback = cb;
192   data.user_data = ud;
193
194   status = fs_foreach_dir (config->data_dir, scan_host_cb, &data);
195
196   ident_destroy (data.ident);
197   return (status);
198 } /* }}} int get_idents */
199
200 static int get_ident_ds_names (void *priv, graph_ident_t *ident,
201     dp_list_get_ident_ds_names_callback cb, void *ud)
202 { /* {{{ */
203   dp_rrdtool_t *config = priv;
204   char file[PATH_MAX + 1];
205   int status;
206
207   char *rrd_argv[] = { "info", file, NULL };
208   int rrd_argc = (sizeof (rrd_argv) / sizeof (rrd_argv[0])) - 1;
209
210   rrd_info_t *info;
211   rrd_info_t *ptr;
212
213   memset (file, 0, sizeof (file));
214   status = ident_to_rrdfile (ident, config, file, sizeof (file));
215   if (status != 0)
216     return (status);
217
218   info = rrd_info (rrd_argc, rrd_argv);
219   if (info == NULL)
220   {
221     printf ("%s: rrd_info (%s) failed.\n", __func__, file);
222     return (-1);
223   }
224
225   for (ptr = info; ptr != NULL; ptr = ptr->next)
226   {
227     size_t keylen;
228     size_t dslen;
229     char *ds;
230
231     if (ptr->key[0] != 'd')
232       continue;
233
234     if (strncmp ("ds[", ptr->key, strlen ("ds[")) != 0)
235       continue;
236
237     keylen = strlen (ptr->key);
238     if (keylen < strlen ("ds[?].index"))
239       continue;
240
241     dslen = keylen - strlen ("ds[].index");
242     assert (dslen >= 1);
243
244     if (strcmp ("].index", ptr->key + (strlen ("ds[") + dslen)) != 0)
245       continue;
246
247     ds = malloc (dslen + 1);
248     if (ds == NULL)
249       continue;
250
251     memcpy (ds, ptr->key + strlen ("ds["), dslen);
252     ds[dslen] = 0;
253
254     status = (*cb) (ident, ds, ud);
255
256     free (ds);
257
258     if (status != 0)
259       break;
260   }
261
262   rrd_info_free (info);
263
264   return (status);
265 } /* }}} int get_ident_ds_names */
266
267 static int get_ident_data (void *priv,
268     graph_ident_t *ident, const char *ds_name,
269     dp_time_t begin, dp_time_t end,
270     dp_get_ident_data_callback cb, void *ud)
271 { /* {{{ */
272   dp_rrdtool_t *config = priv;
273
274   char filename[PATH_MAX + 1];
275   const char *cf = "AVERAGE"; /* FIXME */
276   time_t rrd_start;
277   time_t rrd_end;
278   unsigned long step;
279   unsigned long ds_count;
280   char **ds_namv;
281   rrd_value_t *data;
282   int status;
283
284   unsigned long ds_index;
285   unsigned long data_index;
286   unsigned long data_length;
287
288   status = ident_to_rrdfile (ident, config, filename, sizeof (filename));
289   if (status != 0)
290     return (status);
291
292   rrd_start = (time_t) begin.tv_sec;
293   rrd_end = (time_t) end.tv_sec;
294   step = 0;
295   ds_count = 0;
296   ds_namv = NULL;
297   data = NULL;
298
299   status = rrd_fetch_r (filename, cf,
300       &rrd_start, &rrd_end,
301       &step, &ds_count, &ds_namv,
302       &data);
303   if (status != 0)
304     return (status);
305
306 #define BAIL_OUT(ret_status) do { \
307   unsigned long i;                \
308   for (i = 0; i < ds_count; i++)  \
309     free (ds_namv[i]);            \
310   free (ds_namv);                 \
311   free (data);                    \
312   return (ret_status);            \
313 } while (0)
314
315   for (ds_index = 0; ds_index < ds_count; ds_index++)
316     if (strcmp (ds_name, ds_namv[ds_index]) == 0)
317       break;
318
319   if (ds_index >= ds_count)
320     BAIL_OUT (ENOENT);
321
322   /* Number of data points returned. */
323   data_length = (rrd_end - rrd_start) / step;
324
325   for (data_index = 0; data_index < data_length; data_index++)
326   {
327     dp_data_point_t dp;
328     unsigned long index = (ds_count * data_index) + ds_index;
329
330     memset (&dp, 0, sizeof (dp));
331     dp.time.tv_sec = rrd_start + (data_index * step);
332     dp.time.tv_nsec = 0;
333     dp.value = (double) data[index];
334
335     status = (*cb) (ident, ds_name, &dp, ud);
336     if (status != 0)
337       BAIL_OUT (status);
338   }
339
340   BAIL_OUT (0);
341 #undef BAIL_OUT
342 } /* }}} int get_ident_data */
343
344 static int print_graph (void *priv,
345     graph_config_t *cfg, graph_instance_t *inst)
346 { /* {{{ */
347   priv = NULL;
348   cfg = NULL;
349   inst = NULL;
350
351   return (-1);
352 } /* }}} int print_graph */
353
354 int dp_rrdtool_config (const oconfig_item_t *ci)
355 { /* {{{ */
356   dp_rrdtool_t *conf;
357
358   data_provider_t dp =
359   {
360     get_idents,
361     get_ident_ds_names,
362     get_ident_data,
363     print_graph,
364     /* private_data = */ NULL
365   };
366
367   /* FIXME: Actuelly do config parsing here. */
368   ci = NULL; /* FIXME */
369   conf = malloc (sizeof (dp_rrdtool_t));
370   conf->data_dir = strdup ("/var/lib/collectd/rrd");
371
372   dp.private_data = conf;
373
374   gl_register_data_provider ("rrdtool", &dp);
375
376   return (0);
377 } /* }}} int dp_rrdtool_config */
378
379 /* vim: set sw=2 sts=2 et fdm=marker : */