2 * collectd - src/check_uptime.c
3 * Copyright (C) 2007-2019 Florian Forster
4 * Copyright (C) 2019 Pavel V. Rochnyack
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; only version 2 of the License is applicable.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Florian octo Forster <octo at collectd.org>
21 * Pavel Rochnyak <pavel2000 ngs.ru>
26 #include "utils/avltree/avltree.h"
27 #include "utils/common/common.h"
28 #include "utils_cache.h"
30 /* Types are registered only in `config` phase, so access is not protected by
32 c_avl_tree_t *types_tree = NULL;
34 static int format_uptime(unsigned long uptime_sec, char *buf, size_t bufsize) {
36 unsigned int uptime_days = uptime_sec / 24 / 3600;
37 uptime_sec -= uptime_days * 24 * 3600;
38 unsigned int uptime_hours = uptime_sec / 3600;
39 uptime_sec -= uptime_hours * 3600;
40 unsigned int uptime_mins = uptime_sec / 60;
41 uptime_sec -= uptime_mins * 60;
45 ret += snprintf(buf + ret, bufsize - ret, " %u day(s)", uptime_days);
47 if (uptime_days || uptime_hours) {
48 ret += snprintf(buf + ret, bufsize - ret, " %u hour(s)", uptime_hours);
50 if (uptime_days || uptime_hours || uptime_mins) {
51 ret += snprintf(buf + ret, bufsize - ret, " %u min", uptime_mins);
53 ret += snprintf(buf + ret, bufsize - ret, " %lu sec.", uptime_sec);
57 static int cu_notify(enum cache_event_type_e event_type, const value_list_t *vl,
58 gauge_t old_uptime, gauge_t new_uptime) {
60 NOTIFICATION_INIT_VL(&n, vl);
63 char *buf = n.message;
64 size_t bufsize = sizeof(n.message);
68 const char *service = "Service";
69 if (strcmp(vl->plugin, "uptime") == 0)
74 n.severity = NOTIF_OKAY;
75 status = snprintf(buf, bufsize, "%s is running.", service);
80 n.severity = NOTIF_WARNING;
81 status = snprintf(buf, bufsize, "%s just restarted.", service);
85 case CE_VALUE_EXPIRED:
86 n.severity = NOTIF_FAILURE;
87 status = snprintf(buf, bufsize, "%s is unreachable.", service);
93 if (!isnan(old_uptime)) {
94 status = snprintf(buf, bufsize, " Uptime was:");
98 status = format_uptime(old_uptime, buf, bufsize);
102 plugin_notification_meta_add_double(&n, "LastValue", old_uptime);
105 if (!isnan(new_uptime)) {
106 status = snprintf(buf, bufsize, " Uptime now:");
110 status = format_uptime(new_uptime, buf, bufsize);
114 plugin_notification_meta_add_double(&n, "CurrentValue", new_uptime);
117 plugin_dispatch_notification(&n);
119 plugin_notification_meta_free(n.meta);
123 static int cu_cache_event(cache_event_t *event,
124 __attribute__((unused)) user_data_t *ud) {
125 gauge_t values_history[2];
127 /* For CE_VALUE_EXPIRED */
131 gauge_t old_uptime = NAN;
133 switch (event->type) {
135 DEBUG("check_uptime: CE_VALUE_NEW, %s", event->value_list_name);
136 if (c_avl_get(types_tree, event->value_list->type, NULL) == 0) {
138 assert(event->value_list->values_len > 0);
139 cu_notify(CE_VALUE_NEW, event->value_list, NAN /* old */,
140 event->value_list->values[0].gauge /* new */);
143 case CE_VALUE_UPDATE:
144 DEBUG("check_uptime: CE_VALUE_UPDATE, %s", event->value_list_name);
145 if (uc_get_history_by_name(event->value_list_name, values_history, 2, 1)) {
146 ERROR("check_uptime plugin: Failed to get value history for %s.",
147 event->value_list_name);
149 if (!isnan(values_history[0]) && !isnan(values_history[1]) &&
150 values_history[0] < values_history[1]) {
151 cu_notify(CE_VALUE_UPDATE, event->value_list,
152 values_history[1] /* old */, values_history[0] /* new */);
156 case CE_VALUE_EXPIRED:
157 DEBUG("check_uptime: CE_VALUE_EXPIRED, %s", event->value_list_name);
158 ret = uc_get_value_by_name(event->value_list_name, &values, &values_num);
160 old_uptime = values[0].gauge;
164 cu_notify(CE_VALUE_EXPIRED, event->value_list, old_uptime, NAN /* new */);
170 static int cu_config(oconfig_item_t *ci) {
171 if (types_tree == NULL) {
172 types_tree = c_avl_create((int (*)(const void *, const void *))strcmp);
173 if (types_tree == NULL) {
174 ERROR("check_uptime plugin: c_avl_create failed.");
179 for (int i = 0; i < ci->children_num; ++i) {
180 oconfig_item_t *child = ci->children + i;
181 if (strcasecmp("Type", child->key) == 0) {
182 if ((child->values_num != 1) ||
183 (child->values[0].type != OCONFIG_TYPE_STRING)) {
184 WARNING("check_uptime plugin: The `Type' option needs exactly one "
188 char *type = child->values[0].value.string;
190 if (c_avl_get(types_tree, type, NULL) == 0) {
191 ERROR("check_uptime plugin: Type `%s' already added.", type);
195 char *type_copy = strdup(type);
196 if (type_copy == NULL) {
197 ERROR("check_uptime plugin: strdup failed.");
201 int status = c_avl_insert(types_tree, type_copy, NULL);
203 ERROR("check_uptime plugin: c_avl_insert failed.");
208 WARNING("check_uptime plugin: Ignore unknown config option `%s'.",
215 static int cu_init(void) {
216 if (types_tree == NULL) {
217 types_tree = c_avl_create((int (*)(const void *, const void *))strcmp);
218 if (types_tree == NULL) {
219 ERROR("check_uptime plugin: c_avl_create failed.");
222 /* Default configuration */
223 char *type = strdup("uptime");
225 ERROR("check_uptime plugin: strdup failed.");
228 int status = c_avl_insert(types_tree, type, NULL);
230 ERROR("check_uptime plugin: c_avl_insert failed.");
239 c_avl_iterator_t *iter = c_avl_get_iterator(types_tree);
240 while (c_avl_iterator_next(iter, (void *)&type, (void *)&val) == 0) {
241 data_set_t const *ds = plugin_get_ds(type);
243 ERROR("check_uptime plugin: Failed to look up type \"%s\".", type);
247 if (ds->ds_num != 1) {
248 ERROR("check_uptime plugin: The type \"%s\" has %" PRIsz " data sources. "
249 "Only types with a single GAUGE data source are supported.",
250 ds->type, ds->ds_num);
254 if (ds->ds[0].type != DS_TYPE_GAUGE) {
255 ERROR("check_uptime plugin: The type \"%s\" has wrong data source type. "
256 "Only types with a single GAUGE data source are supported.",
262 c_avl_iterator_destroy(iter);
265 plugin_register_cache_event("check_uptime", cu_cache_event, NULL);
270 void module_register(void) {
271 plugin_register_complex_config("check_uptime", cu_config);
272 plugin_register_init("check_uptime", cu_init);