2 * collectd - src/target_notification.c
3 * Copyright (C) 2008 Florian Forster
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Florian Forster <octo at verplant.org>
23 * First tell the compiler to stick to the C99 and POSIX standards as close as
26 #ifndef __STRICT_ANSI__ /* {{{ */
27 # define __STRICT_ANSI__
30 #ifndef _ISOC99_SOURCE
31 # define _ISOC99_SOURCE
34 #ifdef _POSIX_C_SOURCE
35 # undef _POSIX_C_SOURCE
37 #define _POSIX_C_SOURCE 200112L
42 #define _XOPEN_SOURCE 600
59 #include "filter_chain.h"
60 #include "utils_cache.h"
61 #include "utils_subst.h"
68 typedef struct tn_data_s tn_data_t;
70 static int tn_config_add_severity (tn_data_t *data, /* {{{ */
71 const oconfig_item_t *ci)
73 if ((ci->values_num != 1)
74 || (ci->values[0].type != OCONFIG_TYPE_STRING))
76 ERROR ("Target `notification': The `%s' option requires exactly one string "
77 "argument.", ci->key);
81 if ((strcasecmp ("FAILURE", ci->values[0].value.string) == 0)
82 || (strcasecmp ("CRITICAL", ci->values[0].value.string) == 0))
83 data->severity = NOTIF_FAILURE;
84 else if ((strcasecmp ("WARNING", ci->values[0].value.string) == 0)
85 || (strcasecmp ("WARN", ci->values[0].value.string) == 0))
86 data->severity = NOTIF_WARNING;
87 else if (strcasecmp ("OKAY", ci->values[0].value.string) == 0)
88 data->severity = NOTIF_OKAY;
91 WARNING ("Target `notification': Unknown severity `%s'. "
92 "Will use `FAILURE' instead.",
93 ci->values[0].value.string);
94 data->severity = NOTIF_FAILURE;
98 } /* }}} int tn_config_add_severity */
100 static int tn_config_add_string (char **dest, /* {{{ */
101 const oconfig_item_t *ci)
108 if ((ci->values_num != 1)
109 || (ci->values[0].type != OCONFIG_TYPE_STRING))
111 ERROR ("Target `notification': The `%s' option requires exactly one string "
112 "argument.", ci->key);
116 if (ci->values[0].value.string[0] == 0)
118 ERROR ("Target `notification': The `%s' option does not accept empty strings.",
123 temp = sstrdup (ci->values[0].value.string);
126 ERROR ("tn_config_add_string: sstrdup failed.");
134 } /* }}} int tn_config_add_string */
136 static int tn_destroy (void **user_data) /* {{{ */
140 if (user_data == NULL)
147 sfree (data->message);
151 } /* }}} int tn_destroy */
153 static int tn_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
159 data = (tn_data_t *) malloc (sizeof (*data));
162 ERROR ("tn_create: malloc failed.");
165 memset (data, 0, sizeof (*data));
167 data->message = NULL;
171 for (i = 0; i < ci->children_num; i++)
173 oconfig_item_t *child = ci->children + i;
175 if (strcasecmp ("Message", child->key) == 0)
176 status = tn_config_add_string (&data->message, child);
177 else if (strcasecmp ("Severity", child->key) == 0)
178 status = tn_config_add_severity (data, child);
181 ERROR ("Target `notification': The `%s' configuration option is not understood "
182 "and will be ignored.", child->key);
190 /* Additional sanity-checking */
193 if ((data->severity != NOTIF_FAILURE)
194 && (data->severity != NOTIF_WARNING)
195 && (data->severity != NOTIF_OKAY))
197 DEBUG ("Target `notification': Setting "
198 "the default severity `WARNING'.");
199 data->severity = NOTIF_WARNING;
202 if (data->message == NULL)
204 ERROR ("Target `notification': No `Message' option has been specified. "
205 "Without it, the `Notification' target is useless.");
214 tn_destroy ((void *) data);
220 } /* }}} int tn_create */
222 static int tn_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
223 notification_meta_t __attribute__((unused)) **meta, void **user_data)
227 char temp[NOTIF_MAX_MSG_LEN];
234 if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
240 ERROR ("Target `notification': Invoke: `data' is NULL.");
244 /* Initialize the structure. */
245 memset (&n, 0, sizeof (n));
246 n.severity = data->severity;
247 n.time = time (NULL);
248 sstrncpy (n.message, data->message, sizeof (n.message));
249 sstrncpy (n.host, vl->host, sizeof (n.host));
250 sstrncpy (n.plugin, vl->plugin, sizeof (n.plugin));
251 sstrncpy (n.plugin_instance, vl->plugin_instance,
252 sizeof (n.plugin_instance));
253 sstrncpy (n.type, vl->type, sizeof (n.type));
254 sstrncpy (n.type_instance, vl->type_instance,
255 sizeof (n.type_instance));
258 #define REPLACE_FIELD(t,v) \
259 if (subst_string (temp, sizeof (temp), n.message, t, v) != NULL) \
260 sstrncpy (n.message, temp, sizeof (n.message));
261 REPLACE_FIELD ("%{host}", n.host);
262 REPLACE_FIELD ("%{plugin}", n.plugin);
263 REPLACE_FIELD ("%{plugin_instance}", n.plugin_instance);
264 REPLACE_FIELD ("%{type}", n.type);
265 REPLACE_FIELD ("%{type_instance}", n.type_instance);
269 for (i = 0; i < ds->ds_num; i++)
271 char template[DATA_MAX_NAME_LEN];
272 char value_str[DATA_MAX_NAME_LEN];
274 ssnprintf (template, sizeof (template), "%%{ds:%s}", ds->ds[i].name);
276 if (ds->ds[i].type != DS_TYPE_GAUGE)
278 if ((rates == NULL) && (rates_failed == 0))
280 rates = uc_get_rate (ds, vl);
286 /* If this is a gauge value, use the current value. */
287 if (ds->ds[i].type == DS_TYPE_GAUGE)
288 ssnprintf (value_str, sizeof (value_str),
289 "%g", (double) vl->values[i].gauge);
290 /* If it's a counter, try to use the current rate. This may fail, if the
291 * value has been renamed. */
292 else if (rates != NULL)
293 ssnprintf (value_str, sizeof (value_str),
294 "%g", (double) rates[i]);
295 /* Since we don't know any better, use the string `unknown'. */
297 sstrncpy (value_str, "unknown", sizeof (value_str));
299 REPLACE_FIELD (template, value_str);
303 plugin_dispatch_notification (&n);
305 return (FC_TARGET_CONTINUE);
306 } /* }}} int tn_invoke */
308 void module_register (void)
312 memset (&tproc, 0, sizeof (tproc));
313 tproc.create = tn_create;
314 tproc.destroy = tn_destroy;
315 tproc.invoke = tn_invoke;
316 fc_register_target ("notification", tproc);
317 } /* module_register */
319 /* vim: set sw=2 sts=2 tw=78 et fdm=marker : */