X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fplugin.c;h=cd7b10834c4559f8e456ef8e6efe20bdf51f4271;hb=bc7992ed0693313a2b1fe282a5bf23f1cc9f8e42;hp=e611b8cec2067c06c9f93fd053bfe24973c80d8b;hpb=903ebad4e6fe24e6b04097f18048b63ebb3bcb29;p=collectd.git diff --git a/src/plugin.c b/src/plugin.c index e611b8ce..cd7b1083 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -1,6 +1,6 @@ /** * collectd - src/plugin.c - * Copyright (C) 2005-2008 Florian octo Forster + * Copyright (C) 2005-2009 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 @@ -21,6 +21,7 @@ **/ #include "collectd.h" +#include "utils_complain.h" #include @@ -35,6 +36,7 @@ #include "utils_llist.h" #include "utils_cache.h" #include "utils_threshold.h" +#include "filter_chain.h" /* * Private structures @@ -54,11 +56,15 @@ 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_filter; static llist_t *list_flush; static llist_t *list_shutdown; static llist_t *list_log; static llist_t *list_notification; +static fc_chain_t *pre_cache_chain = NULL; +static fc_chain_t *post_cache_chain = NULL; + static c_avl_tree_t *data_sets; static char *plugindir = NULL; @@ -148,14 +154,14 @@ static int plugin_load_file (char *file) { const char *error = lt_dlerror (); - ERROR ("lt_dlopen failed: %s", error); - fprintf (stderr, "lt_dlopen failed: %s\n", error); + 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); @@ -273,6 +279,9 @@ static void stop_threads (void) { int i; + if (read_threads == NULL) + return; + pthread_mutex_lock (&read_lock); read_loop = 0; DEBUG ("plugin: stop_threads: Signalling `read_cond'"); @@ -328,7 +337,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); @@ -348,7 +358,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; @@ -439,7 +450,14 @@ 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)) +int plugin_register_filter (const char *name, + int (*callback) (const data_set_t *ds, value_list_t *vl)) +{ + return (register_callback (&list_filter, name, (void *) callback)); +} /* int plugin_register_filter */ + +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 */ @@ -538,6 +556,11 @@ int plugin_unregister_write (const char *name) return (plugin_unregister (list_write, name)); } +int plugin_unregister_filter (const char *name) +{ + return (plugin_unregister (list_filter, name)); +} + int plugin_unregister_flush (const char *name) { return (plugin_unregister (list_flush, name)); @@ -576,6 +599,7 @@ int plugin_unregister_notification (const char *name) void plugin_init_all (void) { + const char *chain_name; int (*callback) (void); llentry_t *le; int status; @@ -583,6 +607,13 @@ void plugin_init_all (void) /* Init the value cache */ uc_init (); + chain_name = global_option_get ("PreCacheChain"); + pre_cache_chain = fc_chain_get_by_name (chain_name); + + chain_name = global_option_get ("PostCacheChain"); + post_cache_chain = fc_chain_get_by_name (chain_name); + + if ((list_init == NULL) && (list_read == NULL)) return; @@ -618,7 +649,8 @@ void plugin_init_all (void) int num; rt = global_option_get ("ReadThreads"); num = atoi (rt); - start_threads ((num > 0) ? num : 5); + if (num != -1) + start_threads ((num > 0) ? num : 5); } } /* void plugin_init_all */ @@ -661,42 +693,129 @@ void plugin_read_all (void) pthread_mutex_unlock (&read_lock); } /* void plugin_read_all */ -int plugin_flush_one (int timeout, const char *name) +/* Read function called when the `-T' command line argument is given. */ +int plugin_read_all_once (void) { - int (*callback) (int); - llentry_t *le; + llentry_t *le; + read_func_t *rf; int status; + int return_status = 0; - if (list_flush == NULL) - return (-1); - - le = llist_search (list_flush, name); - if (le == NULL) - return (-1); - callback = (int (*) (int)) le->value; + if (list_read == NULL) + { + NOTICE ("No read-functions are registered."); + return (0); + } - status = (*callback) (timeout); + for (le = llist_head (list_read); + le != NULL; + le = le->next) + { + rf = (read_func_t *) le->value; + status = rf->callback (); + if (status != 0) + { + NOTICE ("read-function of plugin `%s' failed.", + le->key); + return_status = -1; + } + } - return (status); -} /* int plugin_flush_ont */ + return (return_status); +} /* int plugin_read_all_once */ -void plugin_flush_all (int timeout) +int plugin_write (const char *plugin, /* {{{ */ + const data_set_t *ds, const value_list_t *vl) { - 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 (*callback) (const data_set_t *ds, const value_list_t *vl); + llentry_t *le; + int status; + + if (vl == NULL) + return (EINVAL); + + if (list_write == NULL) + return (ENOENT); + + if (ds == NULL) + { + ds = plugin_get_ds (vl->type); + if (ds == NULL) + { + ERROR ("plugin_write: Unable to lookup type `%s'.", vl->type); + return (ENOENT); + } + } + + if (plugin == NULL) + { + int success = 0; + int failure = 0; + + le = llist_head (list_write); + while (le != NULL) + { + callback = le->value; + status = (*callback) (ds, vl); + if (status != 0) + failure++; + else + success++; + + le = le->next; + } + + if ((success == 0) && (failure != 0)) + status = -1; + else + status = 0; + } + else /* plugin != NULL */ + { + le = llist_head (list_write); + while (le != NULL) + { + if (strcasecmp (plugin, le->key) == 0) + break; + + le = le->next; + } + + if (le == NULL) + return (ENOENT); + + callback = le->value; + status = (*callback) (ds, vl); + } + + return (status); +} /* }}} int plugin_write */ + +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)) + { + le = le->next; + continue; + } + + callback = (int (*) (int, const char *)) le->value; + (*callback) (timeout, identifier); + + le = le->next; + } + return (0); +} /* int plugin_flush */ void plugin_shutdown_all (void) { @@ -723,20 +842,24 @@ 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) { - int (*callback) (const data_set_t *, const value_list_t *); + int status; + static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC; + data_set_t *ds; - llentry_t *le; - if (list_write == NULL) - { - ERROR ("plugin_dispatch_values: No write callback has been " - "registered. Please load at least one plugin " - "that provides a write function."); + if ((vl == NULL) || (*vl->type == '\0')) { + ERROR ("plugin_dispatch_values: Invalid value list."); return (-1); } + 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) { ERROR ("plugin_dispatch_values: No data sets registered. " @@ -745,12 +868,15 @@ int plugin_dispatch_values (const char *name, value_list_t *vl) return (-1); } - if (c_avl_get (data_sets, name, (void *) &ds) != 0) + if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0) { - INFO ("plugin_dispatch_values: Dataset not found: %s", name); + INFO ("plugin_dispatch_values: Dataset not found: %s", vl->type); return (-1); } + if (vl->time == 0) + vl->time = time (NULL); + DEBUG ("plugin_dispatch_values: time = %u; interval = %i; " "host = %s; " "plugin = %s; plugin_instance = %s; " @@ -758,7 +884,15 @@ int plugin_dispatch_values (const char *name, value_list_t *vl) (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); @@ -776,20 +910,39 @@ 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)); + if (pre_cache_chain != NULL) + { + status = fc_process_chain (ds, vl, pre_cache_chain); + if (status < 0) + { + WARNING ("plugin_dispatch_values: Running the " + "pre-cache chain failed with " + "status %i (%#x).", + status, status); + } + else if (status == FC_TARGET_STOP) + return (0); + } + /* Update the value cache */ uc_update (ds, vl); - ut_check_threshold (ds, vl); - le = llist_head (list_write); - while (le != NULL) + if (post_cache_chain != NULL) { - callback = (int (*) (const data_set_t *, const value_list_t *)) le->value; - (*callback) (ds, vl); - - le = le->next; + status = fc_process_chain (ds, vl, post_cache_chain); + if (status < 0) + { + WARNING ("plugin_dispatch_values: Running the " + "post-cache chain failed with " + "status %i (%#x).", + status, status); + } } + else + fc_default_action (ds, vl); return (0); } /* int plugin_dispatch_values */ @@ -823,7 +976,7 @@ int plugin_dispatch_notification (const notification_t *notif) void plugin_log (int level, const char *format, ...) { - char msg[512]; + char msg[1024]; va_list ap; void (*callback) (int, const char *); @@ -838,8 +991,8 @@ void plugin_log (int level, const char *format, ...) #endif va_start (ap, format); - vsnprintf (msg, 512, format, ap); - msg[511] = '\0'; + vsnprintf (msg, sizeof (msg), format, ap); + msg[sizeof (msg) - 1] = '\0'; va_end (ap); le = llist_head (list_log); @@ -864,3 +1017,179 @@ const data_set_t *plugin_get_ds (const char *name) return (ds); } /* data_set_t *plugin_get_ds */ + +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->nm_value.nm_string = strdup ((const char *) value); + if (meta->nm_value.nm_string == NULL) + { + ERROR ("plugin_notification_meta_add: strdup failed."); + sfree (meta); + return (-1); + } + break; + } + case NM_TYPE_SIGNED_INT: + { + meta->nm_value.nm_signed_int = *((int64_t *) value); + break; + } + case NM_TYPE_UNSIGNED_INT: + { + meta->nm_value.nm_unsigned_int = *((uint64_t *) value); + break; + } + case NM_TYPE_DOUBLE: + { + meta->nm_value.nm_double = *((double *) value); + break; + } + case NM_TYPE_BOOLEAN: + { + meta->nm_value.nm_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)); +} + +int plugin_notification_meta_add_signed_int (notification_t *n, + const char *name, + int64_t value) +{ + return (plugin_notification_meta_add (n, name, NM_TYPE_SIGNED_INT, &value)); +} + +int plugin_notification_meta_add_unsigned_int (notification_t *n, + const char *name, + uint64_t value) +{ + return (plugin_notification_meta_add (n, name, NM_TYPE_UNSIGNED_INT, &value)); +} + +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)); +} + +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)); +} + +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->nm_value.nm_string); + else if (meta->type == NM_TYPE_SIGNED_INT) + plugin_notification_meta_add_signed_int (dst, meta->name, + meta->nm_value.nm_signed_int); + else if (meta->type == NM_TYPE_UNSIGNED_INT) + plugin_notification_meta_add_unsigned_int (dst, meta->name, + meta->nm_value.nm_unsigned_int); + else if (meta->type == NM_TYPE_DOUBLE) + plugin_notification_meta_add_double (dst, meta->name, + meta->nm_value.nm_double); + else if (meta->type == NM_TYPE_BOOLEAN) + plugin_notification_meta_add_boolean (dst, meta->name, + meta->nm_value.nm_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->nm_value.nm_string); + this->nm_value.nm_string = NULL; + } + sfree (this); + + this = next; + } + + return (0); +} /* int plugin_notification_meta_free */