/* * int ut_report_state * * Checks if the `state' differs from the old state and creates a notification * if appropriate. * Does not fail. */ static int ut_report_state (const data_set_t *ds, const value_list_t *vl, const threshold_t *th, const gauge_t *values, int ds_index, int state) { /* {{{ */ int state_old; notification_t n; char *buf; size_t bufsize; int status; state_old = uc_get_state (ds, vl); /* If the state didn't change, only report if `persistent' is specified and * the state is not `okay'. */ if (state == state_old) { if ((th->flags & UT_FLAG_PERSIST) == 0) return (0); else if (state == STATE_OKAY) return (0); } if (state != state_old) uc_set_state (ds, vl, state); NOTIFICATION_INIT_VL (&n, vl, ds); buf = n.message; bufsize = sizeof (n.message); if (state == STATE_OKAY) n.severity = NOTIF_OKAY; else if (state == STATE_WARNING) n.severity = NOTIF_WARNING; else n.severity = NOTIF_FAILURE; n.time = vl->time; status = ssnprintf (buf, bufsize, "Host %s, plugin %s", vl->host, vl->plugin); buf += status; bufsize -= status; if (vl->plugin_instance[0] != '\0') { status = ssnprintf (buf, bufsize, " (instance %s)", vl->plugin_instance); buf += status; bufsize -= status; } status = ssnprintf (buf, bufsize, " type %s", vl->type); buf += status; bufsize -= status; if (vl->type_instance[0] != '\0') { status = ssnprintf (buf, bufsize, " (instance %s)", vl->type_instance); buf += status; bufsize -= status; } plugin_notification_meta_add_string (&n, "DataSource", ds->ds[ds_index].name); plugin_notification_meta_add_double (&n, "CurrentValue", values[ds_index]); plugin_notification_meta_add_double (&n, "WarningMin", th->warning_min); plugin_notification_meta_add_double (&n, "WarningMax", th->warning_max); plugin_notification_meta_add_double (&n, "FailureMin", th->failure_min); plugin_notification_meta_add_double (&n, "FailureMax", th->failure_max); /* Send an okay notification */ if (state == STATE_OKAY) { status = ssnprintf (buf, bufsize, ": All data sources are within range again."); buf += status; bufsize -= status; } else { double min; double max; min = (state == STATE_ERROR) ? th->failure_min : th->warning_min; max = (state == STATE_ERROR) ? th->failure_max : th->warning_max; if (th->flags & UT_FLAG_INVERT) { if (!isnan (min) && !isnan (max)) { status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently " "%f. That is within the %s region of %f and %f.", ds->ds[ds_index].name, values[ds_index], (state == STATE_ERROR) ? "failure" : "warning", min, max); } else { status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently " "%f. That is %s the %s threshold of %f.", ds->ds[ds_index].name, values[ds_index], isnan (min) ? "below" : "above", (state == STATE_ERROR) ? "failure" : "warning", isnan (min) ? max : min); } } else /* is not inverted */ { status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently " "%f. That is %s the %s threshold of %f.", ds->ds[ds_index].name, values[ds_index], (values[ds_index] < min) ? "below" : "above", (state == STATE_ERROR) ? "failure" : "warning", (values[ds_index] < min) ? min : max); } buf += status; bufsize -= status; } plugin_dispatch_notification (&n); plugin_notification_meta_free (n.meta); return (0); } /* }}} int ut_report_state */
/* * int ut_report_state * * Checks if the `state' differs from the old state and creates a notification * if appropriate. * Does not fail. */ static int ut_report_state(const data_set_t *ds, const value_list_t *vl, const threshold_t *th, const gauge_t *values, int ds_index, int state) { /* {{{ */ int state_old; notification_t n; char *buf; size_t bufsize; int status; /* Check if hits matched */ if ((th->hits != 0)) { int hits = uc_get_hits(ds, vl); /* STATE_OKAY resets hits unless PERSIST_OK flag is set. Hits resets if * threshold is hit. */ if (((state == STATE_OKAY) && ((th->flags & UT_FLAG_PERSIST_OK) == 0)) || (hits > th->hits)) { DEBUG("ut_report_state: reset uc_get_hits = 0"); uc_set_hits(ds, vl, 0); /* reset hit counter and notify */ } else { DEBUG("ut_report_state: th->hits = %d, uc_get_hits = %d", th->hits, uc_get_hits(ds, vl)); (void)uc_inc_hits(ds, vl, 1); /* increase hit counter */ return 0; } } /* end check hits */ state_old = uc_get_state(ds, vl); /* If the state didn't change, report if `persistent' is specified. If the * state is `okay', then only report if `persist_ok` flag is set. */ if (state == state_old) { if ((th->flags & UT_FLAG_PERSIST) == 0) return 0; else if ((state == STATE_OKAY) && ((th->flags & UT_FLAG_PERSIST_OK) == 0)) return 0; } if (state != state_old) uc_set_state(ds, vl, state); NOTIFICATION_INIT_VL(&n, vl); buf = n.message; bufsize = sizeof(n.message); if (state == STATE_OKAY) n.severity = NOTIF_OKAY; else if (state == STATE_WARNING) n.severity = NOTIF_WARNING; else n.severity = NOTIF_FAILURE; n.time = vl->time; status = snprintf(buf, bufsize, "Host %s, plugin %s", vl->host, vl->plugin); buf += status; bufsize -= status; if (vl->plugin_instance[0] != '\0') { status = snprintf(buf, bufsize, " (instance %s)", vl->plugin_instance); buf += status; bufsize -= status; } status = snprintf(buf, bufsize, " type %s", vl->type); buf += status; bufsize -= status; if (vl->type_instance[0] != '\0') { status = snprintf(buf, bufsize, " (instance %s)", vl->type_instance); buf += status; bufsize -= status; } plugin_notification_meta_add_string(&n, "DataSource", ds->ds[ds_index].name); plugin_notification_meta_add_double(&n, "CurrentValue", values[ds_index]); plugin_notification_meta_add_double(&n, "WarningMin", th->warning_min); plugin_notification_meta_add_double(&n, "WarningMax", th->warning_max); plugin_notification_meta_add_double(&n, "FailureMin", th->failure_min); plugin_notification_meta_add_double(&n, "FailureMax", th->failure_max); /* Send an okay notification */ if (state == STATE_OKAY) { if (state_old == STATE_MISSING) snprintf(buf, bufsize, ": Value is no longer missing."); else snprintf(buf, bufsize, ": All data sources are within range again. " "Current value of \"%s\" is %f.", ds->ds[ds_index].name, values[ds_index]); } else { double min; double max; min = (state == STATE_ERROR) ? th->failure_min : th->warning_min; max = (state == STATE_ERROR) ? th->failure_max : th->warning_max; if (th->flags & UT_FLAG_INVERT) { if (!isnan(min) && !isnan(max)) { snprintf(buf, bufsize, ": Data source \"%s\" is currently " "%f. That is within the %s region of %f%s and %f%s.", ds->ds[ds_index].name, values[ds_index], (state == STATE_ERROR) ? "failure" : "warning", min, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "", max, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : ""); } else { snprintf(buf, bufsize, ": Data source \"%s\" is currently " "%f. That is %s the %s threshold of %f%s.", ds->ds[ds_index].name, values[ds_index], isnan(min) ? "below" : "above", (state == STATE_ERROR) ? "failure" : "warning", isnan(min) ? max : min, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : ""); } } else if (th->flags & UT_FLAG_PERCENTAGE) { gauge_t value; gauge_t sum; sum = 0.0; for (size_t i = 0; i < vl->values_len; i++) { if (isnan(values[i])) continue; sum += values[i]; } if (sum == 0.0) value = NAN; else value = 100.0 * values[ds_index] / sum; snprintf(buf, bufsize, ": Data source \"%s\" is currently " "%g (%.2f%%). That is %s the %s threshold of %.2f%%.", ds->ds[ds_index].name, values[ds_index], value, (value < min) ? "below" : "above", (state == STATE_ERROR) ? "failure" : "warning", (value < min) ? min : max); } else /* is not inverted */ { snprintf(buf, bufsize, ": Data source \"%s\" is currently " "%f. That is %s the %s threshold of %f.", ds->ds[ds_index].name, values[ds_index], (values[ds_index] < min) ? "below" : "above", (state == STATE_ERROR) ? "failure" : "warning", (values[ds_index] < min) ? min : max); } } plugin_dispatch_notification(&n); plugin_notification_meta_free(n.meta); return 0; } /* }}} int ut_report_state */
int uc_update (const data_set_t *ds, const value_list_t *vl) { char name[6 * DATA_MAX_NAME_LEN]; cache_entry_t *ce = NULL; int send_okay_notification = 0; time_t update_delay = 0; notification_t n; int status; int i; if (FORMAT_VL (name, sizeof (name), vl) != 0) { ERROR ("uc_update: FORMAT_VL failed."); return (-1); } pthread_mutex_lock (&cache_lock); status = c_avl_get (cache_tree, name, (void *) &ce); if (status != 0) /* entry does not yet exist */ { status = uc_insert (ds, vl, name); pthread_mutex_unlock (&cache_lock); return (status); } assert (ce != NULL); assert (ce->values_num == ds->ds_num); if (ce->last_time >= vl->time) { pthread_mutex_unlock (&cache_lock); NOTICE ("uc_update: Value too old: name = %s; value time = %u; " "last cache update = %u;", name, (unsigned int) vl->time, (unsigned int) ce->last_time); return (-1); } /* Send a notification (after the lock has been released) if we switch the * state from something else to `okay'. */ if (ce->state == STATE_MISSING) { send_okay_notification = 1; ce->state = STATE_OKAY; update_delay = time (NULL) - ce->last_update; } for (i = 0; i < ds->ds_num; i++) { switch (ds->ds[i].type) { case DS_TYPE_COUNTER: { counter_t diff; /* check if the counter has wrapped around */ if (vl->values[i].counter < ce->values_raw[i].counter) { if (ce->values_raw[i].counter <= 4294967295U) diff = (4294967295U - ce->values_raw[i].counter) + vl->values[i].counter; else diff = (18446744073709551615ULL - ce->values_raw[i].counter) + vl->values[i].counter; } else /* counter has NOT wrapped around */ { diff = vl->values[i].counter - ce->values_raw[i].counter; } ce->values_gauge[i] = ((double) diff) / ((double) (vl->time - ce->last_time)); ce->values_raw[i].counter = vl->values[i].counter; } break; case DS_TYPE_GAUGE: ce->values_raw[i].gauge = vl->values[i].gauge; ce->values_gauge[i] = vl->values[i].gauge; break; case DS_TYPE_DERIVE: { derive_t diff; diff = vl->values[i].derive - ce->values_raw[i].derive; ce->values_gauge[i] = ((double) diff) / ((double) (vl->time - ce->last_time)); ce->values_raw[i].derive = vl->values[i].derive; } break; case DS_TYPE_ABSOLUTE: ce->values_gauge[i] = ((double) vl->values[i].absolute) / ((double) (vl->time - ce->last_time)); ce->values_raw[i].absolute = vl->values[i].absolute; break; default: /* This shouldn't happen. */ pthread_mutex_unlock (&cache_lock); ERROR ("uc_update: Don't know how to handle data source type %i.", ds->ds[i].type); return (-1); } /* switch (ds->ds[i].type) */ DEBUG ("uc_update: %s: ds[%i] = %lf", name, i, ce->values_gauge[i]); } /* for (i) */ /* Update the history if it exists. */ if (ce->history != NULL) { assert (ce->history_index < ce->history_length); for (i = 0; i < ce->values_num; i++) { size_t hist_idx = (ce->values_num * ce->history_index) + i; ce->history[hist_idx] = ce->values_gauge[i]; } assert (ce->history_length > 0); ce->history_index = (ce->history_index + 1) % ce->history_length; } /* Prune invalid gauge data */ uc_check_range (ds, ce); ce->last_time = vl->time; ce->last_update = time (NULL); ce->interval = vl->interval; pthread_mutex_unlock (&cache_lock); if (send_okay_notification == 0) return (0); /* Do not send okay notifications for uninteresting values, i. e. values for * which no threshold is configured. */ status = ut_check_interesting (name); if (status <= 0) return (0); /* Initialize the notification */ memset (&n, '\0', sizeof (n)); NOTIFICATION_INIT_VL (&n, vl, ds); n.severity = NOTIF_OKAY; n.time = vl->time; ssnprintf (n.message, sizeof (n.message), "Received a value for %s. It was missing for %u seconds.", name, (unsigned int) update_delay); plugin_dispatch_notification (&n); return (0); } /* int uc_update */