1 /**
2 * collectd - src/rrdcached.c
3 * Copyright (C) 2008 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; only version 2 of the License is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Authors:
19 * Florian octo Forster <octo at verplant.org>
20 **/
22 #include "collectd.h"
23 #include "plugin.h"
24 #include "common.h"
25 #include "utils_rrdcreate.h"
27 #include <rrd_client.h>
29 /*
30 * Private variables
31 */
32 static const char *config_keys[] =
33 {
34 "DaemonAddress",
35 "DataDir",
36 "CreateFiles"
37 };
38 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
40 static char *datadir = NULL;
41 static char *daemon_address = NULL;
42 static int config_create_files = 1;
43 static rrdcreate_config_t rrdcreate_config =
44 {
45 /* stepsize = */ 0,
46 /* heartbeat = */ 0,
47 /* rrarows = */ 1200,
48 /* xff = */ 0.1,
50 /* timespans = */ NULL,
51 /* timespans_num = */ 0,
53 /* consolidation_functions = */ NULL,
54 /* consolidation_functions_num = */ 0
55 };
57 static int value_list_to_string (char *buffer, int buffer_len,
58 const data_set_t *ds, const value_list_t *vl)
59 {
60 int offset;
61 int status;
62 int i;
64 assert (0 == strcmp (ds->type, vl->type));
66 memset (buffer, '\0', buffer_len);
68 status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
69 if ((status < 1) || (status >= buffer_len))
70 return (-1);
71 offset = status;
73 for (i = 0; i < ds->ds_num; i++)
74 {
75 if ((ds->ds[i].type != DS_TYPE_COUNTER)
76 && (ds->ds[i].type != DS_TYPE_GAUGE))
77 return (-1);
79 if (ds->ds[i].type == DS_TYPE_COUNTER)
80 {
81 status = ssnprintf (buffer + offset, buffer_len - offset,
82 ",%llu", vl->values[i].counter);
83 }
84 else /* if (ds->ds[i].type == DS_TYPE_GAUGE) */
85 {
86 status = ssnprintf (buffer + offset, buffer_len - offset,
87 ",%lf", vl->values[i].gauge);
88 }
90 if ((status < 1) || (status >= (buffer_len - offset)))
91 return (-1);
93 offset += status;
94 } /* for ds->ds_num */
96 return (0);
97 } /* int value_list_to_string */
99 static int value_list_to_filename (char *buffer, int buffer_len,
100 const data_set_t *ds, const value_list_t *vl)
101 {
102 int offset = 0;
103 int status;
105 assert (0 == strcmp (ds->type, vl->type));
107 if (datadir != NULL)
108 {
109 status = ssnprintf (buffer + offset, buffer_len - offset,
110 "%s/", datadir);
111 if ((status < 1) || (status >= buffer_len - offset))
112 return (-1);
113 offset += status;
114 }
116 status = ssnprintf (buffer + offset, buffer_len - offset,
117 "%s/", vl->host);
118 if ((status < 1) || (status >= buffer_len - offset))
119 return (-1);
120 offset += status;
122 if (strlen (vl->plugin_instance) > 0)
123 status = ssnprintf (buffer + offset, buffer_len - offset,
124 "%s-%s/", vl->plugin, vl->plugin_instance);
125 else
126 status = ssnprintf (buffer + offset, buffer_len - offset,
127 "%s/", vl->plugin);
128 if ((status < 1) || (status >= buffer_len - offset))
129 return (-1);
130 offset += status;
132 if (strlen (vl->type_instance) > 0)
133 status = ssnprintf (buffer + offset, buffer_len - offset,
134 "%s-%s", vl->type, vl->type_instance);
135 else
136 status = ssnprintf (buffer + offset, buffer_len - offset,
137 "%s", vl->type);
138 if ((status < 1) || (status >= buffer_len - offset))
139 return (-1);
140 offset += status;
142 strncpy (buffer + offset, ".rrd", buffer_len - offset);
143 buffer[buffer_len - 1] = 0;
145 return (0);
146 } /* int value_list_to_filename */
148 static int rc_config (const char *key, const char *value)
149 {
150 if (strcasecmp ("DataDir", key) == 0)
151 {
152 if (datadir != NULL)
153 free (datadir);
154 datadir = strdup (value);
155 if (datadir != NULL)
156 {
157 int len = strlen (datadir);
158 while ((len > 0) && (datadir[len - 1] == '/'))
159 {
160 len--;
161 datadir[len] = '\0';
162 }
163 if (len <= 0)
164 {
165 free (datadir);
166 datadir = NULL;
167 }
168 }
169 }
170 else if (strcasecmp ("DaemonAddress", key) == 0)
171 {
172 sfree (daemon_address);
173 daemon_address = strdup (value);
174 if (daemon_address == NULL)
175 {
176 ERROR ("rrdcached plugin: strdup failed.");
177 return (1);
178 }
179 }
180 else if (strcasecmp ("CreateFiles", key) == 0)
181 {
182 if ((strcasecmp ("true", value) == 0)
183 || (strcasecmp ("yes", value) == 0)
184 || (strcasecmp ("on", value) == 0))
185 config_create_files = 1;
186 else
187 config_create_files = 0;
188 }
189 else
190 {
191 return (-1);
192 }
193 return (0);
194 } /* int rc_config */
196 static int rc_write (const data_set_t *ds, const value_list_t *vl)
197 {
198 char filename[512];
199 char values[512];
200 char *values_array[2];
201 int status;
203 if (daemon_address == NULL)
204 {
205 ERROR ("rrdcached plugin: daemon_address == NULL.");
206 plugin_unregister_write ("rrdcached");
207 return (-1);
208 }
210 if (strcmp (ds->type, vl->type) != 0)
211 {
212 ERROR ("rrdcached plugin: DS type does not match value list type");
213 return (-1);
214 }
216 if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
217 {
218 ERROR ("rrdcached plugin: value_list_to_filename failed.");
219 return (-1);
220 }
222 if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
223 {
224 ERROR ("rrdcached plugin: value_list_to_string failed.");
225 return (-1);
226 }
228 values_array[0] = values;
229 values_array[1] = NULL;
231 if (config_create_files != 0)
232 {
233 struct stat statbuf;
235 status = stat (filename, &statbuf);
236 if (status != 0)
237 {
238 if (errno != ENOENT)
239 {
240 char errbuf[1024];
241 ERROR ("rrdcached plugin: stat (%s) failed: %s",
242 filename, sstrerror (errno, errbuf, sizeof (errbuf)));
243 return (-1);
244 }
246 status = cu_rrd_create_file (filename, ds, vl, &rrdcreate_config);
247 if (status != 0)
248 {
249 ERROR ("rrdcached plugin: cu_rrd_create_file (%s) failed.",
250 filename);
251 return (-1);
252 }
253 }
254 }
256 status = rrdc_connect (daemon_address);
257 if (status != 0)
258 {
259 ERROR ("rrdcached plugin: rrdc_connect (%s) failed with status %i.",
260 daemon_address, status);
261 return (-1);
262 }
264 status = rrdc_update (filename, /* values_num = */ 1, (void *) values_array);
265 if (status != 0)
266 {
267 ERROR ("rrdcached plugin: rrdc_update (%s, [%s], 1) failed with "
268 "status %i.",
269 filename, values_array[0], status);
270 return (-1);
271 }
273 return (0);
274 } /* int rc_write */
276 static int rc_shutdown (void)
277 {
278 rrdc_disconnect ();
279 return (0);
280 } /* int rc_shutdown */
282 void module_register (void)
283 {
284 plugin_register_config ("rrdcached", rc_config,
285 config_keys, config_keys_num);
286 plugin_register_write ("rrdcached", rc_write);
287 plugin_register_shutdown ("rrdcached", rc_shutdown);
288 } /* void module_register */
290 /*
291 * vim: set sw=2 sts=2 et :
292 */