X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fplugin.c;h=4a25aaa773b3dd6ba4f381bb7fcfa3344cae34c7;hb=43b3f7d1ce3195c93c5357bcafb60421699aab7d;hp=67d61880ee963c5cc4fc2403d9da8c3c274f0a3b;hpb=682dfca77df320c3b6d014074ab230009abf9098;p=collectd.git diff --git a/src/plugin.c b/src/plugin.c index 67d61880..4a25aaa7 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -1,6 +1,6 @@ /** * collectd - src/plugin.c - * Copyright (C) 2005,2006 Florian octo Forster + * Copyright (C) 2005-2008 Florian octo Forster * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,9 +17,11 @@ * * Authors: * Florian octo Forster + * Sebastian Harl **/ #include "collectd.h" +#include "utils_complain.h" #include @@ -30,8 +32,10 @@ #include "common.h" #include "plugin.h" #include "configfile.h" +#include "utils_avltree.h" #include "utils_llist.h" #include "utils_cache.h" +#include "utils_threshold.h" /* * Private structures @@ -51,11 +55,13 @@ typedef struct read_func_s read_func_t; static llist_t *list_init; static llist_t *list_read; static llist_t *list_write; +static llist_t *list_flush; static llist_t *list_shutdown; -static llist_t *list_data_set; static llist_t *list_log; static llist_t *list_notification; +static c_avl_tree_t *data_sets; + static char *plugindir = NULL; static int read_loop = 1; @@ -78,6 +84,7 @@ static const char *plugin_get_dir (void) static int register_callback (llist_t **list, const char *name, void *callback) { llentry_t *le; + char *key; if ((*list == NULL) && ((*list = llist_create ()) == NULL)) @@ -86,9 +93,16 @@ static int register_callback (llist_t **list, const char *name, void *callback) le = llist_search (*list, name); if (le == NULL) { - le = llentry_create (name, callback); + key = strdup (name); + if (key == NULL) + return (-1); + + le = llentry_create (key, callback); if (le == NULL) + { + free (key); return (-1); + } llist_append (*list, le); } @@ -110,6 +124,7 @@ static int plugin_unregister (llist_t *list, const char *name) return (-1); llist_remove (list, e); + free (e->key); llentry_destroy (e); return (0); @@ -222,6 +237,7 @@ static void *plugin_read_thread (void *args) pthread_mutex_unlock (&read_lock); pthread_exit (NULL); + return ((void *) 0); } /* void *plugin_read_thread */ static void start_threads (int num) @@ -299,7 +315,7 @@ int plugin_load (const char *type) { DIR *dh; const char *dir; - char filename[BUFSIZE]; + char filename[BUFSIZE] = ""; char typename[BUFSIZE]; int typename_len; int ret; @@ -313,7 +329,8 @@ int plugin_load (const char *type) /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the * type when matching the filename */ - if (snprintf (typename, BUFSIZE, "%s.so", type) >= BUFSIZE) + if (ssnprintf (typename, sizeof (typename), + "%s.so", type) >= sizeof (typename)) { WARNING ("snprintf: truncated: `%s.so'", type); return (-1); @@ -333,7 +350,8 @@ int plugin_load (const char *type) if (strncasecmp (de->d_name, typename, typename_len)) continue; - if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE) + if (ssnprintf (filename, sizeof (filename), + "%s/%s", dir, de->d_name) >= sizeof (filename)) { WARNING ("snprintf: truncated: `%s/%s'", dir, de->d_name); continue; @@ -366,6 +384,9 @@ int plugin_load (const char *type) closedir (dh); + if (filename[0] == '\0') + fprintf (stderr, "Could not find plugin %s.\n", type); + return (ret); } @@ -421,6 +442,12 @@ int plugin_register_write (const char *name, return (register_callback (&list_write, name, (void *) callback)); } /* int plugin_register_write */ +int plugin_register_flush (const char *name, + int (*callback) (const int timeout, const char *identifier)) +{ + return (register_callback (&list_flush, name, (void *) callback)); +} /* int plugin_register_flush */ + int plugin_register_shutdown (char *name, int (*callback) (void)) { @@ -432,12 +459,18 @@ int plugin_register_data_set (const data_set_t *ds) data_set_t *ds_copy; int i; - if ((list_data_set != NULL) - && (llist_search (list_data_set, ds->type) != NULL)) + if ((data_sets != NULL) + && (c_avl_get (data_sets, ds->type, NULL) == 0)) { NOTICE ("Replacing DS `%s' with another version.", ds->type); plugin_unregister_data_set (ds->type); } + else if (data_sets == NULL) + { + data_sets = c_avl_create ((int (*) (const void *, const void *)) strcmp); + if (data_sets == NULL) + return (-1); + } ds_copy = (data_set_t *) malloc (sizeof (data_set_t)); if (ds_copy == NULL) @@ -455,7 +488,7 @@ int plugin_register_data_set (const data_set_t *ds) for (i = 0; i < ds->ds_num; i++) memcpy (ds_copy->ds + i, ds->ds + i, sizeof (data_source_t)); - return (register_callback (&list_data_set, ds->type, (void *) ds_copy)); + return (c_avl_insert (data_sets, (void *) ds_copy->type, (void *) ds_copy)); } /* int plugin_register_data_set */ int plugin_register_log (char *name, @@ -467,7 +500,7 @@ int plugin_register_log (char *name, int plugin_register_notification (const char *name, int (*callback) (const notification_t *notif)) { - return (register_callback (&list_log, name, (void *) callback)); + return (register_callback (&list_notification, name, (void *) callback)); } /* int plugin_register_log */ int plugin_unregister_config (const char *name) @@ -498,6 +531,7 @@ int plugin_unregister_read (const char *name) llist_remove (list_read, e); free (e->value); + free (e->key); llentry_destroy (e); return (0); @@ -508,6 +542,11 @@ int plugin_unregister_write (const char *name) return (plugin_unregister (list_write, name)); } +int plugin_unregister_flush (const char *name) +{ + return (plugin_unregister (list_flush, name)); +} + int plugin_unregister_shutdown (const char *name) { return (plugin_unregister (list_shutdown, name)); @@ -515,21 +554,14 @@ int plugin_unregister_shutdown (const char *name) int plugin_unregister_data_set (const char *name) { - llentry_t *e; data_set_t *ds; - if (list_data_set == NULL) + if (data_sets == NULL) return (-1); - e = llist_search (list_data_set, name); - - if (e == NULL) + if (c_avl_remove (data_sets, name, NULL, (void *) &ds) != 0) return (-1); - llist_remove (list_data_set, e); - ds = (data_set_t *) e->value; - llentry_destroy (e); - sfree (ds->ds); sfree (ds); @@ -588,11 +620,13 @@ void plugin_init_all (void) } } /* void plugin_init_all */ -void plugin_read_all (const int *loop) +void plugin_read_all (void) { llentry_t *le; read_func_t *rf; + uc_check_timeout (); + if (list_read == NULL) return; @@ -625,6 +659,66 @@ void plugin_read_all (const int *loop) pthread_mutex_unlock (&read_lock); } /* void plugin_read_all */ +int plugin_flush_one (int timeout, const char *name) +{ + int (*callback) (int); + llentry_t *le; + int status; + + if (list_flush == NULL) + return (-1); + + le = llist_search (list_flush, name); + if (le == NULL) + return (-1); + callback = (int (*) (int)) le->value; + + status = (*callback) (timeout); + + return (status); +} /* int plugin_flush_ont */ + +void plugin_flush_all (int timeout) +{ + int (*callback) (int); + llentry_t *le; + + if (list_flush == NULL) + return; + + le = llist_head (list_flush); + while (le != NULL) + { + callback = (int (*) (int)) le->value; + le = le->next; + + (*callback) (timeout); + } +} /* void plugin_flush_all */ + +int plugin_flush (const char *plugin, int timeout, const char *identifier) +{ + int (*callback) (int timeout, const char *identifier); + llentry_t *le; + + if (list_flush == NULL) + return (0); + + le = llist_head (list_flush); + while (le != NULL) + { + if ((plugin != NULL) + && (strcmp (plugin, le->key) != 0)) + continue; + + callback = (int (*) (int, const char *)) le->value; + le = le->next; + + (*callback) (timeout, identifier); + } + return (0); +} /* int plugin_flush */ + void plugin_shutdown_all (void) { int (*callback) (void); @@ -650,39 +744,63 @@ void plugin_shutdown_all (void) } } /* void plugin_shutdown_all */ -int plugin_dispatch_values (const char *name, value_list_t *vl) +int plugin_dispatch_values (value_list_t *vl) { + static c_complain_t no_write_complaint = C_COMPLAIN_INIT; + int (*callback) (const data_set_t *, const value_list_t *); data_set_t *ds; llentry_t *le; - if ((list_write == NULL) || (list_data_set == NULL)) + if ((vl == NULL) || (*vl->type == '\0')) { + ERROR ("plugin_dispatch_values: Invalid value list."); return (-1); + } - le = llist_search (list_data_set, name); - if (le == NULL) + if (list_write == NULL) + c_complain_once (LOG_WARNING, &no_write_complaint, + "plugin_dispatch_values: No write callback has been " + "registered. Please load at least one output plugin, " + "if you want the collected data to be stored."); + + if (data_sets == NULL) { - DEBUG ("No such dataset registered: %s", name); + ERROR ("plugin_dispatch_values: No data sets registered. " + "Could the types database be read? Check " + "your `TypesDB' setting!"); return (-1); } - ds = (data_set_t *) le->value; + if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0) + { + INFO ("plugin_dispatch_values: Dataset not found: %s", vl->type); + return (-1); + } - DEBUG ("plugin: plugin_dispatch_values: time = %u; interval = %i; " + DEBUG ("plugin_dispatch_values: time = %u; interval = %i; " "host = %s; " "plugin = %s; plugin_instance = %s; " "type = %s; type_instance = %s;", (unsigned int) vl->time, vl->interval, vl->host, vl->plugin, vl->plugin_instance, - ds->type, vl->type_instance); + vl->type, vl->type_instance); + +#if COLLECT_DEBUG + assert (0 == strcmp (ds->type, vl->type)); +#else + if (0 != strcmp (ds->type, vl->type)) + WARNING ("plugin_dispatch_values: (ds->type = %s) != (vl->type = %s)", + ds->type, vl->type); +#endif #if COLLECT_DEBUG assert (ds->ds_num == vl->values_len); #else if (ds->ds_num != vl->values_len) { - ERROR ("plugin: ds->type = %s: (ds->ds_num = %i) != " + ERROR ("plugin_dispatch_values: ds->type = %s: " + "(ds->ds_num = %i) != " "(vl->values_len = %i)", ds->type, ds->ds_num, vl->values_len); return (-1); @@ -692,10 +810,12 @@ int plugin_dispatch_values (const char *name, value_list_t *vl) escape_slashes (vl->host, sizeof (vl->host)); escape_slashes (vl->plugin, sizeof (vl->plugin)); escape_slashes (vl->plugin_instance, sizeof (vl->plugin_instance)); + escape_slashes (vl->type, sizeof (vl->type)); escape_slashes (vl->type_instance, sizeof (vl->type_instance)); /* Update the value cache */ uc_update (ds, vl); + ut_check_threshold (ds, vl); le = llist_head (list_write); while (le != NULL) @@ -715,6 +835,11 @@ int plugin_dispatch_notification (const notification_t *notif) llentry_t *le; /* Possible TODO: Add flap detection here */ + DEBUG ("plugin_dispatch_notification: severity = %i; message = %s; " + "time = %u; host = %s;", + notif->severity, notif->message, + (unsigned int) notif->time, notif->host); + /* Nobody cares for notifications */ if (list_notification == NULL) return (-1); @@ -762,66 +887,191 @@ void plugin_log (int level, const char *format, ...) } } /* void plugin_log */ -void plugin_complain (int level, complain_t *c, const char *format, ...) +const data_set_t *plugin_get_ds (const char *name) { - char message[512]; - va_list ap; + data_set_t *ds; - if (c->delay > 0) + if (c_avl_get (data_sets, name, (void *) &ds) != 0) { - c->delay--; - return; + DEBUG ("No such dataset registered: %s", name); + return (NULL); } - if (c->interval < interval_g) - c->interval = interval_g; - else - c->interval *= 2; - - if (c->interval > 86400) - c->interval = 86400; - - c->delay = c->interval / interval_g; - - va_start (ap, format); - vsnprintf (message, 512, format, ap); - message[511] = '\0'; - va_end (ap); + return (ds); +} /* data_set_t *plugin_get_ds */ - plugin_log (level, message); +static int plugin_notification_meta_add (notification_t *n, + const char *name, + enum notification_meta_type_e type, + const void *value) +{ + notification_meta_t *meta; + notification_meta_t *tail; + + if ((n == NULL) || (name == NULL) || (value == NULL)) + { + ERROR ("plugin_notification_meta_add: A pointer is NULL!"); + return (-1); + } + + meta = (notification_meta_t *) malloc (sizeof (notification_meta_t)); + if (meta == NULL) + { + ERROR ("plugin_notification_meta_add: malloc failed."); + return (-1); + } + memset (meta, 0, sizeof (notification_meta_t)); + + sstrncpy (meta->name, name, sizeof (meta->name)); + meta->type = type; + + switch (type) + { + case NM_TYPE_STRING: + { + meta->value_string = strdup ((const char *) value); + if (meta->value_string == NULL) + { + ERROR ("plugin_notification_meta_add: strdup failed."); + sfree (meta); + return (-1); + } + break; + } + case NM_TYPE_SIGNED_INT: + { + meta->value_signed_int = *((int64_t *) value); + break; + } + case NM_TYPE_UNSIGNED_INT: + { + meta->value_unsigned_int = *((uint64_t *) value); + break; + } + case NM_TYPE_DOUBLE: + { + meta->value_double = *((double *) value); + break; + } + case NM_TYPE_BOOLEAN: + { + meta->value_boolean = *((bool *) value); + break; + } + default: + { + ERROR ("plugin_notification_meta_add: Unknown type: %i", type); + sfree (meta); + return (-1); + } + } /* switch (type) */ + + meta->next = NULL; + tail = n->meta; + while ((tail != NULL) && (tail->next != NULL)) + tail = tail->next; + + if (tail == NULL) + n->meta = meta; + else + tail->next = meta; + + return (0); +} /* int plugin_notification_meta_add */ + +int plugin_notification_meta_add_string (notification_t *n, + const char *name, + const char *value) +{ + return (plugin_notification_meta_add (n, name, NM_TYPE_STRING, value)); } -void plugin_relief (int level, complain_t *c, const char *format, ...) +int plugin_notification_meta_add_signed_int (notification_t *n, + const char *name, + int64_t value) { - char message[512]; - va_list ap; - - if (c->interval == 0) - return; - - c->interval = 0; - - va_start (ap, format); - vsnprintf (message, 512, format, ap); - message[511] = '\0'; - va_end (ap); - - plugin_log (level, message); + return (plugin_notification_meta_add (n, name, NM_TYPE_SIGNED_INT, &value)); } -const data_set_t *plugin_get_ds (const char *name) +int plugin_notification_meta_add_unsigned_int (notification_t *n, + const char *name, + uint64_t value) { - data_set_t *ds; - llentry_t *le; + return (plugin_notification_meta_add (n, name, NM_TYPE_UNSIGNED_INT, &value)); +} - le = llist_search (list_data_set, name); - if (le == NULL) - { - DEBUG ("No such dataset registered: %s", name); - return (NULL); - } +int plugin_notification_meta_add_double (notification_t *n, + const char *name, + double value) +{ + return (plugin_notification_meta_add (n, name, NM_TYPE_DOUBLE, &value)); +} - ds = (data_set_t *) le->value; +int plugin_notification_meta_add_boolean (notification_t *n, + const char *name, + bool value) +{ + return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value)); +} - return (ds); -} /* data_set_t *plugin_get_ds */ +int plugin_notification_meta_copy (notification_t *dst, + const notification_t *src) +{ + notification_meta_t *meta; + + assert (dst != NULL); + assert (src != NULL); + assert (dst != src); + assert ((src->meta == NULL) || (src->meta != dst->meta)); + + for (meta = src->meta; meta != NULL; meta = meta->next) + { + if (meta->type == NM_TYPE_STRING) + plugin_notification_meta_add_string (dst, meta->name, + meta->value_string); + else if (meta->type == NM_TYPE_SIGNED_INT) + plugin_notification_meta_add_signed_int (dst, meta->name, + meta->value_signed_int); + else if (meta->type == NM_TYPE_UNSIGNED_INT) + plugin_notification_meta_add_unsigned_int (dst, meta->name, + meta->value_unsigned_int); + else if (meta->type == NM_TYPE_DOUBLE) + plugin_notification_meta_add_double (dst, meta->name, + meta->value_double); + else if (meta->type == NM_TYPE_BOOLEAN) + plugin_notification_meta_add_boolean (dst, meta->name, + meta->value_boolean); + } + + return (0); +} /* int plugin_notification_meta_copy */ + +int plugin_notification_meta_free (notification_t *n) +{ + notification_meta_t *this; + notification_meta_t *next; + + if (n == NULL) + { + ERROR ("plugin_notification_meta_free: n == NULL!"); + return (-1); + } + + this = n->meta; + n->meta = NULL; + while (this != NULL) + { + next = this->next; + + if (this->type == NM_TYPE_STRING) + { + free ((char *)this->value_string); + this->value_string = NULL; + } + sfree (this); + + this = next; + } + + return (0); +} /* int plugin_notification_meta_free */