From ba4b24567e4dc5a5e3182a187912aaa3e8d10b54 Mon Sep 17 00:00:00 2001 From: "Andres J. Diaz" Date: Sun, 13 Jun 2010 15:19:01 +0200 Subject: [PATCH] Add custom message for threshold and missings. Hi everybuddy Add two new options in thresholds, the Message which can define a custom message for thresholds and MissingMessage, which define a custom message for missing interesting values related with that threshold. This work is heavly based on previously custom message patch publishded by Taizo ITO on Mar-2010 [1]. The code was modify to add more patterns and keep compatibility with target_notification syntax. Also now we have a MissingMessage too. The pattern matching code was moved to a new function in utils_threshold.c (ut_build_message) which create the message string. New patterns: %{ds:} returns values for ds called "name", as target_notification does. %{value} return the offending value for the threshold. %{data_source} return the datasource name for offending value %{hysteresis} return the hysteresis parameter value %{hits} return the hits parameter value [1] http://www.mail-archive.com/collectd@verplant.org/msg00569.html Thanks again to Taizo for the previously work :) Enjoy! --- src/plugin.h | 2 +- src/utils_cache.c | 56 ++++++++- src/utils_threshold.c | 313 ++++++++++++++++++++++++++++++++++++++++---------- src/utils_threshold.h | 13 +++ 4 files changed, 318 insertions(+), 66 deletions(-) diff --git a/src/plugin.h b/src/plugin.h index 8b9449ee..ba40c659 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -58,7 +58,7 @@ # define LOG_DEBUG 7 #endif -#define NOTIF_MAX_MSG_LEN 256 +#define NOTIF_MAX_MSG_LEN 512 #define NOTIF_FAILURE 1 #define NOTIF_WARNING 2 diff --git a/src/utils_cache.c b/src/utils_cache.c index 69ea864b..2e33ab08 100644 --- a/src/utils_cache.c +++ b/src/utils_cache.c @@ -25,6 +25,7 @@ #include "utils_avltree.h" #include "utils_cache.h" #include "utils_threshold.h" +#include "utils_subst.h" #include "meta_data.h" #include @@ -131,9 +132,13 @@ static int uc_send_notification (const char *name) char *plugin_instance; char *type; char *type_instance; + threshold_t th; notification_t n; + data_set_t ds; + value_list_t vl; + name_copy = strdup (name); if (name_copy == NULL) { @@ -150,6 +155,18 @@ static int uc_send_notification (const char *name) return (-1); } + memset (&ds, '\0', sizeof (ds)); + memset (&vl, '\0', sizeof (vl)); + sstrncpy (vl.host, host, sizeof (vl.host)); + sstrncpy (vl.plugin, plugin, sizeof (vl.plugin)); + if (plugin_instance != NULL) + sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance)); + sstrncpy (ds.type, type, sizeof (ds.type)); + sstrncpy (vl.type, type, sizeof (vl.type)); + if (type_instance != NULL) + sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); + + /* Copy the associative members */ notification_init (&n, NOTIF_FAILURE, /* host = */ NULL, host, plugin, plugin_instance, type, type_instance); @@ -157,6 +174,7 @@ static int uc_send_notification (const char *name) sfree (name_copy); name_copy = host = plugin = plugin_instance = type = type_instance = NULL; + pthread_mutex_lock (&cache_lock); /* @@ -183,9 +201,41 @@ static int uc_send_notification (const char *name) return (-1); } - ssnprintf (n.message, sizeof (n.message), - "%s has not been updated for %i seconds.", name, - (int) (n.time - ce->last_update)); + /* if the associated threshold has a missing message, then use custom + * message. FIXME: we do a threshold_search here and in uc_check_timeout + * (calling ut_check_interesting, but we really need to do this once */ + if ( !ut_search_threshold(&vl, &th) && + (th.missing_message != NULL) ) + { + char msg[NOTIF_MAX_MSG_LEN]; + char temp[NOTIF_MAX_MSG_LEN]; + + sstrncpy (msg, th.missing_message, sizeof (msg)); + (void) ut_build_message (msg, NOTIF_MAX_MSG_LEN, th.missing_message, + &ds, 0, &vl, ce->values_gauge, + &n, &th); + +#define REPLACE_FIELD(t,v) \ + if (subst_string (temp, sizeof (temp), msg, t, v) != NULL) \ + sstrncpy (msg, temp, sizeof (msg)); + + char itoa_temp[NOTIF_MAX_MSG_LEN]; +#define ITOA(string,i) \ + memset(string,0x00,sizeof(string)); \ + snprintf(string, sizeof(string), "%i", i); + + ITOA(itoa_temp, (int)(n.time - ce->last_update)) + REPLACE_FIELD("%{missing}", itoa_temp) + + (void) ssnprintf (n.message, sizeof (n.message), + "%s", msg); + } + else + { + ssnprintf (n.message, sizeof (n.message), + "%s has not been updated for %i seconds.", name, + (int) (n.time - ce->last_update)); + } pthread_mutex_unlock (&cache_lock); diff --git a/src/utils_threshold.c b/src/utils_threshold.c index 99309b93..6f28da2f 100644 --- a/src/utils_threshold.c +++ b/src/utils_threshold.c @@ -30,6 +30,7 @@ #include "utils_avltree.h" #include "utils_cache.h" #include "utils_threshold.h" +#include "utils_subst.h" #include #include @@ -248,6 +249,62 @@ static int ut_config_type_hysteresis (threshold_t *th, oconfig_item_t *ci) return (0); } /* int ut_config_type_hysteresis */ +static int ut_config_type_message (threshold_t *th, oconfig_item_t *ci) +{ + + if ((ci->values_num != 1) + || (ci->values[0].type != OCONFIG_TYPE_STRING)) + { + WARNING ("threshold values: The `%s' option needs exactly one " + "string argument.", ci->key); + return (-1); + } + + if (ci->values[0].value.string[0] == 0) + { + WARNING ("threshold values: The `%s' option does not accept empty strings.", + ci->key); + return (-1); + } + + th->message = strdup (ci->values[0].value.string); + if (th->message == NULL) + { + ERROR ("ut_config_type_message: sstrdup failed."); + return (-1); + } + + return (0); +} /* int ut_config_type_message */ + +static int ut_config_type_missingmessage (threshold_t *th, oconfig_item_t *ci) +{ + + if ((ci->values_num != 1) + || (ci->values[0].type != OCONFIG_TYPE_STRING)) + { + WARNING ("threshold values: The `%s' option needs exactly one " + "string argument.", ci->key); + return (-1); + } + + if (ci->values[0].value.string[0] == 0) + { + WARNING ("threshold values: The `%s' option does not accept empty strings.", + ci->key); + return (-1); + } + + th->missing_message = strdup (ci->values[0].value.string); + if (th->missing_message == NULL) + { + ERROR ("ut_config_type_missingmessage: sstrdup failed."); + return (-1); + } + + return (0); +} /* int ut_config_type_missingmessage */ + static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci) { int i; @@ -277,6 +334,7 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci) th.failure_max = NAN; th.hits = 0; th.hysteresis = 0; + th.message = NULL; th.flags = UT_FLAG_INTERESTING; /* interesting by default */ for (i = 0; i < ci->children_num; i++) @@ -306,6 +364,10 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci) status = ut_config_type_hits (&th, option); else if (strcasecmp ("Hysteresis", option->key) == 0) status = ut_config_type_hysteresis (&th, option); + else if (strcasecmp ("Message", option->key) == 0) + status = ut_config_type_message (&th, option); + else if (strcasecmp ("MissingMessage", option->key) == 0) + status = ut_config_type_missingmessage (&th, option); else { WARNING ("threshold values: Option `%s' not allowed inside a `Type' " @@ -541,6 +603,120 @@ static threshold_t *threshold_search (const value_list_t *vl) return (NULL); } /* threshold_t *threshold_search */ +/* char *ut_build_message + * + * Return a custom formated message for dataset, values and previously created + * notification (which must include time and other fields), if th is present, + * templates for threshold will be interpreted, if th is NULL these will be + * skipped. + */ +int ut_build_message(char *out, size_t bufsize, const char *fmt, + const data_set_t *ds, int ds_index, const value_list_t *vl, const gauge_t *values, + const notification_t *n, const threshold_t *th) +{ + + /* TODO: We could provide here a way to use meta information on thresholds + * directly in the future. */ + char msg[NOTIF_MAX_MSG_LEN]; + char temp[NOTIF_MAX_MSG_LEN]; + gauge_t *rates; + int rates_failed; + + int i; + + sstrncpy (msg, fmt, sizeof (msg)); + +#define REPLACE_FIELD(t,v) \ + if (subst_string (temp, sizeof (temp), msg, t, v) != NULL) \ + sstrncpy (msg, temp, sizeof (msg)); + + char ftoa_temp[NOTIF_MAX_MSG_LEN]; +#define FTOA(string,f) \ + memset(string,0x00,sizeof(string)); \ + snprintf(string, sizeof(string), "%f", f); + + char itoa_temp[NOTIF_MAX_MSG_LEN]; +#define ITOA(string,i) \ + memset(string,0x00,sizeof(string)); \ + snprintf(string, sizeof(string), "%i", i); + + REPLACE_FIELD ("%{host}", n->host); + REPLACE_FIELD ("%{plugin}", n->plugin); + REPLACE_FIELD ("%{plugin_instance}", n->plugin_instance); + REPLACE_FIELD ("%{type}", n->type); + REPLACE_FIELD ("%{type_instance}", n->type_instance); + REPLACE_FIELD ("%{data_source}", ds->ds[ds_index].name); + + /* This is the offending value, its equivalent to %{ds:value}, if + * value is the data_source name. */ + FTOA(ftoa_temp,values[ds_index]) + REPLACE_FIELD ("%{value}", ftoa_temp); + + /* Now replace all %{ds: