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
40 /* Single UNIX needed for strdup. */
44 #define _XOPEN_SOURCE 500
62 #include "filter_chain.h"
63 #include "utils_cache.h"
64 #include "utils_subst.h"
71 typedef struct tn_data_s tn_data_t;
73 static int tn_config_add_severity (tn_data_t *data, /* {{{ */
74 const oconfig_item_t *ci)
76 if ((ci->values_num != 1)
77 || (ci->values[0].type != OCONFIG_TYPE_STRING))
79 ERROR ("Target `notification': The `%s' option requires exactly one string "
80 "argument.", ci->key);
84 if ((strcasecmp ("FAILURE", ci->values[0].value.string) == 0)
85 || (strcasecmp ("CRITICAL", ci->values[0].value.string) == 0))
86 data->severity = NOTIF_FAILURE;
87 else if ((strcasecmp ("WARNING", ci->values[0].value.string) == 0)
88 || (strcasecmp ("WARN", ci->values[0].value.string) == 0))
89 data->severity = NOTIF_WARNING;
90 else if (strcasecmp ("OKAY", ci->values[0].value.string) == 0)
91 data->severity = NOTIF_OKAY;
94 WARNING ("Target `notification': Unknown severity `%s'. "
95 "Will use `FAILURE' instead.",
96 ci->values[0].value.string);
97 data->severity = NOTIF_FAILURE;
101 } /* }}} int tn_config_add_severity */
103 static int tn_config_add_string (char **dest, /* {{{ */
104 const oconfig_item_t *ci)
111 if ((ci->values_num != 1)
112 || (ci->values[0].type != OCONFIG_TYPE_STRING))
114 ERROR ("Target `notification': The `%s' option requires exactly one string "
115 "argument.", ci->key);
119 if (ci->values[0].value.string[0] == 0)
121 ERROR ("Target `notification': The `%s' option does not accept empty strings.",
126 temp = sstrdup (ci->values[0].value.string);
129 ERROR ("tn_config_add_string: sstrdup failed.");
137 } /* }}} int tn_config_add_string */
139 static int tn_destroy (void **user_data) /* {{{ */
143 if (user_data == NULL)
150 sfree (data->message);
154 } /* }}} int tn_destroy */
156 static int tn_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
162 data = (tn_data_t *) malloc (sizeof (*data));
165 ERROR ("tn_create: malloc failed.");
168 memset (data, 0, sizeof (*data));
170 data->message = NULL;
174 for (i = 0; i < ci->children_num; i++)
176 oconfig_item_t *child = ci->children + i;
178 if (strcasecmp ("Message", child->key) == 0)
179 status = tn_config_add_string (&data->message, child);
180 else if (strcasecmp ("Severity", child->key) == 0)
181 status = tn_config_add_severity (data, child);
184 ERROR ("Target `notification': The `%s' configuration option is not understood "
185 "and will be ignored.", child->key);
193 /* Additional sanity-checking */
196 if ((data->severity != NOTIF_FAILURE)
197 && (data->severity != NOTIF_WARNING)
198 && (data->severity != NOTIF_OKAY))
200 DEBUG ("Target `notification': Setting "
201 "the default severity `WARNING'.");
202 data->severity = NOTIF_WARNING;
205 if (data->message == NULL)
207 ERROR ("Target `notification': No `Message' option has been specified. "
208 "Without it, the `Notification' target is useless.");
217 tn_destroy ((void *) data);
223 } /* }}} int tn_create */
225 static int tn_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
226 notification_meta_t __attribute__((unused)) **meta, void **user_data)
230 char temp[NOTIF_MAX_MSG_LEN];
237 if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
243 ERROR ("Target `notification': Invoke: `data' is NULL.");
247 /* Initialize the structure. */
248 memset (&n, 0, sizeof (n));
249 n.severity = data->severity;
250 n.time = time (NULL);
251 sstrncpy (n.message, data->message, sizeof (n.message));
252 sstrncpy (n.host, vl->host, sizeof (n.host));
253 sstrncpy (n.plugin, vl->plugin, sizeof (n.plugin));
254 sstrncpy (n.plugin_instance, vl->plugin_instance,
255 sizeof (n.plugin_instance));
256 sstrncpy (n.type, vl->type, sizeof (n.type));
257 sstrncpy (n.type_instance, vl->type_instance,
258 sizeof (n.type_instance));
261 #define REPLACE_FIELD(t,v) \
262 if (subst_string (temp, sizeof (temp), n.message, t, v) != NULL) \
263 sstrncpy (n.message, temp, sizeof (n.message));
264 REPLACE_FIELD ("%{host}", n.host);
265 REPLACE_FIELD ("%{plugin}", n.plugin);
266 REPLACE_FIELD ("%{plugin_instance}", n.plugin_instance);
267 REPLACE_FIELD ("%{type}", n.type);
268 REPLACE_FIELD ("%{type_instance}", n.type_instance);
272 for (i = 0; i < ds->ds_num; i++)
274 char template[DATA_MAX_NAME_LEN];
275 char value_str[DATA_MAX_NAME_LEN];
277 ssnprintf (template, sizeof (template), "%%{ds:%s}", ds->ds[i].name);
279 if (ds->ds[i].type != DS_TYPE_GAUGE)
281 if ((rates == NULL) && (rates_failed == 0))
283 rates = uc_get_rate (ds, vl);
289 /* If this is a gauge value, use the current value. */
290 if (ds->ds[i].type == DS_TYPE_GAUGE)
291 ssnprintf (value_str, sizeof (value_str),
292 "%g", (double) vl->values[i].gauge);
293 /* If it's a counter, try to use the current rate. This may fail, if the
294 * value has been renamed. */
295 else if (rates != NULL)
296 ssnprintf (value_str, sizeof (value_str),
297 "%g", (double) rates[i]);
298 /* Since we don't know any better, use the string `unknown'. */
300 sstrncpy (value_str, "unknown", sizeof (value_str));
302 REPLACE_FIELD (template, value_str);
306 plugin_dispatch_notification (&n);
308 return (FC_TARGET_CONTINUE);
309 } /* }}} int tn_invoke */
311 void module_register (void)
315 memset (&tproc, 0, sizeof (tproc));
316 tproc.create = tn_create;
317 tproc.destroy = tn_destroy;
318 tproc.invoke = tn_invoke;
319 fc_register_target ("notification", tproc);
320 } /* module_register */
322 /* vim: set sw=2 sts=2 tw=78 et fdm=marker : */