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