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 "data_provider.h"
27 #include "filesystem.h"
28 #include "oconfig.h"
29 #include "common.h"
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <limits.h>
35 #include <errno.h>
36 #include <assert.h>
38 #include <rrd.h>
40 struct dp_rrdtool_s
41 {
42 char *data_dir;
43 };
44 typedef struct dp_rrdtool_s dp_rrdtool_t;
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;
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;
62 sub_dir_len = strlen (sub_dir);
63 if (sub_dir_len < 5)
64 return (0);
66 /* Ignore files that don't end in ".rrd". */
67 if (strcasecmp (".rrd", sub_dir + (sub_dir_len - 4)) != 0)
68 return (0);
70 strncpy (type_copy, sub_dir, sizeof (type_copy));
71 type_copy[sub_dir_len - 4] = 0;
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 }
84 ident_set_type (data->ident, type_copy);
85 ident_set_type_instance (data->ident, type_inst);
87 return (data->callback (data->ident, data->user_data));
88 } /* }}} int scan_type_cb */
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;
96 dp_get_idents_data_t *data = ud;
97 char abs_dir[PATH_MAX + 1];
99 strncpy (plugin_copy, sub_dir, sizeof (plugin_copy));
100 plugin_copy[sizeof (plugin_copy) - 1] = 0;
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 }
113 ident_set_plugin (data->ident, plugin_copy);
114 ident_set_plugin_instance (data->ident, plugin_inst);
116 snprintf (abs_dir, sizeof (abs_dir), "%s/%s", base_dir, sub_dir);
117 abs_dir[sizeof (abs_dir) - 1] = 0;
119 return (fs_foreach_file (abs_dir, scan_type_cb, data));
120 } /* }}} int scan_host_cb */
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];
128 ident_set_host (data->ident, sub_dir);
130 snprintf (abs_dir, sizeof (abs_dir), "%s/%s", base_dir, sub_dir);
131 abs_dir[sizeof (abs_dir) - 1] = 0;
133 return (fs_foreach_dir (abs_dir, scan_plugin_cb, data));
134 } /* }}} int scan_host_cb */
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;
143 plugin_instance = ident_get_plugin_instance (ident);
144 if ((plugin_instance != NULL) && (plugin_instance[0] == 0))
145 plugin_instance = NULL;
147 type_instance = ident_get_type_instance (ident);
148 if ((type_instance != NULL) && (type_instance[0] == 0))
149 type_instance = NULL;
151 buffer[0] = 0;
153 strlcat (buffer, config->data_dir, buffer_size);
154 strlcat (buffer, "/", buffer_size);
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 }
172 strlcat (buffer, ".rrd", buffer_size);
174 return (0);
175 } /* }}} int ident_to_rrdfile */
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;
187 data.ident = ident_create ("", "", "", "", "");
188 if (data.ident == NULL)
189 return (ENOMEM);
190 data.callback = cb;
191 data.user_data = ud;
193 status = fs_foreach_dir (config->data_dir, scan_host_cb, &data);
195 ident_destroy (data.ident);
196 return (status);
197 } /* }}} int get_idents */
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;
206 char *rrd_argv[] = { "info", file, NULL };
207 int rrd_argc = (sizeof (rrd_argv) / sizeof (rrd_argv[0])) - 1;
209 rrd_info_t *info;
210 rrd_info_t *ptr;
212 memset (file, 0, sizeof (file));
213 status = ident_to_rrdfile (ident, config, file, sizeof (file));
214 if (status != 0)
215 return (status);
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 }
224 for (ptr = info; ptr != NULL; ptr = ptr->next)
225 {
226 size_t keylen;
227 size_t dslen;
228 char *ds;
230 if (ptr->key[0] != 'd')
231 continue;
233 if (strncmp ("ds[", ptr->key, strlen ("ds[")) != 0)
234 continue;
236 keylen = strlen (ptr->key);
237 if (keylen < strlen ("ds[?].index"))
238 continue;
240 dslen = keylen - strlen ("ds[].index");
241 assert (dslen >= 1);
243 if (strcmp ("].index", ptr->key + (strlen ("ds[") + dslen)) != 0)
244 continue;
246 ds = malloc (dslen + 1);
247 if (ds == NULL)
248 continue;
250 memcpy (ds, ptr->key + strlen ("ds["), dslen);
251 ds[dslen] = 0;
253 status = (*cb) (ident, ds, ud);
255 free (ds);
257 if (status != 0)
258 break;
259 }
261 rrd_info_free (info);
263 return (status);
264 } /* }}} int get_ident_ds_names */
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;
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;
283 unsigned long ds_index;
284 unsigned long data_index;
285 unsigned long data_length;
287 status = ident_to_rrdfile (ident, config, filename, sizeof (filename));
288 if (status != 0)
289 return (status);
291 rrd_start = (time_t) begin.tv_sec;
292 rrd_end = (time_t) end.tv_sec;
293 step = 0;
294 ds_count = 0;
295 ds_namv = NULL;
296 data = NULL;
298 status = rrd_fetch_r (filename, cf,
299 &rrd_start, &rrd_end,
300 &step, &ds_count, &ds_namv,
301 &data);
302 if (status != 0)
303 return (status);
305 #define BAIL_OUT(ret_status) do { \
306 unsigned long i; \
307 for (i = 0; i < ds_count; i++) \
308 free (ds_namv[i]); \
309 free (ds_namv); \
310 free (data); \
311 return (ret_status); \
312 } while (0)
314 for (ds_index = 0; ds_index < ds_count; ds_index++)
315 if (strcmp (ds_name, ds_namv[ds_index]) == 0)
316 break;
318 if (ds_index >= ds_count)
319 BAIL_OUT (ENOENT);
321 /* Number of data points returned. */
322 data_length = (rrd_end - rrd_start) / step;
324 for (data_index = 0; data_index < data_length; data_index++)
325 {
326 dp_data_point_t dp;
327 unsigned long index = (ds_count * data_index) + ds_index;
329 memset (&dp, 0, sizeof (dp));
330 dp.time.tv_sec = rrd_start + (data_index * step);
331 dp.time.tv_nsec = 0;
332 dp.value = (double) data[index];
334 status = (*cb) (ident, ds_name, &dp, ud);
335 if (status != 0)
336 BAIL_OUT (status);
337 }
339 BAIL_OUT (0);
340 #undef BAIL_OUT
341 } /* }}} int get_ident_data */
343 static int print_graph (void *priv,
344 graph_config_t *cfg, graph_instance_t *inst)
345 { /* {{{ */
346 priv = NULL;
347 cfg = NULL;
348 inst = NULL;
350 return (-1);
351 } /* }}} int print_graph */
353 int dp_rrdtool_config (const oconfig_item_t *ci)
354 { /* {{{ */
355 dp_rrdtool_t *conf;
357 data_provider_t dp =
358 {
359 get_idents,
360 get_ident_ds_names,
361 get_ident_data,
362 print_graph,
363 /* private_data = */ NULL
364 };
366 /* FIXME: Actuelly do config parsing here. */
367 ci = NULL; /* FIXME */
368 conf = malloc (sizeof (dp_rrdtool_t));
369 conf->data_dir = strdup ("/var/lib/collectd/rrd");
371 dp.private_data = conf;
373 data_provider_register ("rrdtool", &dp);
375 return (0);
376 } /* }}} int dp_rrdtool_config */
378 /* vim: set sw=2 sts=2 et fdm=marker : */