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"
38 typedef struct tn_data_s tn_data_t;
40 static int tn_config_add_severity(tn_data_t *data, /* {{{ */
41 const oconfig_item_t *ci) {
42 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
43 ERROR("Target `notification': The `%s' option requires exactly one string "
49 if ((strcasecmp("FAILURE", ci->values[0].value.string) == 0) ||
50 (strcasecmp("CRITICAL", ci->values[0].value.string) == 0))
51 data->severity = NOTIF_FAILURE;
52 else if ((strcasecmp("WARNING", ci->values[0].value.string) == 0) ||
53 (strcasecmp("WARN", ci->values[0].value.string) == 0))
54 data->severity = NOTIF_WARNING;
55 else if (strcasecmp("OKAY", ci->values[0].value.string) == 0)
56 data->severity = NOTIF_OKAY;
58 WARNING("Target `notification': Unknown severity `%s'. "
59 "Will use `FAILURE' instead.",
60 ci->values[0].value.string);
61 data->severity = NOTIF_FAILURE;
65 } /* }}} int tn_config_add_severity */
67 static int tn_config_add_string(char **dest, /* {{{ */
68 const oconfig_item_t *ci) {
74 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
75 ERROR("Target `notification': The `%s' option requires exactly one string "
81 if (ci->values[0].value.string[0] == 0) {
83 "Target `notification': The `%s' option does not accept empty strings.",
88 temp = sstrdup(ci->values[0].value.string);
90 ERROR("tn_config_add_string: sstrdup failed.");
98 } /* }}} int tn_config_add_string */
100 static int tn_destroy(void **user_data) /* {{{ */
104 if (user_data == NULL)
111 sfree(data->message);
115 } /* }}} int tn_destroy */
117 static int tn_create(const oconfig_item_t *ci, void **user_data) /* {{{ */
122 data = calloc(1, sizeof(*data));
124 ERROR("tn_create: calloc failed.");
128 data->message = NULL;
132 for (int i = 0; i < ci->children_num; i++) {
133 oconfig_item_t *child = ci->children + i;
135 if (strcasecmp("Message", child->key) == 0)
136 status = tn_config_add_string(&data->message, child);
137 else if (strcasecmp("Severity", child->key) == 0)
138 status = tn_config_add_severity(data, child);
140 ERROR("Target `notification': The `%s' configuration option is not "
142 "and will be ignored.",
151 /* Additional sanity-checking */
152 while (status == 0) {
153 if ((data->severity != NOTIF_FAILURE) &&
154 (data->severity != NOTIF_WARNING) && (data->severity != NOTIF_OKAY)) {
155 DEBUG("Target `notification': Setting "
156 "the default severity `WARNING'.");
157 data->severity = NOTIF_WARNING;
160 if (data->message == NULL) {
161 ERROR("Target `notification': No `Message' option has been specified. "
162 "Without it, the `Notification' target is useless.");
170 tn_destroy((void *)&data);
176 } /* }}} int tn_create */
178 static int tn_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */
179 notification_meta_t __attribute__((unused)) * *meta,
182 notification_t n = {0};
183 char temp[NOTIF_MAX_MSG_LEN];
188 if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
193 ERROR("Target `notification': Invoke: `data' is NULL.");
197 /* Initialize the structure. */
198 n.severity = data->severity;
200 sstrncpy(n.message, data->message, sizeof(n.message));
201 sstrncpy(n.host, vl->host, sizeof(n.host));
202 sstrncpy(n.plugin, vl->plugin, sizeof(n.plugin));
203 sstrncpy(n.plugin_instance, vl->plugin_instance, sizeof(n.plugin_instance));
204 sstrncpy(n.type, vl->type, sizeof(n.type));
205 sstrncpy(n.type_instance, vl->type_instance, sizeof(n.type_instance));
208 #define REPLACE_FIELD(t, v) \
209 if (subst_string(temp, sizeof(temp), n.message, t, v) != NULL) \
210 sstrncpy(n.message, temp, sizeof(n.message));
211 REPLACE_FIELD("%{host}", n.host);
212 REPLACE_FIELD("%{plugin}", n.plugin);
213 REPLACE_FIELD("%{plugin_instance}", n.plugin_instance);
214 REPLACE_FIELD("%{type}", n.type);
215 REPLACE_FIELD("%{type_instance}", n.type_instance);
220 for (size_t i = 0; i < ds->ds_num; i++) {
221 char template[DATA_MAX_NAME_LEN];
222 char value_str[DATA_MAX_NAME_LEN];
224 snprintf(template, sizeof(template), "%%{ds:%s}", ds->ds[i].name);
226 if (ds->ds[i].type != DS_TYPE_GAUGE) {
227 if ((rates == NULL) && (rates_failed == 0)) {
228 rates = uc_get_rate(ds, vl);
234 /* If this is a gauge value, use the current value. */
235 if (ds->ds[i].type == DS_TYPE_GAUGE)
236 snprintf(value_str, sizeof(value_str), GAUGE_FORMAT,
237 (double)vl->values[i].gauge);
238 /* If it's a counter, try to use the current rate. This may fail, if the
239 * value has been renamed. */
240 else if (rates != NULL)
241 snprintf(value_str, sizeof(value_str), GAUGE_FORMAT, (double)rates[i]);
242 /* Since we don't know any better, use the string `unknown'. */
244 sstrncpy(value_str, "unknown", sizeof(value_str));
246 REPLACE_FIELD(template, value_str);
250 plugin_dispatch_notification(&n);
252 return FC_TARGET_CONTINUE;
253 } /* }}} int tn_invoke */
255 void module_register(void) {
256 target_proc_t tproc = {0};
258 tproc.create = tn_create;
259 tproc.destroy = tn_destroy;
260 tproc.invoke = tn_invoke;
261 fc_register_target("notification", tproc);
262 } /* module_register */