2 * collectd - src/target_notification.c
3 * Copyright (C) 2008 Florian Forster
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Florian Forster <octo at collectd.org>
30 #include "filter_chain.h"
31 #include "utils_cache.h"
32 #include "utils_subst.h"
39 typedef struct tn_data_s tn_data_t;
41 static int tn_config_add_severity (tn_data_t *data, /* {{{ */
42 const oconfig_item_t *ci)
44 if ((ci->values_num != 1)
45 || (ci->values[0].type != OCONFIG_TYPE_STRING))
47 ERROR ("Target `notification': The `%s' option requires exactly one string "
48 "argument.", ci->key);
52 if ((strcasecmp ("FAILURE", ci->values[0].value.string) == 0)
53 || (strcasecmp ("CRITICAL", ci->values[0].value.string) == 0))
54 data->severity = NOTIF_FAILURE;
55 else if ((strcasecmp ("WARNING", ci->values[0].value.string) == 0)
56 || (strcasecmp ("WARN", ci->values[0].value.string) == 0))
57 data->severity = NOTIF_WARNING;
58 else if (strcasecmp ("OKAY", ci->values[0].value.string) == 0)
59 data->severity = NOTIF_OKAY;
62 WARNING ("Target `notification': Unknown severity `%s'. "
63 "Will use `FAILURE' instead.",
64 ci->values[0].value.string);
65 data->severity = NOTIF_FAILURE;
69 } /* }}} int tn_config_add_severity */
71 static int tn_config_add_string (char **dest, /* {{{ */
72 const oconfig_item_t *ci)
79 if ((ci->values_num != 1)
80 || (ci->values[0].type != OCONFIG_TYPE_STRING))
82 ERROR ("Target `notification': The `%s' option requires exactly one string "
83 "argument.", ci->key);
87 if (ci->values[0].value.string[0] == 0)
89 ERROR ("Target `notification': The `%s' option does not accept empty strings.",
94 temp = sstrdup (ci->values[0].value.string);
97 ERROR ("tn_config_add_string: sstrdup failed.");
105 } /* }}} int tn_config_add_string */
107 static int tn_destroy (void **user_data) /* {{{ */
111 if (user_data == NULL)
118 sfree (data->message);
122 } /* }}} int tn_destroy */
124 static int tn_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
129 data = calloc (1, sizeof (*data));
132 ERROR ("tn_create: calloc failed.");
136 data->message = NULL;
140 for (int i = 0; i < ci->children_num; i++)
142 oconfig_item_t *child = ci->children + i;
144 if (strcasecmp ("Message", child->key) == 0)
145 status = tn_config_add_string (&data->message, child);
146 else if (strcasecmp ("Severity", child->key) == 0)
147 status = tn_config_add_severity (data, child);
150 ERROR ("Target `notification': The `%s' configuration option is not understood "
151 "and will be ignored.", child->key);
159 /* Additional sanity-checking */
162 if ((data->severity != NOTIF_FAILURE)
163 && (data->severity != NOTIF_WARNING)
164 && (data->severity != NOTIF_OKAY))
166 DEBUG ("Target `notification': Setting "
167 "the default severity `WARNING'.");
168 data->severity = NOTIF_WARNING;
171 if (data->message == NULL)
173 ERROR ("Target `notification': No `Message' option has been specified. "
174 "Without it, the `Notification' target is useless.");
183 tn_destroy ((void *) &data);
189 } /* }}} int tn_create */
191 static int tn_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
192 notification_meta_t __attribute__((unused)) **meta, void **user_data)
195 notification_t n = { 0 };
196 char temp[NOTIF_MAX_MSG_LEN];
201 if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
207 ERROR ("Target `notification': Invoke: `data' is NULL.");
211 /* Initialize the structure. */
212 n.severity = data->severity;
214 sstrncpy (n.message, data->message, sizeof (n.message));
215 sstrncpy (n.host, vl->host, sizeof (n.host));
216 sstrncpy (n.plugin, vl->plugin, sizeof (n.plugin));
217 sstrncpy (n.plugin_instance, vl->plugin_instance,
218 sizeof (n.plugin_instance));
219 sstrncpy (n.type, vl->type, sizeof (n.type));
220 sstrncpy (n.type_instance, vl->type_instance,
221 sizeof (n.type_instance));
224 #define REPLACE_FIELD(t,v) \
225 if (subst_string (temp, sizeof (temp), n.message, t, v) != NULL) \
226 sstrncpy (n.message, temp, sizeof (n.message));
227 REPLACE_FIELD ("%{host}", n.host);
228 REPLACE_FIELD ("%{plugin}", n.plugin);
229 REPLACE_FIELD ("%{plugin_instance}", n.plugin_instance);
230 REPLACE_FIELD ("%{type}", n.type);
231 REPLACE_FIELD ("%{type_instance}", n.type_instance);
236 for (size_t i = 0; i < ds->ds_num; i++)
238 char template[DATA_MAX_NAME_LEN];
239 char value_str[DATA_MAX_NAME_LEN];
241 ssnprintf (template, sizeof (template), "%%{ds:%s}", ds->ds[i].name);
243 if (ds->ds[i].type != DS_TYPE_GAUGE)
245 if ((rates == NULL) && (rates_failed == 0))
247 rates = uc_get_rate (ds, vl);
253 /* If this is a gauge value, use the current value. */
254 if (ds->ds[i].type == DS_TYPE_GAUGE)
255 ssnprintf (value_str, sizeof (value_str),
256 GAUGE_FORMAT, (double) vl->values[i].gauge);
257 /* If it's a counter, try to use the current rate. This may fail, if the
258 * value has been renamed. */
259 else if (rates != NULL)
260 ssnprintf (value_str, sizeof (value_str),
261 GAUGE_FORMAT, (double) rates[i]);
262 /* Since we don't know any better, use the string `unknown'. */
264 sstrncpy (value_str, "unknown", sizeof (value_str));
266 REPLACE_FIELD (template, value_str);
270 plugin_dispatch_notification (&n);
272 return (FC_TARGET_CONTINUE);
273 } /* }}} int tn_invoke */
275 void module_register (void)
277 target_proc_t tproc = { 0 };
279 tproc.create = tn_create;
280 tproc.destroy = tn_destroy;
281 tproc.invoke = tn_invoke;
282 fc_register_target ("notification", tproc);
283 } /* module_register */
285 /* vim: set sw=2 sts=2 tw=78 et fdm=marker : */