X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Ffilter_chain.c;h=7d8369b901def7d9633e78e6c73de5b14cc26f92;hb=HEAD;hp=01cd224cde5d430bb4fcf9fe7b949d32ed1cdbea;hpb=02ea8fa749d3225f2e4dbb7e00198abc3990e523;p=collectd.git diff --git a/src/filter_chain.c b/src/filter_chain.c index 01cd224c..7d8369b9 100644 --- a/src/filter_chain.c +++ b/src/filter_chain.c @@ -1,6 +1,6 @@ /** * collectd - src/filter_chain.h - * Copyright (C) 2008 Florian octo Forster + * Copyright (C) 2008-2010 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 @@ -19,47 +19,10 @@ * Florian octo Forster **/ -/* - * First tell the compiler to stick to the C99 and POSIX standards as close as - * possible. - */ -#ifndef __STRICT_ANSI__ /* {{{ */ -# define __STRICT_ANSI__ -#endif - -#ifndef _ISOC99_SOURCE -# define _ISOC99_SOURCE -#endif - -#ifdef _POSIX_C_SOURCE -# undef _POSIX_C_SOURCE -#endif -#define _POSIX_C_SOURCE 200112L - -#if 0 -/* Single UNIX needed for strdup. */ -#ifdef _XOPEN_SOURCE -# undef _XOPEN_SOURCE -#endif -#define _XOPEN_SOURCE 500 -#endif - -#ifndef _REENTRANT -# define _REENTRANT -#endif - -#ifndef _THREAD_SAFE -# define _THREAD_SAFE -#endif - -#ifdef _GNU_SOURCE -# undef _GNU_SOURCE -#endif -/* }}} */ - #include "collectd.h" #include "configfile.h" #include "plugin.h" +#include "utils_complain.h" #include "common.h" #include "filter_chain.h" @@ -102,9 +65,7 @@ struct fc_rule_s }; /* }}} */ /* List of chains, used for `chain_list_head' */ -struct fc_chain_s; -typedef struct fc_chain_s fc_chain_t; /* {{{ */ -struct fc_chain_s +struct fc_chain_s /* {{{ */ { char name[DATA_MAX_NAME_LEN]; fc_rule_t *rules; @@ -131,7 +92,7 @@ static void fc_free_matches (fc_match_t *m) /* {{{ */ (*m->proc.destroy) (&m->user_data); else if (m->user_data != NULL) { - ERROR ("Filter sybsystem: fc_free_matches: There is user data, but no " + ERROR ("Filter subsystem: fc_free_matches: There is user data, but no " "destroy functions has been specified. " "Memory will probably be lost!"); } @@ -151,7 +112,7 @@ static void fc_free_targets (fc_target_t *t) /* {{{ */ (*t->proc.destroy) (&t->user_data); else if (t->user_data != NULL) { - ERROR ("Filter sybsystem: fc_free_targets: There is user data, but no " + ERROR ("Filter subsystem: fc_free_targets: There is user data, but no " "destroy functions has been specified. " "Memory will probably be lost!"); } @@ -213,7 +174,7 @@ static char *fc_strdup (const char *orig) /* {{{ */ * * The configuration looks somewhat like this: * - * + * * * * Plugin "^mysql$" @@ -270,19 +231,21 @@ static int fc_config_add_match (fc_match_t **matches_head, /* {{{ */ sstrncpy (m->name, ptr->name, sizeof (m->name)); memcpy (&m->proc, &ptr->proc, sizeof (m->proc)); - assert (m->proc.create != NULL); m->user_data = NULL; m->next = NULL; - status = (*m->proc.create) (ci, &m->user_data); - if (status != 0) + if (m->proc.create != NULL) { - WARNING ("Filter subsystem: Failed to create a %s match.", - m->name); - fc_free_matches (m); - return (-1); + status = (*m->proc.create) (ci, &m->user_data); + if (status != 0) + { + WARNING ("Filter subsystem: Failed to create a %s match.", + m->name); + fc_free_matches (m); + return (-1); + } } - + if (*matches_head != NULL) { ptr = *matches_head; @@ -333,7 +296,7 @@ static int fc_config_add_target (fc_target_t **targets_head, /* {{{ */ t = (fc_target_t *) malloc (sizeof (*t)); if (t == NULL) { - ERROR ("fc_config_add_match: malloc failed."); + ERROR ("fc_config_add_target: malloc failed."); return (-1); } memset (t, 0, sizeof (*t)); @@ -348,7 +311,7 @@ static int fc_config_add_target (fc_target_t **targets_head, /* {{{ */ status = (*t->proc.create) (ci, &t->user_data); if (status != 0) { - WARNING ("Filter subsystem: Failed to create a %s match.", + WARNING ("Filter subsystem: Failed to create a %s target.", t->name); fc_free_targets (t); return (-1); @@ -516,21 +479,6 @@ static int fc_config_add_chain (const oconfig_item_t *ci) /* {{{ */ break; } /* for (ci->children) */ - /* Additional sanity checking. */ - while (status == 0) - { - if (chain->targets == NULL) - { - WARNING ("Filter subsystem: Chain %s: No default target has been " - "specified. Please make sure that there is a block within " - "the block!", chain->name); - status = -1; - break; - } - - break; - } /* while (status == 0) */ - if (status != 0) { fc_free_chains (chain); @@ -555,157 +503,6 @@ static int fc_config_add_chain (const oconfig_item_t *ci) /* {{{ */ return (0); } /* }}} int fc_config_add_chain */ -int fc_process_chain (const data_set_t *ds, value_list_t *vl, /* {{{ */ - fc_chain_t *chain) -{ - fc_rule_t *rule; - fc_target_t *target; - int status; - - if (chain == NULL) - return (-1); - - DEBUG ("fc_process_chain (chain = %s);", chain->name); - - status = FC_TARGET_CONTINUE; - for (rule = chain->rules; rule != NULL; rule = rule->next) - { - fc_match_t *match; - - if (rule->name[0] != 0) - { - DEBUG ("fc_process_chain (%s): Testing the `%s' rule.", - chain->name, rule->name); - } - - /* N. B.: rule->matches may be NULL. */ - for (match = rule->matches; match != NULL; match = match->next) - { - status = (*match->proc.match) (ds, vl, /* meta = */ NULL, - &match->user_data); - if (status < 0) - { - WARNING ("fc_process_chain (%s): A match failed.", chain->name); - break; - } - else if (status != FC_MATCH_MATCHES) - break; - } - - /* for-loop has been aborted: Either error or no match. */ - if (match != NULL) - { - status = FC_TARGET_CONTINUE; - continue; - } - - if (rule->name[0] != 0) - { - DEBUG ("fc_process_chain (%s): Rule `%s' matches.", - chain->name, rule->name); - } - - for (target = rule->targets; target != NULL; target = target->next) - { - /* If we get here, all matches have matched the value. Execute the - * target. */ - status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL, - &target->user_data); - if (status < 0) - { - WARNING ("fc_process_chain (%s): A target failed.", chain->name); - continue; - } - else if (status == FC_TARGET_CONTINUE) - continue; - else if (status == FC_TARGET_STOP) - break; - else if (status == FC_TARGET_RETURN) - break; - else - { - WARNING ("fc_process_chain (%s): Unknown return value " - "from target `%s': %i", - chain->name, target->name, status); - } - } - - if ((status == FC_TARGET_STOP) - || (status == FC_TARGET_RETURN)) - { - if (rule->name[0] != 0) - { - DEBUG ("fc_process_chain (%s): Rule `%s' signaled " - "the %s condition.", - chain->name, rule->name, - (status == FC_TARGET_STOP) ? "stop" : "return"); - } - break; - } - else - { - status = FC_TARGET_CONTINUE; - } - } /* for (rule) */ - - if (status == FC_TARGET_STOP) - return (FC_TARGET_STOP); - else if (status == FC_TARGET_RETURN) - return (FC_TARGET_CONTINUE); - - /* for-loop has been aborted: A target returned `FC_TARGET_STOP' */ - if (rule != NULL) - return (FC_TARGET_CONTINUE); - - DEBUG ("fc_process_chain (%s): Executing the default targets.", - chain->name); - - status = FC_TARGET_CONTINUE; - for (target = chain->targets; target != NULL; target = target->next) - { - /* If we get here, all matches have matched the value. Execute the - * target. */ - status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL, - &target->user_data); - if (status < 0) - { - WARNING ("fc_process_chain (%s): The default target failed.", - chain->name); - } - else if (status == FC_TARGET_CONTINUE) - continue; - else if (status == FC_TARGET_STOP) - break; - else if (status == FC_TARGET_RETURN) - break; - else - { - WARNING ("fc_process_chain (%s): Unknown return value " - "from target `%s': %i", - chain->name, target->name, status); - } - } - - if ((status == FC_TARGET_STOP) - || (status == FC_TARGET_RETURN)) - { - assert (target != NULL); - DEBUG ("fc_process_chain (%s): Default target `%s' signaled " - "the %s condition.", - chain->name, target->name, - (status == FC_TARGET_STOP) ? "stop" : "return"); - if (status == FC_TARGET_STOP) - return (FC_TARGET_STOP); - else - return (FC_TARGET_CONTINUE); - } - - DEBUG ("fc_process_chain (%s): Signaling `continue' at end of chain.", - chain->name); - - return (FC_TARGET_CONTINUE); -} /* }}} int fc_process_chain */ - /* * Built-in target "jump" * @@ -762,7 +559,8 @@ static int fc_bit_jump_destroy (void **user_data) /* {{{ */ } /* }}} int fc_bit_jump_destroy */ static int fc_bit_jump_invoke (const data_set_t *ds, /* {{{ */ - value_list_t *vl, notification_meta_t **meta, void **user_data) + value_list_t *vl, notification_meta_t __attribute__((unused)) **meta, + void **user_data) { char *chain_name; fc_chain_t *chain; @@ -790,14 +588,18 @@ static int fc_bit_jump_invoke (const data_set_t *ds, /* {{{ */ return (FC_TARGET_CONTINUE); } /* }}} int fc_bit_jump_invoke */ -static int fc_bit_stop_invoke (const data_set_t *ds, /* {{{ */ - value_list_t *vl, notification_meta_t **meta, void **user_data) +static int fc_bit_stop_invoke (const data_set_t __attribute__((unused)) *ds, /* {{{ */ + value_list_t __attribute__((unused)) *vl, + notification_meta_t __attribute__((unused)) **meta, + void __attribute__((unused)) **user_data) { return (FC_TARGET_STOP); } /* }}} int fc_bit_stop_invoke */ -static int fc_bit_return_invoke (const data_set_t *ds, /* {{{ */ - value_list_t *vl, notification_meta_t **meta, void **user_data) +static int fc_bit_return_invoke (const data_set_t __attribute__((unused)) *ds, /* {{{ */ + value_list_t __attribute__((unused)) *vl, + notification_meta_t __attribute__((unused)) **meta, + void __attribute__((unused)) **user_data) { return (FC_TARGET_RETURN); } /* }}} int fc_bit_return_invoke */ @@ -879,7 +681,8 @@ static int fc_bit_write_destroy (void **user_data) /* {{{ */ } /* }}} int fc_bit_write_destroy */ static int fc_bit_write_invoke (const data_set_t *ds, /* {{{ */ - value_list_t *vl, notification_meta_t **meta, void **user_data) + value_list_t *vl, notification_meta_t __attribute__((unused)) **meta, + void **user_data) { char **plugin_list; int status; @@ -890,12 +693,31 @@ static int fc_bit_write_invoke (const data_set_t *ds, /* {{{ */ if ((plugin_list == NULL) || (plugin_list[0] == NULL)) { + static c_complain_t enoent_complaint = C_COMPLAIN_INIT_STATIC; + status = plugin_write (/* plugin = */ NULL, ds, vl); - if (status != 0) + if (status == ENOENT) + { + /* in most cases this is a permanent error, so use the complain + * mechanism rather than spamming the logs */ + c_complain (LOG_INFO, &enoent_complaint, + "Filter subsystem: Built-in target `write': Dispatching value to " + "all write plugins failed with status %i (ENOENT). " + "Most likely this means you didn't load any write plugins.", + status); + } + else if (status != 0) { INFO ("Filter subsystem: Built-in target `write': Dispatching value to " "all write plugins failed with status %i.", status); } + else + { + assert (status == 0); + c_release (LOG_INFO, &enoent_complaint, "Filter subsystem: " + "Built-in target `write': Some write plugin is back to normal " + "operation. `write' succeeded."); + } } else { @@ -1022,22 +844,182 @@ int fc_register_target (const char *name, target_proc_t proc) /* {{{ */ return (0); } /* }}} int fc_register_target */ -/* Iterate over all rules in the chain and execute all targets for which all - * matches match. */ -int fc_process (const data_set_t *ds, value_list_t *vl) /* {{{ */ +fc_chain_t *fc_chain_get_by_name (const char *chain_name) /* {{{ */ { fc_chain_t *chain; + if (chain_name == NULL) + return (NULL); + for (chain = chain_list_head; chain != NULL; chain = chain->next) - if (strcasecmp ("Main", chain->name) == 0) + if (strcasecmp (chain_name, chain->name) == 0) + return (chain); + + return (NULL); +} /* }}} int fc_chain_get_by_name */ + +int fc_process_chain (const data_set_t *ds, value_list_t *vl, /* {{{ */ + fc_chain_t *chain) +{ + fc_rule_t *rule; + fc_target_t *target; + int status; + + if (chain == NULL) + return (-1); + + DEBUG ("fc_process_chain (chain = %s);", chain->name); + + status = FC_TARGET_CONTINUE; + for (rule = chain->rules; rule != NULL; rule = rule->next) + { + fc_match_t *match; + + if (rule->name[0] != 0) + { + DEBUG ("fc_process_chain (%s): Testing the `%s' rule.", + chain->name, rule->name); + } + + /* N. B.: rule->matches may be NULL. */ + for (match = rule->matches; match != NULL; match = match->next) + { + /* FIXME: Pass the meta-data to match targets here (when implemented). */ + status = (*match->proc.match) (ds, vl, /* meta = */ NULL, + &match->user_data); + if (status < 0) + { + WARNING ("fc_process_chain (%s): A match failed.", chain->name); + break; + } + else if (status != FC_MATCH_MATCHES) + break; + } + + /* for-loop has been aborted: Either error or no match. */ + if (match != NULL) + { + status = FC_TARGET_CONTINUE; + continue; + } + + if (rule->name[0] != 0) + { + DEBUG ("fc_process_chain (%s): Rule `%s' matches.", + chain->name, rule->name); + } + + for (target = rule->targets; target != NULL; target = target->next) + { + /* If we get here, all matches have matched the value. Execute the + * target. */ + /* FIXME: Pass the meta-data to match targets here (when implemented). */ + status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL, + &target->user_data); + if (status < 0) + { + WARNING ("fc_process_chain (%s): A target failed.", chain->name); + continue; + } + else if (status == FC_TARGET_CONTINUE) + continue; + else if (status == FC_TARGET_STOP) + break; + else if (status == FC_TARGET_RETURN) + break; + else + { + WARNING ("fc_process_chain (%s): Unknown return value " + "from target `%s': %i", + chain->name, target->name, status); + } + } + + if ((status == FC_TARGET_STOP) + || (status == FC_TARGET_RETURN)) + { + if (rule->name[0] != 0) + { + DEBUG ("fc_process_chain (%s): Rule `%s' signaled " + "the %s condition.", + chain->name, rule->name, + (status == FC_TARGET_STOP) ? "stop" : "return"); + } break; + } + else + { + status = FC_TARGET_CONTINUE; + } + } /* for (rule) */ - if (chain != NULL) - return (fc_process_chain (ds, vl, chain)); + if (status == FC_TARGET_STOP) + return (FC_TARGET_STOP); + else if (status == FC_TARGET_RETURN) + return (FC_TARGET_CONTINUE); + + /* for-loop has been aborted: A target returned `FC_TARGET_STOP' */ + if (rule != NULL) + return (FC_TARGET_CONTINUE); + DEBUG ("fc_process_chain (%s): Executing the default targets.", + chain->name); + + status = FC_TARGET_CONTINUE; + for (target = chain->targets; target != NULL; target = target->next) + { + /* If we get here, all matches have matched the value. Execute the + * target. */ + /* FIXME: Pass the meta-data to match targets here (when implemented). */ + status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL, + &target->user_data); + if (status < 0) + { + WARNING ("fc_process_chain (%s): The default target failed.", + chain->name); + } + else if (status == FC_TARGET_CONTINUE) + continue; + else if (status == FC_TARGET_STOP) + break; + else if (status == FC_TARGET_RETURN) + break; + else + { + WARNING ("fc_process_chain (%s): Unknown return value " + "from target `%s': %i", + chain->name, target->name, status); + } + } + + if ((status == FC_TARGET_STOP) + || (status == FC_TARGET_RETURN)) + { + assert (target != NULL); + DEBUG ("fc_process_chain (%s): Default target `%s' signaled " + "the %s condition.", + chain->name, target->name, + (status == FC_TARGET_STOP) ? "stop" : "return"); + if (status == FC_TARGET_STOP) + return (FC_TARGET_STOP); + else + return (FC_TARGET_CONTINUE); + } + + DEBUG ("fc_process_chain (%s): Signaling `continue' at end of chain.", + chain->name); + + return (FC_TARGET_CONTINUE); +} /* }}} int fc_process_chain */ + +/* Iterate over all rules in the chain and execute all targets for which all + * matches match. */ +int fc_default_action (const data_set_t *ds, value_list_t *vl) /* {{{ */ +{ + /* FIXME: Pass the meta-data to match targets here (when implemented). */ return (fc_bit_write_invoke (ds, vl, /* meta = */ NULL, /* user_data = */ NULL)); -} /* }}} int fc_process */ +} /* }}} int fc_default_action */ int fc_configure (const oconfig_item_t *ci) /* {{{ */ {