7bf407abdb6240a624201e6e6dd3437ca02cf3d4
1 /**
2 * collectd - src/rrdtool.c
3 * Copyright (C) 2006 Florian octo Forster
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Authors:
20 * Florian octo Forster <octo at verplant.org>
21 **/
23 #include "collectd.h"
24 #include "plugin.h"
25 #include "common.h"
27 /*
28 * This weird macro cascade forces the glibc to define `NAN'. I don't know
29 * another way to solve this, so more intelligent solutions are welcome. -octo
30 */
31 #ifndef __USE_ISOC99
32 # define DISABLE__USE_ISOC99 1
33 # define __USE_ISOC99 1
34 #endif
35 #include <math.h>
36 #ifdef DISABLE__USE_ISOC99
37 # undef DISABLE__USE_ISOC99
38 # undef __USE_ISOC99
39 #endif
41 static int rra_timespans[] =
42 {
43 3600,
44 86400,
45 604800,
46 2678400,
47 31622400,
48 0
49 };
50 static int rra_timespans_num = 5;
52 static char *rra_types[] =
53 {
54 "AVERAGE",
55 "MIN",
56 "MAX",
57 NULL
58 };
59 static int rra_types_num = 3;
61 /* * * * * * * * * *
62 * WARNING: Magic *
63 * * * * * * * * * */
64 static int rra_get (char ***ret)
65 {
66 static char **rra_def = NULL;
67 static int rra_num = 0;
69 int rra_max = rra_timespans_num * rra_types_num;
71 int step;
72 int rows;
73 int span;
75 int cdp_num;
76 int cdp_len;
77 int i, j;
79 char buffer[64];
81 if ((rra_num != 0) && (rra_def != NULL))
82 {
83 *ret = rra_def;
84 return (rra_num);
85 }
87 if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
88 return (-1);
89 memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
91 step = atoi (COLLECTD_STEP);
92 rows = atoi (COLLECTD_ROWS);
94 if ((step <= 0) || (rows <= 0))
95 {
96 *ret = NULL;
97 return (-1);
98 }
100 cdp_len = 0;
101 for (i = 0; i < rra_timespans_num; i++)
102 {
103 span = rra_timespans[i];
105 if ((span / step) < rows)
106 continue;
108 if (cdp_len == 0)
109 cdp_len = 1;
110 else
111 cdp_len = (int) floor (((double) span) / ((double) (rows * step)));
113 cdp_num = (int) ceil (((double) span) / ((double) (cdp_len * step)));
115 for (j = 0; j < rra_types_num; j++)
116 {
117 if (rra_num >= rra_max)
118 break;
120 if (snprintf (buffer, sizeof(buffer), "RRA:%s:%3.1f:%u:%u",
121 rra_types[j], COLLECTD_XFF,
122 cdp_len, cdp_num) >= sizeof (buffer))
123 {
124 syslog (LOG_ERR, "rra_get: Buffer would have been truncated.");
125 continue;
126 }
128 rra_def[rra_num++] = sstrdup (buffer);
129 }
130 }
132 #if COLLECT_DEBUG
133 DBG ("rra_num = %i", rra_num);
134 for (i = 0; i < rra_num; i++)
135 DBG (" %s", rra_def[i]);
136 #endif
138 *ret = rra_def;
139 return (rra_num);
140 }
142 static void ds_free (int ds_num, char **ds_def)
143 {
144 int i;
146 for (i = 0; i < ds_num; i++)
147 if (ds_def[i] != NULL)
148 free (ds_def[i]);
149 free (ds_def);
150 }
152 static int ds_get (char ***ret, const data_set_t *ds)
153 {
154 char **ds_def;
155 int ds_num;
157 char min[32];
158 char max[32];
159 char buffer[128];
161 ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
162 if (ds_def == NULL)
163 {
164 syslog (LOG_ERR, "rrdtool plugin: malloc failed: %s",
165 strerror (errno));
166 return (-1);
167 }
168 memset (ds_def, '\0', ds->ds_num * sizeof (char *));
170 for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
171 {
172 data_source_t *d = ds->ds + ds_num;
173 char *type;
174 int status;
176 ds_def[ds_num] = NULL;
178 if (d->type == DS_TYPE_COUNTER)
179 type = "COUNTER";
180 else if (d->type == DS_TYPE_GAUGE)
181 type = "GAUGE";
182 else
183 {
184 syslog (LOG_ERR, "rrdtool plugin: Unknown DS type: %i",
185 d->type);
186 break;
187 }
189 if (d->min == NAN)
190 {
191 strcpy (min, "U");
192 }
193 else
194 {
195 snprintf (buffer, sizeof (min), "%lf", d->min);
196 min[sizeof (min) - 1] = '\0';
197 }
199 if (d->max == NAN)
200 {
201 strcpy (max, "U");
202 }
203 else
204 {
205 snprintf (buffer, sizeof (max), "%lf", d->max);
206 max[sizeof (max) - 1] = '\0';
207 }
209 status = snprintf (buffer, sizeof (buffer),
210 "DS:%s:%s:%s:%s:%s",
211 d->name, type, COLLECTD_HEARTBEAT,
212 min, max);
213 if ((status < 1) || (status >= sizeof (buffer)))
214 break;
216 ds_def[ds_num] = sstrdup (buffer);
217 ds_num++;
218 } /* for ds_num = 0 .. ds->ds_num */
220 if (ds_num != ds->ds_num)
221 {
222 ds_free (ds_num, ds_def);
223 return (-1);
224 }
226 *ret = ds_def;
227 return (ds_num);
228 }
230 static int rrd_create_file (char *filename, const data_set_t *ds)
231 {
232 char **argv;
233 int argc;
234 char **rra_def;
235 int rra_num;
236 char **ds_def;
237 int ds_num;
238 int i, j;
239 int status = 0;
241 if (check_create_dir (filename))
242 return (-1);
244 if ((rra_num = rra_get (&rra_def)) < 1)
245 {
246 syslog (LOG_ERR, "rrd_create_file failed: Could not calculate RRAs");
247 return (-1);
248 }
250 if ((ds_num = ds_get (&ds_def, ds)) < 1)
251 {
252 syslog (LOG_ERR, "rrd_create_file failed: Could not calculate DSes");
253 return (-1);
254 }
256 argc = ds_num + rra_num + 4;
258 if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
259 {
260 syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
261 return (-1);
262 }
264 argv[0] = "create";
265 argv[1] = filename;
266 argv[2] = "-s";
267 argv[3] = COLLECTD_STEP;
269 j = 4;
270 for (i = 0; i < ds_num; i++)
271 argv[j++] = ds_def[i];
272 for (i = 0; i < rra_num; i++)
273 argv[j++] = rra_def[i];
274 argv[j] = NULL;
276 optind = 0; /* bug in librrd? */
277 rrd_clear_error ();
278 if (rrd_create (argc, argv) == -1)
279 {
280 syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
281 status = -1;
282 }
284 free (argv);
285 ds_free (ds_num, ds_def);
287 return (status);
288 }
290 static int value_list_to_string (char *buffer, int buffer_len,
291 const data_set_t *ds, const value_list_t *vl)
292 {
293 int offset;
294 int status;
295 int i;
297 memset (buffer, '\0', sizeof (buffer_len));
298 buffer[0] = 'N';
299 offset = 1;
301 for (i = 0; i < ds->ds_num; i++)
302 {
303 if ((ds->ds[i].type != DS_TYPE_COUNTER)
304 && (ds->ds[i].type != DS_TYPE_GAUGE))
305 return (-1);
307 if (ds->ds[i].type == DS_TYPE_COUNTER)
308 status = snprintf (buffer + offset, buffer_len - offset,
309 ":%llu", vl->values[i].counter);
310 else
311 status = snprintf (buffer + offset, buffer_len - offset,
312 ":%lf", vl->values[i].gauge);
314 if ((status < 1) || (status >= (buffer_len - offset)))
315 return (-1);
317 offset += status;
318 } /* for ds->ds_num */
320 return (0);
321 } /* int value_list_to_string */
323 static int value_list_to_filename (char *buffer, int buffer_len,
324 const data_set_t *ds, const value_list_t *vl)
325 {
326 int offset = 0;
327 int status;
329 status = snprintf (buffer + offset, buffer_len - offset,
330 "%s/", vl->host);
331 if ((status < 1) || (status >= buffer_len - offset))
332 return (-1);
333 offset += status;
335 if (strlen (vl->plugin_instance) > 0)
336 status = snprintf (buffer + offset, buffer_len - offset,
337 "%s-%s/", vl->plugin, vl->plugin_instance);
338 else
339 status = snprintf (buffer + offset, buffer_len - offset,
340 "%s/", vl->plugin);
341 if ((status < 1) || (status >= buffer_len - offset))
342 return (-1);
343 offset += status;
345 if (strlen (vl->type_instance) > 0)
346 status = snprintf (buffer + offset, buffer_len - offset,
347 "%s-%s.rrd", ds->type, vl->type_instance);
348 else
349 status = snprintf (buffer + offset, buffer_len - offset,
350 "%s.rrd", ds->type);
351 if ((status < 1) || (status >= buffer_len - offset))
352 return (-1);
353 offset += status;
355 return (0);
356 } /* int value_list_to_filename */
358 static int rrd_write (const data_set_t *ds, const value_list_t *vl)
359 {
360 struct stat statbuf;
361 char filename[512];
362 char values[512];
363 char *argv[4] = { "update", filename, values, NULL };
365 if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
366 return (-1);
368 if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
369 return (-1);
371 if (stat (filename, &statbuf) == -1)
372 {
373 if (errno == ENOENT)
374 {
375 if (rrd_create_file (filename, ds))
376 return (-1);
377 }
378 else
379 {
380 syslog (LOG_ERR, "stat(%s) failed: %s",
381 filename, strerror (errno));
382 return (-1);
383 }
384 }
385 else if (!S_ISREG (statbuf.st_mode))
386 {
387 syslog (LOG_ERR, "stat(%s): Not a regular file!",
388 filename);
389 return (-1);
390 }
392 optind = 0; /* bug in librrd? */
393 rrd_clear_error ();
394 if (rrd_update (3, argv) == -1)
395 {
396 syslog (LOG_WARNING, "rrd_update failed: %s: %s",
397 filename, rrd_get_error ());
398 return (-1);
399 }
400 return (0);
401 } /* int rrd_update_file */
403 void module_register (void)
404 {
405 plugin_register_write ("rrdtool", rrd_write);
406 }