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 **/
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"
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <limits.h>
36 #include <errno.h>
37 #include <assert.h>
39 #include <rrd.h>
41 struct dp_rrdtool_s
42 {
43 char *data_dir;
44 };
45 typedef struct dp_rrdtool_s dp_rrdtool_t;
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;
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;
63 sub_dir_len = strlen (sub_dir);
64 if (sub_dir_len < 5)
65 return (0);
67 /* Ignore files that don't end in ".rrd". */
68 if (strcasecmp (".rrd", sub_dir + (sub_dir_len - 4)) != 0)
69 return (0);
71 strncpy (type_copy, sub_dir, sizeof (type_copy));
72 type_copy[sub_dir_len - 4] = 0;
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 }
85 ident_set_type (data->ident, type_copy);
86 ident_set_type_instance (data->ident, type_inst);
88 return (data->callback (data->ident, data->user_data));
89 } /* }}} int scan_type_cb */
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;
97 dp_get_idents_data_t *data = ud;
98 char abs_dir[PATH_MAX + 1];
100 strncpy (plugin_copy, sub_dir, sizeof (plugin_copy));
101 plugin_copy[sizeof (plugin_copy) - 1] = 0;
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 }
114 ident_set_plugin (data->ident, plugin_copy);
115 ident_set_plugin_instance (data->ident, plugin_inst);
117 snprintf (abs_dir, sizeof (abs_dir), "%s/%s", base_dir, sub_dir);
118 abs_dir[sizeof (abs_dir) - 1] = 0;
120 return (fs_foreach_file (abs_dir, scan_type_cb, data));
121 } /* }}} int scan_host_cb */
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];
129 ident_set_host (data->ident, sub_dir);
131 snprintf (abs_dir, sizeof (abs_dir), "%s/%s", base_dir, sub_dir);
132 abs_dir[sizeof (abs_dir) - 1] = 0;
134 return (fs_foreach_dir (abs_dir, scan_plugin_cb, data));
135 } /* }}} int scan_host_cb */
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;
144 plugin_instance = ident_get_plugin_instance (ident);
145 if ((plugin_instance != NULL) && (plugin_instance[0] == 0))
146 plugin_instance = NULL;
148 type_instance = ident_get_type_instance (ident);
149 if ((type_instance != NULL) && (type_instance[0] == 0))
150 type_instance = NULL;
152 buffer[0] = 0;
154 strlcat (buffer, config->data_dir, buffer_size);
155 strlcat (buffer, "/", buffer_size);
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 }
173 strlcat (buffer, ".rrd", buffer_size);
175 return (0);
176 } /* }}} int ident_to_rrdfile */
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;
188 data.ident = ident_create ("", "", "", "", "");
189 if (data.ident == NULL)
190 return (ENOMEM);
191 data.callback = cb;
192 data.user_data = ud;
194 status = fs_foreach_dir (config->data_dir, scan_host_cb, &data);
196 ident_destroy (data.ident);
197 return (status);
198 } /* }}} int get_idents */
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;
207 char *rrd_argv[] = { "info", file, NULL };
208 int rrd_argc = (sizeof (rrd_argv) / sizeof (rrd_argv[0])) - 1;
210 rrd_info_t *info;
211 rrd_info_t *ptr;
213 memset (file, 0, sizeof (file));
214 status = ident_to_rrdfile (ident, config, file, sizeof (file));
215 if (status != 0)
216 return (status);
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 }
225 for (ptr = info; ptr != NULL; ptr = ptr->next)
226 {
227 size_t keylen;
228 size_t dslen;
229 char *ds;
231 if (ptr->key[0] != 'd')
232 continue;
234 if (strncmp ("ds[", ptr->key, strlen ("ds[")) != 0)
235 continue;
237 keylen = strlen (ptr->key);
238 if (keylen < strlen ("ds[?].index"))
239 continue;
241 dslen = keylen - strlen ("ds[].index");
242 assert (dslen >= 1);
244 if (strcmp ("].index", ptr->key + (strlen ("ds[") + dslen)) != 0)
245 continue;
247 ds = malloc (dslen + 1);
248 if (ds == NULL)
249 continue;
251 memcpy (ds, ptr->key + strlen ("ds["), dslen);
252 ds[dslen] = 0;
254 status = (*cb) (ident, ds, ud);
256 free (ds);
258 if (status != 0)
259 break;
260 }
262 rrd_info_free (info);
264 return (status);
265 } /* }}} int get_ident_ds_names */
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;
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;
284 unsigned long ds_index;
285 unsigned long data_index;
286 unsigned long data_length;
288 status = ident_to_rrdfile (ident, config, filename, sizeof (filename));
289 if (status != 0)
290 return (status);
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;
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);
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)
315 for (ds_index = 0; ds_index < ds_count; ds_index++)
316 if (strcmp (ds_name, ds_namv[ds_index]) == 0)
317 break;
319 if (ds_index >= ds_count)
320 BAIL_OUT (ENOENT);
322 /* Number of data points returned. */
323 data_length = (rrd_end - rrd_start) / step;
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;
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];
335 status = (*cb) (ident, ds_name, &dp, ud);
336 if (status != 0)
337 BAIL_OUT (status);
338 }
340 BAIL_OUT (0);
341 #undef BAIL_OUT
342 } /* }}} int get_ident_data */
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;
351 return (-1);
352 } /* }}} int print_graph */
354 int dp_rrdtool_config (oconfig_item_t *ci)
355 { /* {{{ */
356 dp_rrdtool_t *conf;
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 };
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");
372 dp.private_data = conf;
374 gl_register_data_provider ("rrdtool", &dp);
376 return (0);
377 } /* }}} int dp_rrdtool_config */
379 /* vim: set sw=2 sts=2 et fdm=marker : */