484c604c84580245473188d3b359482cffce0425
1 /**
2 * collectd - src/dbi.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 "common.h"
24 #include "plugin.h"
25 #include "configfile.h"
27 #include <dbi/dbi.h>
29 /*
30 * Data types
31 */
32 struct cdbi_driver_option_s
33 {
34 char *key;
35 char *value;
36 };
37 typedef struct cdbi_driver_option_s cdbi_driver_option_t;
39 struct cdbi_query_s
40 {
41 char *name;
42 char *statement;
43 char *type;
44 char **instances;
45 size_t instances_num;
46 char **values;
47 size_t values_num;
48 };
49 typedef struct cdbi_query_s cdbi_query_t;
51 struct cdbi_database_s
52 {
53 char *name;
54 char *select_db;
56 char *driver;
57 cdbi_driver_option_t *driver_options;
58 size_t driver_options_num;
60 cdbi_query_t **queries;
61 size_t queries_num;
63 dbi_conn connection;
64 };
65 typedef struct cdbi_database_s cdbi_database_t;
67 /*
68 * Global variables
69 */
70 static cdbi_query_t **queries = NULL;
71 static size_t queries_num = 0;
72 static cdbi_database_t **databases = NULL;
73 static size_t databases_num = 0;
75 /*
76 * Functions
77 */
78 static const char *cdbi_strerror (dbi_conn conn, /* {{{ */
79 char *buffer, size_t buffer_size)
80 {
81 const char *msg;
82 int status;
84 if (conn == NULL)
85 {
86 sstrncpy (buffer, "connection is NULL", buffer_size);
87 return (buffer);
88 }
90 msg = NULL;
91 status = dbi_conn_error (conn, &msg);
92 if ((status >= 0) && (msg != NULL))
93 ssnprintf (buffer, buffer_size, "%s (status %i)", msg, status);
94 else
95 ssnprintf (buffer, buffer_size, "dbi_conn_error failed with status %i",
96 status);
98 return (buffer);
99 } /* }}} const char *cdbi_conn_error */
101 static int cdbi_result_get_field (dbi_result res, /* {{{ */
102 const char *name, int dst_type, value_t *ret_value)
103 {
104 value_t value;
105 unsigned int index;
106 unsigned short src_type;
107 dbi_conn connection;
109 index = dbi_result_get_field_idx (res, name);
110 if (index < 1)
111 {
112 ERROR ("dbi plugin: cdbi_result_get: No such column: %s.", name);
113 return (-1);
114 }
116 src_type = dbi_result_get_field_type_idx (res, index);
117 if (src_type == DBI_TYPE_ERROR)
118 {
119 ERROR ("dbi plugin: cdbi_result_get: "
120 "dbi_result_get_field_type_idx failed.");
121 return (-1);
122 }
124 if ((dst_type != DS_TYPE_COUNTER) && (dst_type != DS_TYPE_GAUGE))
125 {
126 ERROR ("dbi plugin: cdbi_result_get: Don't know how to handle "
127 "destination type %i.", dst_type);
128 return (-1);
129 }
131 if (src_type == DBI_TYPE_INTEGER)
132 {
133 if (dst_type == DS_TYPE_COUNTER)
134 value.counter = dbi_result_get_ulonglong_idx (res, index);
135 else
136 value.gauge = (gauge_t) dbi_result_get_longlong_idx (res, index);
137 }
138 else if (src_type == DBI_TYPE_DECIMAL)
139 {
140 value.gauge = dbi_result_get_double_idx (res, index);
141 if (dst_type == DS_TYPE_COUNTER)
142 value.counter = (counter_t) round (value.gauge);
143 }
144 else if (src_type == DBI_TYPE_STRING)
145 {
146 const char *string = dbi_result_get_string_idx (res, index);
147 char *endptr = NULL;
149 if (string == NULL)
150 value.gauge = NAN;
151 else if (dst_type == DS_TYPE_COUNTER)
152 value.counter = (counter_t) strtoll (string, &endptr, 0);
153 else
154 value.gauge = (gauge_t) strtod (string, &endptr);
156 if (string == endptr)
157 {
158 ERROR ("dbi plugin: cdbi_result_get: Can't parse string as number: %s.",
159 string);
160 return (-1);
161 }
162 }
163 else
164 {
165 ERROR ("dbi plugin: cdbi_result_get: Don't know how to handle "
166 "source type %hu.", src_type);
167 return (-1);
168 }
170 connection = dbi_result_get_conn (res);
171 if (dbi_conn_error_flag (connection) != 0)
172 {
173 char errbuf[1024];
174 ERROR ("dbi plugin: cdbi_result_get: dbi_result_get_*_idx failed: %s.",
175 cdbi_strerror (connection, errbuf, sizeof (errbuf)));
176 return (-1);
177 }
179 *ret_value = value;
180 return (0);
181 } /* }}} int cdbi_result_get_field */
183 static void cdbi_query_free (cdbi_query_t *q) /* {{{ */
184 {
185 size_t i;
187 if (q == NULL)
188 return;
190 sfree (q->name);
191 sfree (q->statement);
192 sfree (q->type);
194 for (i = 0; i < q->instances_num; i++)
195 sfree (q->instances[i]);
196 sfree (q->instances);
198 for (i = 0; i < q->values_num; i++)
199 sfree (q->values[i]);
200 sfree (q->values);
202 sfree (q);
203 } /* }}} void cdbi_query_free */
205 static void cdbi_database_free (cdbi_database_t *db) /* {{{ */
206 {
207 size_t i;
209 if (db == NULL)
210 return;
212 sfree (db->name);
213 sfree (db->driver);
215 for (i = 0; i < db->driver_options_num; i++)
216 {
217 sfree (db->driver_options[i].key);
218 sfree (db->driver_options[i].value);
219 }
220 sfree (db->driver_options);
222 sfree (db);
223 } /* }}} void cdbi_database_free */
225 static void cdbi_submit (cdbi_database_t *db, cdbi_query_t *q, /* {{{ */
226 char **instances, value_t *values)
227 {
228 value_list_t vl = VALUE_LIST_INIT;
230 vl.values = values;
231 vl.values_len = (int) q->values_num;
232 vl.time = time (NULL);
233 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
234 sstrncpy (vl.plugin, "dbi", sizeof (vl.plugin));
235 sstrncpy (vl.plugin_instance, db->name, sizeof (vl.type_instance));
236 sstrncpy (vl.type, q->type, sizeof (vl.type));
237 strjoin (vl.type_instance, sizeof (vl.type_instance),
238 instances, q->instances_num, "-");
239 vl.type_instance[sizeof (vl.type_instance) - 1] = 0;
241 plugin_dispatch_values (&vl);
242 } /* }}} void cdbi_submit */
244 /* Configuration handling functions {{{
245 *
246 * <Plugin dbi>
247 * <Query "plugin_instance0">
248 * Statement "SELECT name, value FROM table"
249 * Type "gauge"
250 * InstancesFrom "name"
251 * ValuesFrom "value"
252 * </Query>
253 *
254 * <Database "plugin_instance1">
255 * Driver "mysql"
256 * DriverOption "hostname" "localhost"
257 * ...
258 * Query "plugin_instance0"
259 * </Database>
260 * </Plugin>
261 */
263 static int cdbi_config_set_string (char **ret_string, /* {{{ */
264 oconfig_item_t *ci)
265 {
266 char *string;
268 if ((ci->values_num != 1)
269 || (ci->values[0].type != OCONFIG_TYPE_STRING))
270 {
271 WARNING ("dbi plugin: The `%s' config option "
272 "needs exactly one string argument.", ci->key);
273 return (-1);
274 }
276 string = strdup (ci->values[0].value.string);
277 if (string == NULL)
278 {
279 ERROR ("dbi plugin: strdup failed.");
280 return (-1);
281 }
283 if (*ret_string != NULL)
284 free (*ret_string);
285 *ret_string = string;
287 return (0);
288 } /* }}} int cdbi_config_set_string */
290 static int cdbi_config_add_string (char ***ret_array, /* {{{ */
291 size_t *ret_array_len, oconfig_item_t *ci)
292 {
293 char **array;
294 size_t array_len;
295 int i;
297 if (ci->values_num < 1)
298 {
299 WARNING ("dbi plugin: The `%s' config option "
300 "needs at least one argument.", ci->key);
301 return (-1);
302 }
304 for (i = 0; i < ci->values_num; i++)
305 {
306 if (ci->values[i].type != OCONFIG_TYPE_STRING)
307 {
308 WARNING ("dbi plugin: Argument %i to the `%s' option "
309 "is not a string.", i + 1, ci->key);
310 return (-1);
311 }
312 }
314 array_len = *ret_array_len;
315 array = (char **) realloc (*ret_array,
316 sizeof (char *) * (array_len + ci->values_num));
317 if (array == NULL)
318 {
319 ERROR ("dbi plugin: realloc failed.");
320 return (-1);
321 }
322 *ret_array = array;
324 for (i = 0; i < ci->values_num; i++)
325 {
326 array[array_len] = strdup (ci->values[i].value.string);
327 if (array[array_len] == NULL)
328 {
329 ERROR ("dbi plugin: strdup failed.");
330 *ret_array_len = array_len;
331 return (-1);
332 }
333 array_len++;
334 }
336 *ret_array_len = array_len;
337 return (0);
338 } /* }}} int cdbi_config_add_string */
340 static int cdbi_config_add_query (oconfig_item_t *ci) /* {{{ */
341 {
342 cdbi_query_t *q;
343 int status;
344 int i;
346 if ((ci->values_num != 1)
347 || (ci->values[0].type != OCONFIG_TYPE_STRING))
348 {
349 WARNING ("dbi plugin: The `Query' block "
350 "needs exactly one string argument.");
351 return (-1);
352 }
354 q = (cdbi_query_t *) malloc (sizeof (*q));
355 if (q == NULL)
356 {
357 ERROR ("dbi plugin: malloc failed.");
358 return (-1);
359 }
360 memset (q, 0, sizeof (*q));
362 status = cdbi_config_set_string (&q->name, ci);
363 if (status != 0)
364 {
365 sfree (q);
366 return (status);
367 }
369 /* Fill the `cdbi_query_t' structure.. */
370 for (i = 0; i < ci->children_num; i++)
371 {
372 oconfig_item_t *child = ci->children + i;
374 if (strcasecmp ("Statement", child->key) == 0)
375 status = cdbi_config_set_string (&q->statement, child);
376 else if (strcasecmp ("Type", child->key) == 0)
377 status = cdbi_config_set_string (&q->type, child);
378 else if (strcasecmp ("InstancesFrom", child->key) == 0)
379 status = cdbi_config_add_string (&q->instances, &q->instances_num, child);
380 else if (strcasecmp ("ValuesFrom", child->key) == 0)
381 status = cdbi_config_add_string (&q->values, &q->values_num, child);
382 else
383 {
384 WARNING ("dbi plugin: Option `%s' not allowed here.", child->key);
385 status = -1;
386 }
388 if (status != 0)
389 break;
390 }
392 /* Check that all necessary options have been given. */
393 while (status == 0)
394 {
395 if (q->statement == NULL)
396 {
397 WARNING ("dbi plugin: `Statement' not given for query `%s'", q->name);
398 status = -1;
399 }
400 if (q->type == NULL)
401 {
402 WARNING ("dbi plugin: `Type' not given for query `%s'", q->name);
403 status = -1;
404 }
405 if (q->instances == NULL)
406 {
407 WARNING ("dbi plugin: `InstancesFrom' not given for query `%s'", q->name);
408 status = -1;
409 }
410 if (q->values == NULL)
411 {
412 WARNING ("dbi plugin: `ValuesFrom' not given for query `%s'", q->name);
413 status = -1;
414 }
416 break;
417 } /* while (status == 0) */
419 /* If all went well, add this query to the list of queries within the
420 * database structure. */
421 if (status == 0)
422 {
423 cdbi_query_t **temp;
425 temp = (cdbi_query_t **) realloc (queries,
426 sizeof (*queries) * (queries_num + 1));
427 if (temp == NULL)
428 {
429 ERROR ("dbi plugin: realloc failed");
430 status = -1;
431 }
432 else
433 {
434 queries = temp;
435 queries[queries_num] = q;
436 queries_num++;
437 }
438 }
440 if (status != 0)
441 {
442 cdbi_query_free (q);
443 return (-1);
444 }
446 return (0);
447 } /* }}} int cdbi_config_add_query */
449 static int cdbi_config_add_database_driver_option (cdbi_database_t *db, /* {{{ */
450 oconfig_item_t *ci)
451 {
452 cdbi_driver_option_t *option;
454 if ((ci->values_num != 2)
455 || (ci->values[0].type != OCONFIG_TYPE_STRING)
456 || (ci->values[1].type != OCONFIG_TYPE_STRING))
457 {
458 WARNING ("dbi plugin: The `DriverOption' config option "
459 "needs exactly two string arguments.");
460 return (-1);
461 }
463 option = (cdbi_driver_option_t *) realloc (db->driver_options,
464 sizeof (*option) * (db->driver_options_num + 1));
465 if (option == NULL)
466 {
467 ERROR ("dbi plugin: realloc failed");
468 return (-1);
469 }
471 db->driver_options = option;
472 option = db->driver_options + db->driver_options_num;
474 option->key = strdup (ci->values[0].value.string);
475 if (option->key == NULL)
476 {
477 ERROR ("dbi plugin: strdup failed.");
478 return (-1);
479 }
481 option->value = strdup (ci->values[1].value.string);
482 if (option->value == NULL)
483 {
484 ERROR ("dbi plugin: strdup failed.");
485 sfree (option->key);
486 return (-1);
487 }
489 db->driver_options_num++;
490 return (0);
491 } /* }}} int cdbi_config_add_database_driver_option */
493 static int cdbi_config_add_database_query (cdbi_database_t *db, /* {{{ */
494 oconfig_item_t *ci)
495 {
496 cdbi_query_t *q;
497 cdbi_query_t **temp;
498 size_t i;
500 if ((ci->values_num != 1)
501 || (ci->values[0].type != OCONFIG_TYPE_STRING))
502 {
503 WARNING ("dbi plugin: The `Query' config option "
504 "needs exactly one string argument.");
505 return (-1);
506 }
508 q = NULL;
509 for (i = 0; i < queries_num; i++)
510 {
511 if (strcasecmp (queries[i]->name, ci->values[0].value.string) == 0)
512 {
513 q = queries[i];
514 break;
515 }
516 }
518 if (q == NULL)
519 {
520 WARNING ("dbi plugin: Database `%s': Unknown query `%s'. "
521 "Please make sure that the <Query \"%s\"> block comes before "
522 "the <Database \"%s\"> block.",
523 db->name, ci->values[0].value.string,
524 ci->values[0].value.string, db->name);
525 return (-1);
526 }
528 temp = (cdbi_query_t **) realloc (db->queries,
529 sizeof (*db->queries) * (db->queries_num + 1));
530 if (temp == NULL)
531 {
532 ERROR ("dbi plugin: realloc failed");
533 return (-1);
534 }
535 else
536 {
537 db->queries = temp;
538 db->queries[db->queries_num] = q;
539 db->queries_num++;
540 }
542 return (0);
543 } /* }}} int cdbi_config_add_database_query */
545 static int cdbi_config_add_database (oconfig_item_t *ci) /* {{{ */
546 {
547 cdbi_database_t *db;
548 int status;
549 int i;
551 if ((ci->values_num != 1)
552 || (ci->values[0].type != OCONFIG_TYPE_STRING))
553 {
554 WARNING ("dbi plugin: The `Database' block "
555 "needs exactly one string argument.");
556 return (-1);
557 }
559 db = (cdbi_database_t *) malloc (sizeof (*db));
560 if (db == NULL)
561 {
562 ERROR ("dbi plugin: malloc failed.");
563 return (-1);
564 }
565 memset (db, 0, sizeof (*db));
567 status = cdbi_config_set_string (&db->name, ci);
568 if (status != 0)
569 {
570 sfree (db);
571 return (status);
572 }
574 /* Fill the `cdbi_database_t' structure.. */
575 for (i = 0; i < ci->children_num; i++)
576 {
577 oconfig_item_t *child = ci->children + i;
579 if (strcasecmp ("Driver", child->key) == 0)
580 status = cdbi_config_set_string (&db->driver, child);
581 else if (strcasecmp ("DriverOption", child->key) == 0)
582 status = cdbi_config_add_database_driver_option (db, child);
583 else if (strcasecmp ("SelectDB", child->key) == 0)
584 status = cdbi_config_set_string (&db->select_db, child);
585 else if (strcasecmp ("Query", child->key) == 0)
586 status = cdbi_config_add_database_query (db, child);
587 else
588 {
589 WARNING ("dbi plugin: Option `%s' not allowed here.", child->key);
590 status = -1;
591 }
593 if (status != 0)
594 break;
595 }
597 /* Check that all necessary options have been given. */
598 while (status == 0)
599 {
600 if (db->driver == NULL)
601 {
602 WARNING ("dbi plugin: `Driver' not given for database `%s'", db->name);
603 status = -1;
604 }
605 if (db->driver_options_num == 0)
606 {
607 WARNING ("dbi plugin: No `DriverOption' given for database `%s'. "
608 "This will likely not work.", db->name);
609 }
611 break;
612 } /* while (status == 0) */
614 /* If all went well, add this database to the global list of databases. */
615 if (status == 0)
616 {
617 cdbi_database_t **temp;
619 temp = (cdbi_database_t **) realloc (databases,
620 sizeof (*databases) * (databases_num + 1));
621 if (temp == NULL)
622 {
623 ERROR ("dbi plugin: realloc failed");
624 status = -1;
625 }
626 else
627 {
628 databases = temp;
629 databases[databases_num] = db;
630 databases_num++;
631 }
632 }
634 if (status != 0)
635 {
636 cdbi_database_free (db);
637 return (-1);
638 }
640 return (0);
641 } /* }}} int cdbi_config_add_database */
643 static int cdbi_config (oconfig_item_t *ci) /* {{{ */
644 {
645 int i;
647 for (i = 0; i < ci->children_num; i++)
648 {
649 oconfig_item_t *child = ci->children + i;
650 if (strcasecmp ("Query", child->key) == 0)
651 cdbi_config_add_query (child);
652 else if (strcasecmp ("Database", child->key) == 0)
653 cdbi_config_add_database (child);
654 else
655 {
656 WARNING ("snmp plugin: Ignoring unknown config option `%s'.", child->key);
657 }
658 } /* for (ci->children) */
660 return (0);
661 } /* }}} int cdbi_config */
663 /* }}} End of configuration handling functions */
665 static int cdbi_init (void) /* {{{ */
666 {
667 static int did_init = 0;
668 int status;
670 if (did_init != 0)
671 return (0);
673 if (queries_num == 0)
674 {
675 ERROR ("dbi plugin: No <Query> blocks have been found. Without them, "
676 "this plugin can't do anything useful, so we will returns an error.");
677 return (-1);
678 }
680 if (databases_num == 0)
681 {
682 ERROR ("dbi plugin: No <Database> blocks have been found. Without them, "
683 "this plugin can't do anything useful, so we will returns an error.");
684 return (-1);
685 }
687 status = dbi_initialize (NULL);
688 if (status < 0)
689 {
690 ERROR ("dbi plugin: cdbi_init: dbi_initialize failed with status %i.",
691 status);
692 return (-1);
693 }
694 else if (status == 0)
695 {
696 ERROR ("dbi plugin: `dbi_initialize' could not load any drivers. Please "
697 "install at least one `DBD' or check your installation.");
698 return (-1);
699 }
700 DEBUG ("dbi plugin: cdbi_init: dbi_initialize reports %i driver%s.",
701 status, (status == 1) ? "" : "s");
703 return (0);
704 } /* }}} int cdbi_init */
706 static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */
707 cdbi_query_t *q)
708 {
709 dbi_result res;
710 char **instances;
711 value_t *values;
712 const data_set_t *ds;
713 size_t i;
714 int status;
716 res = NULL;
717 instances = NULL;
718 values = NULL;
720 /* Macro that cleans up dynamically allocated memory and returns the
721 * specified status. */
722 #define BAIL_OUT(status) \
723 if (res != NULL) { dbi_result_free (res); res = NULL; } \
724 if (instances != NULL) { sfree (instances[0]); sfree (instances); } \
725 sfree (values); \
726 return (status)
728 ds = plugin_get_ds (q->type);
729 if (ds == NULL)
730 {
731 ERROR ("dbi plugin: cdbi_read_database_query: Query `%s': Type `%s' is not "
732 "known by the daemon. See types.db(5) for details.",
733 q->name, q->type);
734 BAIL_OUT (-1);
735 }
737 if (((size_t) ds->ds_num) != q->values_num)
738 {
739 ERROR ("dbi plugin: cdbi_read_database_query: Query `%s': The type `%s' "
740 "requires exactly %i value%s, but the configuration specifies %zu.",
741 q->name, q->type,
742 ds->ds_num, (ds->ds_num == 1) ? "" : "s",
743 q->values_num);
744 BAIL_OUT (-1);
745 }
747 /* Allocate `instances' and `values' {{{ */
748 instances = (char **) malloc (sizeof (*instances) * q->instances_num);
749 if (instances == NULL)
750 {
751 ERROR ("dbi plugin: malloc failed.");
752 BAIL_OUT (-1);
753 }
755 instances[0] = (char *) malloc (q->instances_num * DATA_MAX_NAME_LEN);
756 if (instances[0] == NULL)
757 {
758 ERROR ("dbi plugin: malloc failed.");
759 BAIL_OUT (-1);
760 }
761 for (i = 1; i < q->instances_num; i++)
762 instances[i] = instances[i - 1] + DATA_MAX_NAME_LEN;
764 values = (value_t *) malloc (sizeof (*values) * q->values_num);
765 if (values == NULL)
766 {
767 ERROR ("dbi plugin: malloc failed.");
768 BAIL_OUT (-1);
769 }
770 /* }}} */
772 res = dbi_conn_query (db->connection, q->statement);
773 if (res == NULL)
774 {
775 char errbuf[1024];
776 ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
777 "dbi_conn_query failed: %s",
778 db->name, q->name,
779 cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
780 BAIL_OUT (-1);
781 }
783 status = dbi_result_first_row (res);
784 if (status != 1)
785 {
786 char errbuf[1024];
787 ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
788 "dbi_result_first_row failed: %s. Maybe the statement didn't "
789 "return any rows?",
790 db->name, q->name,
791 cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
792 BAIL_OUT (-1);
793 }
795 while (42)
796 {
797 /* Get instance names and values from the result: */
798 for (i = 0; i < q->instances_num; i++) /* {{{ */
799 {
800 const char *inst;
802 inst = dbi_result_get_string (res, q->instances[i]);
803 if (dbi_conn_error_flag (db->connection) != 0)
804 {
805 char errbuf[1024];
806 ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
807 "dbi_result_get_string (%s) failed: %s",
808 db->name, q->name, q->instances[i],
809 cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
810 BAIL_OUT (-1);
811 }
813 sstrncpy (instances[i], (inst == NULL) ? "" : inst, DATA_MAX_NAME_LEN);
814 DEBUG ("dbi plugin: cdbi_read_database_query (%s, %s): "
815 "instances[%zu] = %s;",
816 db->name, q->name, i, instances[i]);
817 } /* }}} for (i = 0; i < q->instances_num; i++) */
819 for (i = 0; i < q->values_num; i++) /* {{{ */
820 {
821 status = cdbi_result_get_field (res, q->values[i], ds->ds[i].type,
822 values + i);
823 if (status != 0)
824 {
825 BAIL_OUT (-1);
826 }
828 if (ds->ds[i].type == DS_TYPE_COUNTER)
829 {
830 DEBUG ("dbi plugin: cdbi_read_database_query (%s, %s): values[%zu] = %llu;",
831 db->name, q->name, i, values[i].counter);
832 }
833 else
834 {
835 DEBUG ("dbi plugin: cdbi_read_database_query (%s, %s): values[%zu] = %g;",
836 db->name, q->name, i, values[i].gauge);
837 }
838 } /* }}} for (i = 0; i < q->values_num; i++) */
840 /* Dispatch this row to the daemon. */
841 cdbi_submit (db, q, instances, values);
843 /* Get the next row from the database. */
844 status = dbi_result_next_row (res);
845 if (status != 1)
846 {
847 if (dbi_conn_error_flag (db->connection) != 0)
848 {
849 char errbuf[1024];
850 WARNING ("dbi plugin: cdbi_read_database_query (%s, %s): "
851 "dbi_result_next_row failed: %s.",
852 db->name, q->name,
853 cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
854 }
855 break;
856 }
857 } /* while (42) */
859 BAIL_OUT (0);
860 #undef BAIL_OUT
861 } /* }}} int cdbi_read_database_query */
863 static int cdbi_connect_database (cdbi_database_t *db) /* {{{ */
864 {
865 dbi_driver driver;
866 dbi_conn connection;
867 size_t i;
868 int status;
870 if (db->connection != NULL)
871 {
872 status = dbi_conn_ping (db->connection);
873 if (status != 0) /* connection is alive */
874 return (0);
876 dbi_conn_close (db->connection);
877 db->connection = NULL;
878 }
880 driver = dbi_driver_open (db->driver);
881 if (driver == NULL)
882 {
883 ERROR ("dbi plugin: cdbi_connect_database: dbi_driver_open (%s) failed.",
884 db->driver);
885 INFO ("dbi plugin: Maybe the driver isn't installed? "
886 "Known drivers are:");
887 for (driver = dbi_driver_list (NULL);
888 driver != NULL;
889 driver = dbi_driver_list (driver))
890 {
891 INFO ("dbi plugin: * %s", dbi_driver_get_name (driver));
892 }
893 return (-1);
894 }
896 connection = dbi_conn_open (driver);
897 if (connection == NULL)
898 {
899 ERROR ("dbi plugin: cdbi_connect_database: dbi_conn_open (%s) failed.",
900 db->driver);
901 return (-1);
902 }
904 /* Set all the driver options. Because this is a very very very generic
905 * interface, the error handling is kind of long. If an invalid option is
906 * encountered, it will get a list of options understood by the driver and
907 * report that as `INFO'. This way, users hopefully don't have too much
908 * trouble finding out how to configure the plugin correctly.. */
909 for (i = 0; i < db->driver_options_num; i++)
910 {
911 DEBUG ("dbi plugin: cdbi_connect_database (%s): "
912 "key = %s; value = %s;",
913 db->name,
914 db->driver_options[i].key,
915 db->driver_options[i].value);
917 status = dbi_conn_set_option (connection,
918 db->driver_options[i].key, db->driver_options[i].value);
919 if (status != 0)
920 {
921 char errbuf[1024];
922 const char *opt;
924 ERROR ("dbi plugin: cdbi_connect_database (%s): "
925 "dbi_conn_set_option (%s, %s) failed: %s.",
926 db->name,
927 db->driver_options[i].key, db->driver_options[i].value,
928 cdbi_strerror (connection, errbuf, sizeof (errbuf)));
930 INFO ("dbi plugin: This is a list of all options understood "
931 "by the `%s' driver:", db->driver);
932 for (opt = dbi_conn_get_option_list (connection, NULL);
933 opt != NULL;
934 opt = dbi_conn_get_option_list (connection, opt))
935 {
936 INFO ("dbi plugin: * %s", opt);
937 }
939 dbi_conn_close (connection);
940 return (-1);
941 }
942 } /* for (i = 0; i < db->driver_options_num; i++) */
944 status = dbi_conn_connect (connection);
945 if (status != 0)
946 {
947 char errbuf[1024];
948 ERROR ("dbi plugin: cdbi_connect_database (%s): "
949 "dbi_conn_connect failed: %s",
950 db->name, cdbi_strerror (connection, errbuf, sizeof (errbuf)));
951 dbi_conn_close (connection);
952 return (-1);
953 }
955 if (db->select_db != NULL)
956 {
957 status = dbi_conn_select_db (connection, db->select_db);
958 if (status != 0)
959 {
960 char errbuf[1024];
961 WARNING ("dbi plugin: cdbi_connect_database (%s): "
962 "dbi_conn_select_db (%s) failed: %s. Check the `SelectDB' option.",
963 db->name, db->select_db,
964 cdbi_strerror (connection, errbuf, sizeof (errbuf)));
965 dbi_conn_close (connection);
966 return (-1);
967 }
968 }
970 db->connection = connection;
971 return (0);
972 } /* }}} int cdbi_connect_database */
974 static int cdbi_read_database (cdbi_database_t *db) /* {{{ */
975 {
976 size_t i;
977 int success;
978 int status;
980 status = cdbi_connect_database (db);
981 if (status != 0)
982 return (status);
983 assert (db->connection != NULL);
985 success = 0;
986 for (i = 0; i < db->queries_num; i++)
987 {
988 status = cdbi_read_database_query (db, db->queries[i]);
989 if (status == 0)
990 success++;
991 }
993 if (success == 0)
994 {
995 ERROR ("dbi plugin: All queries failed for database `%s'.", db->name);
996 return (-1);
997 }
999 return (0);
1000 } /* }}} int cdbi_read_database */
1002 static int cdbi_read (void) /* {{{ */
1003 {
1004 size_t i;
1005 int success = 0;
1006 int status;
1008 for (i = 0; i < databases_num; i++)
1009 {
1010 status = cdbi_read_database (databases[i]);
1011 if (status == 0)
1012 success++;
1013 }
1015 if (success == 0)
1016 {
1017 ERROR ("dbi plugin: No database could be read. Will return an error so "
1018 "the plugin will be delayed.");
1019 return (-1);
1020 }
1022 return (0);
1023 } /* }}} int cdbi_read */
1025 static int cdbi_shutdown (void) /* {{{ */
1026 {
1027 size_t i;
1029 for (i = 0; i < databases_num; i++)
1030 {
1031 if (databases[i]->connection != NULL)
1032 {
1033 dbi_conn_close (databases[i]->connection);
1034 databases[i]->connection = NULL;
1035 }
1036 cdbi_database_free (databases[i]);
1037 }
1038 sfree (databases);
1039 databases_num = 0;
1041 for (i = 0; i < queries_num; i++)
1042 cdbi_query_free (queries[i]);
1043 sfree (queries);
1044 queries_num = 0;
1046 return (0);
1047 } /* }}} int cdbi_shutdown */
1049 void module_register (void) /* {{{ */
1050 {
1051 plugin_register_complex_config ("dbi", cdbi_config);
1052 plugin_register_init ("dbi", cdbi_init);
1053 plugin_register_read ("dbi", cdbi_read);
1054 plugin_register_shutdown ("dbi", cdbi_shutdown);
1055 } /* }}} void module_register */
1057 /*
1058 * vim: shiftwidth=2 softtabstop=2 et fdm=marker
1059 */