X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fplugin.c;h=a749d1e07b18502127406469471cd728fe9121bd;hb=61fba41289decabc1a18c855fcd462fece9ab983;hp=3682fa5bb307cad9a2793aa290fbb192d5b59db6;hpb=96382507c3296a35399f6b3c258ae2a47761bf06;p=collectd.git diff --git a/src/plugin.c b/src/plugin.c index 3682fa5b..a749d1e0 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -1,6 +1,6 @@ /** * collectd - src/plugin.c - * Copyright (C) 2005-2009 Florian octo Forster + * Copyright (C) 2005-2011 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 @@ -16,7 +16,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: - * Florian octo Forster + * Florian octo Forster * Sebastian Harl **/ @@ -36,7 +36,6 @@ #include "utils_llist.h" #include "utils_heap.h" #include "utils_cache.h" -#include "utils_threshold.h" #include "filter_chain.h" /* @@ -74,6 +73,7 @@ typedef struct read_func_s read_func_t; static llist_t *list_init; static llist_t *list_write; static llist_t *list_flush; +static llist_t *list_missing; static llist_t *list_shutdown; static llist_t *list_log; static llist_t *list_notification; @@ -280,8 +280,6 @@ static int plugin_load_file (char *file, uint32_t flags) lt_dlhandle dlh; void (*reg_handle) (void); - DEBUG ("file = %s", file); - lt_dlinit (); lt_dlerror (); /* clear errors */ @@ -297,23 +295,35 @@ static int plugin_load_file (char *file, uint32_t flags) } #else /* if LIBTOOL_VERSION == 1 */ if (flags & PLUGIN_FLAGS_GLOBAL) - ERROR ("plugin_load_file: The global flag is not supported, " + WARNING ("plugin_load_file: The global flag is not supported, " "libtool 2 is required for this."); dlh = lt_dlopen (file); #endif if (dlh == NULL) { - const char *error = lt_dlerror (); + char errbuf[1024] = ""; + + ssnprintf (errbuf, sizeof (errbuf), + "lt_dlopen (\"%s\") failed: %s. " + "The most common cause for this problem are " + "missing dependencies. Use ldd(1) to check " + "the dependencies of the plugin " + "/ shared object.", + file, lt_dlerror ()); + + ERROR ("%s", errbuf); + /* Make sure this is printed to STDERR in any case, but also + * make sure it's printed only once. */ + if (list_log != NULL) + fprintf (stderr, "ERROR: %s\n", errbuf); - ERROR ("lt_dlopen (%s) failed: %s", file, error); - fprintf (stderr, "lt_dlopen (%s) failed: %s\n", file, error); return (1); } if ((reg_handle = (void (*) (void)) lt_dlsym (dlh, "module_register")) == NULL) { - WARNING ("Couldn't find symbol `module_register' in `%s': %s\n", + WARNING ("Couldn't find symbol \"module_register\" in \"%s\": %s\n", file, lt_dlerror ()); lt_dlclose (dlh); return (-1); @@ -336,7 +346,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) while (read_loop != 0) { read_func_t *rf; - struct timeval now; + cdtime_t now; int status; int rf_type; int rc; @@ -347,10 +357,9 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) { struct timespec abstime; - gettimeofday (&now, /* timezone = */ NULL); + now = cdtime (); - abstime.tv_sec = now.tv_sec + interval_g; - abstime.tv_nsec = 1000 * now.tv_usec; + CDTIME_T_TO_TIMESPEC (now + interval_g, &abstime); pthread_mutex_lock (&read_lock); pthread_cond_timedwait (&read_cond, &read_lock, @@ -361,15 +370,13 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) if ((rf->rf_interval.tv_sec == 0) && (rf->rf_interval.tv_nsec == 0)) { - gettimeofday (&now, /* timezone = */ NULL); + now = cdtime (); - rf->rf_interval.tv_sec = interval_g; - rf->rf_interval.tv_nsec = 0; + CDTIME_T_TO_TIMESPEC (interval_g, &rf->rf_interval); rf->rf_effective_interval = rf->rf_interval; - rf->rf_next_read.tv_sec = now.tv_sec; - rf->rf_next_read.tv_nsec = 1000 * now.tv_usec; + CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read); } /* sleep until this entry is due, @@ -380,12 +387,15 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) * we need to re-evaluate the condition every time * pthread_cond_timedwait returns. */ rc = 0; - while (!timeout_reached(rf->rf_next_read) && rc == 0) { + while ((read_loop != 0) + && !timeout_reached(rf->rf_next_read) + && rc == 0) + { rc = pthread_cond_timedwait (&read_cond, &read_lock, &rf->rf_next_read); } - /* Must hold `real_lock' when accessing `rf->rf_type'. */ + /* Must hold `read_lock' when accessing `rf->rf_type'. */ rf_type = rf->rf_type; pthread_mutex_unlock (&read_lock); @@ -456,7 +466,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) } /* update the ``next read due'' field */ - gettimeofday (&now, /* timezone = */ NULL); + now = cdtime (); DEBUG ("plugin_read_thread: Effective interval of the " "%s plugin is %i.%09i.", @@ -473,15 +483,12 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) NORMALIZE_TIMESPEC (rf->rf_next_read); /* Check, if `rf_next_read' is in the past. */ - if ((rf->rf_next_read.tv_sec < now.tv_sec) - || ((rf->rf_next_read.tv_sec == now.tv_sec) - && (rf->rf_next_read.tv_nsec < (1000 * now.tv_usec)))) + if (TIMESPEC_TO_CDTIME_T (&rf->rf_next_read) < now) { /* `rf_next_read' is in the past. Insert `now' * so this value doesn't trail off into the * past too much. */ - rf->rf_next_read.tv_sec = now.tv_sec; - rf->rf_next_read.tv_nsec = 1000 * now.tv_usec; + CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read); } DEBUG ("plugin_read_thread: Next read of the %s plugin at %i.%09i.", @@ -731,6 +738,17 @@ static int plugin_insert_read (read_func_t *rf) } } + le = llist_search (read_list, rf->rf_name); + if (le != NULL) + { + pthread_mutex_unlock (&read_lock); + WARNING ("The read function \"%s\" is already registered. " + "Check for duplicate \"LoadPlugin\" lines " + "in your configuration!", + rf->rf_name); + return (EINVAL); + } + le = llentry_create (rf->rf_name, rf); if (le == NULL) { @@ -759,14 +777,13 @@ int plugin_register_read (const char *name, int (*callback) (void)) { read_func_t *rf; + int status; - rf = (read_func_t *) malloc (sizeof (read_func_t)); + rf = malloc (sizeof (*rf)); if (rf == NULL) { - char errbuf[1024]; - ERROR ("plugin_register_read: malloc failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); - return (-1); + ERROR ("plugin_register_read: malloc failed."); + return (ENOMEM); } memset (rf, 0, sizeof (read_func_t)); @@ -780,7 +797,11 @@ int plugin_register_read (const char *name, rf->rf_interval.tv_nsec = 0; rf->rf_effective_interval = rf->rf_interval; - return (plugin_insert_read (rf)); + status = plugin_insert_read (rf); + if (status != 0) + sfree (rf); + + return (status); } /* int plugin_register_read */ int plugin_register_complex_read (const char *group, const char *name, @@ -789,12 +810,13 @@ int plugin_register_complex_read (const char *group, const char *name, user_data_t *user_data) { read_func_t *rf; + int status; - rf = (read_func_t *) malloc (sizeof (read_func_t)); + rf = malloc (sizeof (*rf)); if (rf == NULL) { ERROR ("plugin_register_complex_read: malloc failed."); - return (-1); + return (ENOMEM); } memset (rf, 0, sizeof (read_func_t)); @@ -822,7 +844,11 @@ int plugin_register_complex_read (const char *group, const char *name, rf->rf_udata = *user_data; } - return (plugin_insert_read (rf)); + status = plugin_insert_read (rf); + if (status != 0) + sfree (rf); + + return (status); } /* int plugin_register_complex_read */ int plugin_register_write (const char *name, @@ -839,7 +865,14 @@ int plugin_register_flush (const char *name, (void *) callback, ud)); } /* int plugin_register_flush */ -int plugin_register_shutdown (char *name, +int plugin_register_missing (const char *name, + plugin_missing_cb callback, user_data_t *ud) +{ + return (create_register_callback (&list_missing, name, + (void *) callback, ud)); +} /* int plugin_register_missing */ + +int plugin_register_shutdown (const char *name, int (*callback) (void)) { return (create_register_callback (&list_shutdown, name, @@ -1025,6 +1058,11 @@ int plugin_unregister_flush (const char *name) return (plugin_unregister (list_flush, name)); } +int plugin_unregister_missing (const char *name) +{ + return (plugin_unregister (list_missing, name)); +} + int plugin_unregister_shutdown (const char *name) { return (plugin_unregister (list_shutdown, name)); @@ -1248,7 +1286,7 @@ int plugin_write (const char *plugin, /* {{{ */ return (status); } /* }}} int plugin_write */ -int plugin_flush (const char *plugin, int timeout, const char *identifier) +int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier) { llentry_t *le; @@ -1293,7 +1331,8 @@ void plugin_shutdown_all (void) destroy_read_heap (); - plugin_flush (/* plugin = */ NULL, /* timeout = */ -1, + plugin_flush (/* plugin = */ NULL, + /* timeout = */ 0, /* identifier = */ NULL); le = NULL; @@ -1323,6 +1362,7 @@ void plugin_shutdown_all (void) * the real free function when registering the write callback. This way * the data isn't freed twice. */ destroy_all_callbacks (&list_flush); + destroy_all_callbacks (&list_missing); destroy_all_callbacks (&list_write); destroy_all_callbacks (&list_notification); @@ -1330,6 +1370,44 @@ void plugin_shutdown_all (void) destroy_all_callbacks (&list_log); } /* void plugin_shutdown_all */ +int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */ +{ + llentry_t *le; + + if (list_missing == NULL) + return (0); + + le = llist_head (list_missing); + while (le != NULL) + { + callback_func_t *cf; + plugin_missing_cb callback; + int status; + + cf = le->value; + callback = cf->cf_callback; + + status = (*callback) (vl, &cf->cf_udata); + if (status != 0) + { + if (status < 0) + { + ERROR ("plugin_dispatch_missing: Callback function \"%s\" " + "failed with status %i.", + le->key, status); + return (status); + } + else + { + return (0); + } + } + + le = le->next; + } + return (0); +} /* int }}} plugin_dispatch_missing */ + int plugin_dispatch_values (value_list_t *vl) { int status; @@ -1345,7 +1423,8 @@ int plugin_dispatch_values (value_list_t *vl) if ((vl == NULL) || (vl->type[0] == 0) || (vl->values == NULL) || (vl->values_len < 1)) { - ERROR ("plugin_dispatch_values: Invalid value list."); + ERROR ("plugin_dispatch_values: Invalid value list " + "from plugin %s.", vl->plugin); return (-1); } @@ -1371,21 +1450,27 @@ int plugin_dispatch_values (value_list_t *vl) if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0) { - INFO ("plugin_dispatch_values: Dataset not found: %s", vl->type); + char ident[6 * DATA_MAX_NAME_LEN]; + + FORMAT_VL (ident, sizeof (ident), vl); + INFO ("plugin_dispatch_values: Dataset not found: %s " + "(from \"%s\"), check your types.db!", + vl->type, ident); return (-1); } if (vl->time == 0) - vl->time = time (NULL); + vl->time = cdtime (); if (vl->interval <= 0) vl->interval = interval_g; - DEBUG ("plugin_dispatch_values: time = %u; interval = %i; " + DEBUG ("plugin_dispatch_values: time = %.3f; interval = %.3f; " "host = %s; " "plugin = %s; plugin_instance = %s; " "type = %s; type_instance = %s;", - (unsigned int) vl->time, vl->interval, + CDTIME_T_TO_DOUBLE (vl->time), + CDTIME_T_TO_DOUBLE (vl->interval), vl->host, vl->plugin, vl->plugin_instance, vl->type, vl->type_instance); @@ -1469,9 +1554,6 @@ int plugin_dispatch_values (value_list_t *vl) /* Update the value cache */ uc_update (ds, vl); - /* Initiate threshold checking */ - ut_check_threshold (ds, vl); - if (post_cache_chain != NULL) { status = fc_process_chain (ds, vl, post_cache_chain); @@ -1510,9 +1592,9 @@ int plugin_dispatch_notification (const notification_t *notif) /* Possible TODO: Add flap detection here */ DEBUG ("plugin_dispatch_notification: severity = %i; message = %s; " - "time = %u; host = %s;", + "time = %.3f; host = %s;", notif->severity, notif->message, - (unsigned int) notif->time, notif->host); + CDTIME_T_TO_DOUBLE (notif->time), notif->host); /* Nobody cares for notifications */ if (list_notification == NULL) @@ -1646,7 +1728,7 @@ static int plugin_notification_meta_add (notification_t *n, } case NM_TYPE_BOOLEAN: { - meta->nm_value.nm_boolean = *((bool *) value); + meta->nm_value.nm_boolean = *((_Bool *) value); break; } default: @@ -1700,7 +1782,7 @@ int plugin_notification_meta_add_double (notification_t *n, int plugin_notification_meta_add_boolean (notification_t *n, const char *name, - bool value) + _Bool value) { return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value)); }