X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Futils_threshold.c;h=d831a355981f7f4107ff5f6880d6540c1e2f98bd;hb=095343a8980eda2627455ed94f266e3d59dc527e;hp=03a3f2d473907cc13fd44a3c6fdde5d99749e319;hpb=218635ab44a8533ef5b23fd1ae78be761ff0600c;p=collectd.git diff --git a/src/utils_threshold.c b/src/utils_threshold.c index 03a3f2d4..d831a355 100644 --- a/src/utils_threshold.c +++ b/src/utils_threshold.c @@ -1,6 +1,9 @@ /** * collectd - src/utils_threshold.c - * Copyright (C) 2007,2008 Florian octo Forster + * Copyright (C) 2007-2009 Florian octo Forster + * Copyright (C) 2008-2009 Sebastian Harl + * Copyright (C) 2009 Andrés J. Díaz + * * * 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,6 +20,8 @@ * * Author: * Florian octo Forster + * Sebastian Harl + * Andrés J. Díaz **/ #include "collectd.h" @@ -24,6 +29,8 @@ #include "plugin.h" #include "utils_avltree.h" #include "utils_cache.h" +#include "utils_threshold.h" +#include "utils_subst.h" #include #include @@ -33,22 +40,8 @@ * {{{ */ #define UT_FLAG_INVERT 0x01 #define UT_FLAG_PERSIST 0x02 - -typedef struct threshold_s -{ - char host[DATA_MAX_NAME_LEN]; - char plugin[DATA_MAX_NAME_LEN]; - char plugin_instance[DATA_MAX_NAME_LEN]; - char type[DATA_MAX_NAME_LEN]; - char type_instance[DATA_MAX_NAME_LEN]; - char data_source[DATA_MAX_NAME_LEN]; - gauge_t warning_min; - gauge_t warning_max; - gauge_t failure_min; - gauge_t failure_max; - int flags; - struct threshold_s *next; -} threshold_t; +#define UT_FLAG_PERCENTAGE 0x04 +#define UT_FLAG_INTERESTING 0x08 /* }}} */ /* @@ -226,41 +219,91 @@ static int ut_config_type_min (threshold_t *th, oconfig_item_t *ci) return (0); } /* int ut_config_type_min */ -static int ut_config_type_invert (threshold_t *th, oconfig_item_t *ci) +static int ut_config_type_hits (threshold_t *th, oconfig_item_t *ci) { if ((ci->values_num != 1) - || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) + || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) { - WARNING ("threshold values: The `Invert' option needs exactly one " - "boolean argument."); + WARNING ("threshold values: The `%s' option needs exactly one " + "number argument.", ci->key); return (-1); } - if (ci->values[0].value.boolean) - th->flags |= UT_FLAG_INVERT; - else - th->flags &= ~UT_FLAG_INVERT; + th->hits = ci->values[0].value.number; return (0); -} /* int ut_config_type_invert */ +} /* int ut_config_type_hits */ -static int ut_config_type_persist (threshold_t *th, oconfig_item_t *ci) +static int ut_config_type_hysteresis (threshold_t *th, oconfig_item_t *ci) { if ((ci->values_num != 1) - || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) + || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) { - WARNING ("threshold values: The `Persist' option needs exactly one " - "boolean argument."); + WARNING ("threshold values: The `%s' option needs exactly one " + "number argument.", ci->key); return (-1); } - if (ci->values[0].value.boolean) - th->flags |= UT_FLAG_PERSIST; - else - th->flags &= ~UT_FLAG_PERSIST; + th->hysteresis = ci->values[0].value.number; + + 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_persist */ +} /* 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) { @@ -289,6 +332,10 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci) th.warning_max = NAN; th.failure_min = NAN; 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++) { @@ -305,10 +352,22 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci) else if ((strcasecmp ("WarningMin", option->key) == 0) || (strcasecmp ("FailureMin", option->key) == 0)) status = ut_config_type_min (&th, option); + else if (strcasecmp ("Interesting", option->key) == 0) + status = cf_util_get_flag (option, &th.flags, UT_FLAG_INTERESTING); else if (strcasecmp ("Invert", option->key) == 0) - status = ut_config_type_invert (&th, option); + status = cf_util_get_flag (option, &th.flags, UT_FLAG_INVERT); else if (strcasecmp ("Persist", option->key) == 0) - status = ut_config_type_persist (&th, option); + status = cf_util_get_flag (option, &th.flags, UT_FLAG_PERSIST); + else if (strcasecmp ("Percentage", option->key) == 0) + status = cf_util_get_flag (option, &th.flags, UT_FLAG_PERCENTAGE); + else if (strcasecmp ("Hits", option->key) == 0) + 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' " @@ -467,6 +526,10 @@ int ut_config (const oconfig_item_t *ci) th.warning_max = NAN; th.failure_min = NAN; th.failure_max = NAN; + + th.hits = 0; + th.hysteresis = 0; + th.flags = UT_FLAG_INTERESTING; /* interesting by default */ for (i = 0; i < ci->children_num; i++) { @@ -540,6 +603,100 @@ 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]; + int rates_failed; + + int i; + + sstrncpy (msg, fmt, sizeof (msg)); + +#define REPLACE_FIELD(t,v) do { \ + char temp[NOTIF_MAX_MSG_LEN]; \ + if (subst_string (temp, sizeof (temp), msg, (t), (v)) != NULL) \ + sstrncpy (msg, temp, sizeof (msg)); \ +} while (0) + +#define REPLACE_FIELD_F(t,f) do { \ + char f_str[64]; \ + ssnprintf (f_str, sizeof (f_str), "%g", (f)); \ + REPLACE_FIELD ((t), f_str); \ +} while (0) + +#define REPLACE_FIELD_I(t,i) do { \ + char i_str[64]; \ + ssnprintf (i_str, sizeof (i_str), "%i", (i)); \ + REPLACE_FIELD ((t), i_str); \ +} while (0) + + 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); + + /* ds_index is set to -1 if the value is missing (there is no data source / + * value we could reasonably use. */ + if (ds_index >= 0) + { + 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. */ + REPLACE_FIELD_F ("%{value}", (double) values[ds_index]); + } + + /* Now replace all %{ds: