1
// SPDX-License-Identifier: GPL-3.0-or-later
2
3
#include "health.h"
4
+#include "health_internals.h"
5
5
-#define WORKER_HEALTH_JOB_RRD_LOCK 0
6
-#define WORKER_HEALTH_JOB_HOST_LOCK 1
7
-#define WORKER_HEALTH_JOB_DB_QUERY 2
8
-#define WORKER_HEALTH_JOB_CALC_EVAL 3
9
-#define WORKER_HEALTH_JOB_WARNING_EVAL 4
10
-#define WORKER_HEALTH_JOB_CRITICAL_EVAL 5
11
-#define WORKER_HEALTH_JOB_ALARM_LOG_ENTRY 6
12
-#define WORKER_HEALTH_JOB_ALARM_LOG_PROCESS 7
13
-#define WORKER_HEALTH_JOB_DELAYED_INIT_RRDSET 8
14
-#define WORKER_HEALTH_JOB_DELAYED_INIT_RRDDIM 9
6
+struct health_plugin_globals health_globals = {
7
+ .initialization = {
8
+ .spinlock = NETDATA_SPINLOCK_INITIALIZER,
9
+ .done = false,
10
+ },
11
+ .config = {
12
+ .enabled = true,
13
+ .stock_enabled = true,
14
+ .use_summary_for_notifications = true,
15
16
-#if WORKER_UTILIZATION_MAX_JOB_TYPES < 10
17
-#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 10
18
-#endif
16
+ .health_log_entries_max = HEALTH_LOG_ENTRIES_DEFAULT,
17
+ .health_log_history = HEALTH_LOG_HISTORY_DEFAULT,
18
20
-unsigned int default_health_enabled = 1;
21
-char *silencers_filename;
22
-SIMPLE_PATTERN *conf_enabled_alarms = NULL;
23
-DICTIONARY *health_rrdvars;
19
+ .default_warn_repeat_every = 0,
20
+ .default_crit_repeat_every = 0,
21
25
-bool health_alarm_log_get_global_id_and_transition_id_for_rrdcalc(RRDCALC *rc, usec_t *global_id, uuid_t *transitions_id) {
26
- if(!rc->rrdset)
27
- return false;
28
-
29
- RRDHOST *host = rc->rrdset->rrdhost;
30
-
31
- rw_spinlock_read_lock(&host->health_log.spinlock);
32
-
33
- ALARM_ENTRY *ae;
34
- for(ae = host->health_log.alarms; ae ; ae = ae->next) {
35
- if(unlikely(ae->alarm_id == rc->id))
36
- break;
37
- }
38
-
39
- if(ae) {
40
- *global_id = ae->global_id;
41
- uuid_copy(*transitions_id, ae->transition_id);
42
- }
43
- else {
44
- *global_id = 0;
45
- uuid_clear(*transitions_id);
22
+ .run_at_least_every_seconds = 10,
23
+ .postpone_alarms_during_hibernation_for_seconds = 60,
24
+ },
25
+ .prototypes = {
26
+ .dict = NULL,
27
}
28
+};
29
48
- rw_spinlock_read_unlock(&host->health_log.spinlock);
49
-
50
- return ae != NULL;
30
+bool health_plugin_enabled(void) {
31
+ return health_globals.config.enabled;
32
}
33
53
-void health_entry_flags_to_json_array(BUFFER *wb, const char *key, HEALTH_ENTRY_FLAGS flags) {
54
- buffer_json_member_add_array(wb, key);
55
-
56
- if(flags & HEALTH_ENTRY_FLAG_PROCESSED)
57
- buffer_json_add_array_item_string(wb, "PROCESSED");
58
- if(flags & HEALTH_ENTRY_FLAG_UPDATED)
59
- buffer_json_add_array_item_string(wb, "UPDATED");
60
- if(flags & HEALTH_ENTRY_FLAG_EXEC_RUN)
61
- buffer_json_add_array_item_string(wb, "EXEC_RUN");
62
- if(flags & HEALTH_ENTRY_FLAG_EXEC_FAILED)
63
- buffer_json_add_array_item_string(wb, "EXEC_FAILED");
64
- if(flags & HEALTH_ENTRY_FLAG_SILENCED)
65
- buffer_json_add_array_item_string(wb, "SILENCED");
66
- if(flags & HEALTH_ENTRY_RUN_ONCE)
67
- buffer_json_add_array_item_string(wb, "RUN_ONCE");
68
- if(flags & HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS)
69
- buffer_json_add_array_item_string(wb, "EXEC_IN_PROGRESS");
70
- if(flags & HEALTH_ENTRY_FLAG_IS_REPEATING)
71
- buffer_json_add_array_item_string(wb, "RECURRING");
72
- if(flags & HEALTH_ENTRY_FLAG_SAVED)
73
- buffer_json_add_array_item_string(wb, "SAVED");
74
- if(flags & HEALTH_ENTRY_FLAG_ACLK_QUEUED)
75
- buffer_json_add_array_item_string(wb, "ACLK_QUEUED");
76
- if(flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)
77
- buffer_json_add_array_item_string(wb, "NO_CLEAR_NOTIFICATION");
78
-
79
- buffer_json_array_close(wb);
34
+void health_plugin_disable(void) {
35
+ health_globals.config.enabled = false;
36
}
37
82
-static bool prepare_command(BUFFER *wb,
83
- const char *exec,
84
- const char *recipient,
85
- const char *registry_hostname,
86
- uint32_t unique_id,
87
- uint32_t alarm_id,
88
- uint32_t alarm_event_id,
89
- uint32_t when,
90
- const char *alert_name,
91
- const char *alert_chart_name,
92
- const char *new_status,
93
- const char *old_status,
94
- NETDATA_DOUBLE new_value,
95
- NETDATA_DOUBLE old_value,
96
- const char *alert_source,
97
- uint32_t duration,
98
- uint32_t non_clear_duration,
99
- const char *alert_units,
100
- const char *alert_info,
101
- const char *new_value_string,
102
- const char *old_value_string,
103
- const char *source,
104
- const char *error_msg,
105
- int n_warn,
106
- int n_crit,
107
- const char *warn_alarms,
108
- const char *crit_alarms,
109
- const char *classification,
110
- const char *edit_command,
111
- const char *machine_guid,
112
- uuid_t *transition_id,
113
- const char *summary,
114
- const char *context,
115
- const char *component,
116
- const char *type
117
-) {
118
- char buf[8192];
119
- size_t n = sizeof(buf) - 1;
120
-
121
- buffer_strcat(wb, "exec");
122
-
123
- if (!sanitize_command_argument_string(buf, exec, n))
124
- return false;
125
- buffer_sprintf(wb, " '%s'", buf);
126
-
127
- if (!sanitize_command_argument_string(buf, recipient, n))
128
- return false;
129
- buffer_sprintf(wb, " '%s'", buf);
130
-
131
- if (!sanitize_command_argument_string(buf, registry_hostname, n))
132
- return false;
133
- buffer_sprintf(wb, " '%s'", buf);
134
-
135
- buffer_sprintf(wb, " '%u'", unique_id);
136
-
137
- buffer_sprintf(wb, " '%u'", alarm_id);
138
-
139
- buffer_sprintf(wb, " '%u'", alarm_event_id);
140
-
141
- buffer_sprintf(wb, " '%u'", when);
142
-
143
- if (!sanitize_command_argument_string(buf, alert_name, n))
144
- return false;
145
- buffer_sprintf(wb, " '%s'", buf);
146
-
147
- if (!sanitize_command_argument_string(buf, alert_chart_name, n))
148
- return false;
149
- buffer_sprintf(wb, " '%s'", buf);
150
-
151
- if (!sanitize_command_argument_string(buf, new_status, n))
152
- return false;
153
- buffer_sprintf(wb, " '%s'", buf);
154
-
155
- if (!sanitize_command_argument_string(buf, old_status, n))
156
- return false;
157
- buffer_sprintf(wb, " '%s'", buf);
38
159
- buffer_sprintf(wb, " '" NETDATA_DOUBLE_FORMAT_ZERO "'", new_value);
160
-
161
- buffer_sprintf(wb, " '" NETDATA_DOUBLE_FORMAT_ZERO "'", old_value);
162
-
163
- if (!sanitize_command_argument_string(buf, alert_source, n))
164
- return false;
165
- buffer_sprintf(wb, " '%s'", buf);
166
-
167
- buffer_sprintf(wb, " '%u'", duration);
168
-
169
- buffer_sprintf(wb, " '%u'", non_clear_duration);
170
-
171
- if (!sanitize_command_argument_string(buf, alert_units, n))
172
- return false;
173
- buffer_sprintf(wb, " '%s'", buf);
174
-
175
- if (!sanitize_command_argument_string(buf, alert_info, n))
176
- return false;
177
- buffer_sprintf(wb, " '%s'", buf);
178
-
179
- if (!sanitize_command_argument_string(buf, new_value_string, n))
180
- return false;
181
- buffer_sprintf(wb, " '%s'", buf);
182
-
183
- if (!sanitize_command_argument_string(buf, old_value_string, n))
184
- return false;
185
- buffer_sprintf(wb, " '%s'", buf);
186
-
187
- if (!sanitize_command_argument_string(buf, source, n))
188
- return false;
189
- buffer_sprintf(wb, " '%s'", buf);
190
-
191
- if (!sanitize_command_argument_string(buf, error_msg, n))
192
- return false;
193
- buffer_sprintf(wb, " '%s'", buf);
39
+static void health_load_config_defaults(void) {
40
+ char filename[FILENAME_MAX + 1];
41
195
- buffer_sprintf(wb, " '%d'", n_warn);
42
+ health_globals.config.enabled =
43
+ config_get_boolean(CONFIG_SECTION_HEALTH,
44
+ "enabled",
45
+ health_globals.config.enabled);
46
197
- buffer_sprintf(wb, " '%d'", n_crit);
47
+ health_globals.config.stock_enabled =
48
+ config_get_boolean(CONFIG_SECTION_HEALTH,
49
+ "enable stock health configuration",
50
+ health_globals.config.stock_enabled);
51
199
- if (!sanitize_command_argument_string(buf, warn_alarms, n))
200
- return false;
201
- buffer_sprintf(wb, " '%s'", buf);
52
+ health_globals.config.use_summary_for_notifications =
53
+ config_get_boolean(CONFIG_SECTION_HEALTH,
54
+ "use summary for notifications",
55
+ health_globals.config.use_summary_for_notifications);
56
203
- if (!sanitize_command_argument_string(buf, crit_alarms, n))
204
- return false;
205
- buffer_sprintf(wb, " '%s'", buf);
57
+ health_globals.config.default_warn_repeat_every =
58
+ config_get_duration(CONFIG_SECTION_HEALTH, "default repeat warning", "never");
59
207
- if (!sanitize_command_argument_string(buf, classification, n))
208
- return false;
209
- buffer_sprintf(wb, " '%s'", buf);
60
+ health_globals.config.default_crit_repeat_every =
61
+ config_get_duration(CONFIG_SECTION_HEALTH, "default repeat critical", "never");
62
211
- if (!sanitize_command_argument_string(buf, edit_command, n))
212
- return false;
213
- buffer_sprintf(wb, " '%s'", buf);
63
+ health_globals.config.health_log_entries_max =
64
+ config_get_number(CONFIG_SECTION_HEALTH, "in memory max health log entries",
65
+ health_globals.config.health_log_entries_max);
66
215
- if (!sanitize_command_argument_string(buf, machine_guid, n))
216
- return false;
217
- buffer_sprintf(wb, " '%s'", buf);
67
+ health_globals.config.health_log_history =
68
+ config_get_number(CONFIG_SECTION_HEALTH, "health log history", HEALTH_LOG_DEFAULT_HISTORY);
69
219
- char tr_id[UUID_STR_LEN];
220
- uuid_unparse_lower(*transition_id, tr_id);
221
- if (!sanitize_command_argument_string(buf, tr_id, n))
222
- return false;
223
- buffer_sprintf(wb, " '%s'", buf);
70
+ snprintfz(filename, FILENAME_MAX, "%s/alarm-notify.sh", netdata_configured_primary_plugins_dir);
71
+ health_globals.config.default_exec =
72
+ string_strdupz(config_get(CONFIG_SECTION_HEALTH, "script to execute on alarm", filename));
73
225
- if (!sanitize_command_argument_string(buf, summary, n))
226
- return false;
227
- buffer_sprintf(wb, " '%s'", buf);
74
+ health_globals.config.enabled_alerts =
75
+ simple_pattern_create(config_get(CONFIG_SECTION_HEALTH, "enabled alarms", "*"),
76
+ NULL, SIMPLE_PATTERN_EXACT, true);
77
229
- if (!sanitize_command_argument_string(buf, context, n))
230
- return false;
231
- buffer_sprintf(wb, " '%s'", buf);
78
+ health_globals.config.run_at_least_every_seconds =
79
+ (int)config_get_number(CONFIG_SECTION_HEALTH,
80
+ "run at least every seconds",
81
+ health_globals.config.run_at_least_every_seconds);
82
233
- if (!sanitize_command_argument_string(buf, component, n))
234
- return false;
235
- buffer_sprintf(wb, " '%s'", buf);
83
+ health_globals.config.postpone_alarms_during_hibernation_for_seconds =
84
+ config_get_number(CONFIG_SECTION_HEALTH,
85
+ "postpone alarms during hibernation for seconds",
86
+ health_globals.config.postpone_alarms_during_hibernation_for_seconds);
87
237
- if (!sanitize_command_argument_string(buf, type, n))
238
- return false;
239
- buffer_sprintf(wb, " '%s'", buf);
88
+ health_globals.config.default_recipient =
89
+ string_strdupz("root");
90
241
- return true;
242
-}
243
-
244
-// the queue of executed alarm notifications that haven't been waited for yet
245
-static struct {
246
- ALARM_ENTRY *head; // oldest
247
- ALARM_ENTRY *tail; // latest
248
-} alarm_notifications_in_progress = {NULL, NULL};
91
+ // ------------------------------------------------------------------------
92
+ // verify after loading
93
250
-typedef struct active_alerts {
251
- char *name;
252
- time_t last_status_change;
253
- RRDCALC_STATUS status;
254
-} active_alerts_t;
94
+ if(health_globals.config.run_at_least_every_seconds < 1)
95
+ health_globals.config.run_at_least_every_seconds = 1;
96
256
-static inline void enqueue_alarm_notify_in_progress(ALARM_ENTRY *ae)
257
-{
258
- ae->prev_in_progress = NULL;
259
- ae->next_in_progress = NULL;
97
+ if(health_globals.config.health_log_entries_max < HEALTH_LOG_ENTRIES_MIN) {
98
+ nd_log(NDLS_DAEMON, NDLP_WARNING,
99
+ "Health configuration has invalid max log entries %u, using minimum of %u",
100
+ health_globals.config.health_log_entries_max,
101
+ HEALTH_LOG_ENTRIES_MIN);
102
261
- if (NULL != alarm_notifications_in_progress.tail) {
262
- ae->prev_in_progress = alarm_notifications_in_progress.tail;
263
- alarm_notifications_in_progress.tail->next_in_progress = ae;
264
- }
265
- if (NULL == alarm_notifications_in_progress.head) {
266
- alarm_notifications_in_progress.head = ae;
103
+ health_globals.config.health_log_entries_max = HEALTH_LOG_ENTRIES_MIN;
104
+ config_set_number(CONFIG_SECTION_HEALTH, "in memory max health log entries",
105
+ (long)health_globals.config.health_log_entries_max);
106
}
268
- alarm_notifications_in_progress.tail = ae;
107
+ else if(health_globals.config.health_log_entries_max > HEALTH_LOG_ENTRIES_MAX) {
108
+ nd_log(NDLS_DAEMON, NDLP_WARNING,
109
+ "Health configuration has invalid max log entries %u, using maximum of %u",
110
+ health_globals.config.health_log_entries_max,
111
+ HEALTH_LOG_ENTRIES_MAX);
112
270
-}
113
+ health_globals.config.health_log_entries_max = HEALTH_LOG_ENTRIES_MAX;
114
+ config_set_number(CONFIG_SECTION_HEALTH, "in memory max health log entries",
115
+ (long)health_globals.config.health_log_entries_max);
116
+ }
117
272
-static inline void unlink_alarm_notify_in_progress(ALARM_ENTRY *ae)
273
-{
274
- struct alarm_entry *prev = ae->prev_in_progress;
275
- struct alarm_entry *next = ae->next_in_progress;
118
+ if (health_globals.config.health_log_history < HEALTH_LOG_MINIMUM_HISTORY) {
119
+ nd_log(NDLS_DAEMON, NDLP_WARNING,
120
+ "Health configuration has invalid health log history %u. Using minimum %d",
121
+ health_globals.config.health_log_history, HEALTH_LOG_MINIMUM_HISTORY);
122
277
- if (NULL != prev) {
278
- prev->next_in_progress = next;
279
- }
280
- if (NULL != next) {
281
- next->prev_in_progress = prev;
282
- }
283
- if (ae == alarm_notifications_in_progress.head) {
284
- alarm_notifications_in_progress.head = next;
285
- }
286
- if (ae == alarm_notifications_in_progress.tail) {
287
- alarm_notifications_in_progress.tail = prev;
123
+ health_globals.config.health_log_history = HEALTH_LOG_MINIMUM_HISTORY;
124
+ config_set_number(CONFIG_SECTION_HEALTH, "health log history", health_globals.config.health_log_history);
125
}
126
+
127
+ nd_log(NDLS_DAEMON, NDLP_DEBUG,
128
+ "Health log history is set to %u seconds (%u days)",
129
+ health_globals.config.health_log_history, health_globals.config.health_log_history / 86400);
130
}
290
-// ----------------------------------------------------------------------------
291
-// health initialization
131
293
-/**
294
- * User Config directory
295
- *
296
- * Get the config directory for health and return it.
297
- *
298
- * @return a pointer to the user config directory
299
- */
132
inline char *health_user_config_dir(void) {
133
char buffer[FILENAME_MAX + 1];
134
snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_user_config_dir);
135
return config_get(CONFIG_SECTION_DIRECTORIES, "health config", buffer);
136
}
137
306
-/**
307
- * Stock Config Directory
308
- *
309
- * Get the Stock config directory and return it.
310
- *
311
- * @return a pointer to the stock config directory.
312
- */
138
inline char *health_stock_config_dir(void) {
139
char buffer[FILENAME_MAX + 1];
140
snprintfz(buffer, FILENAME_MAX, "%s/health.d", netdata_configured_stock_config_dir);
141
return config_get(CONFIG_SECTION_DIRECTORIES, "stock health config", buffer);
142
}
143
319
-/**
320
- * Silencers init
321
- *
322
- * Function used to initialize the silencer structure.
323
- */
324
-static void health_silencers_init(void) {
325
- FILE *fd = fopen(silencers_filename, "r");
326
- if (fd) {
327
- fseek(fd, 0 , SEEK_END);
328
- off_t length = (off_t) ftell(fd);
329
- fseek(fd, 0 , SEEK_SET);
330
-
331
- if (length > 0 && length < HEALTH_SILENCERS_MAX_FILE_LEN) {
332
- char *str = mallocz((length+1)* sizeof(char));
333
- if(str) {
334
- size_t copied;
335
- copied = fread(str, sizeof(char), length, fd);
336
- if (copied == (length* sizeof(char))) {
337
- str[length] = 0x00;
338
- json_parse(str, NULL, health_silencers_json_read_callback);
339
- netdata_log_info("Parsed health silencers file %s", silencers_filename);
340
- } else {
341
- netdata_log_error("Cannot read the data from health silencers file %s", silencers_filename);
342
- }
343
- freez(str);
344
- }
345
- } else {
346
- netdata_log_error("Health silencers file %s has the size %" PRId64 " that is out of range[ 1 , %d ]. Aborting read.",
347
- silencers_filename,
348
- (int64_t)length,
349
- HEALTH_SILENCERS_MAX_FILE_LEN);
350
- }
351
- fclose(fd);
352
- } else {
353
- netdata_log_info("Cannot open the file %s, so Netdata will work with the default health configuration.",
354
- silencers_filename);
355
- }
356
-}
357
-
358
-/**
359
- * Health Init
360
- *
361
- * Initialize the health thread.
362
- */
363
-void health_init(void) {
364
- netdata_log_debug(D_HEALTH, "Health configuration initializing");
365
-
366
- if(!(default_health_enabled = (unsigned int)config_get_boolean(CONFIG_SECTION_HEALTH, "enabled", default_health_enabled))) {
367
- netdata_log_debug(D_HEALTH, "Health is disabled.");
368
- return;
369
- }
370
-
371
- health_silencers_init();
372
-}
373
-
374
-// ----------------------------------------------------------------------------
375
-// re-load health configuration
376
-
377
-/**
378
- * Reload host
379
- *
380
- * Reload configuration for a specific host.
381
- *
382
- * @param host the structure of the host that the function will reload the configuration.
383
- */
384
-static void health_reload_host(RRDHOST *host) {
385
- if(unlikely(!host->health.health_enabled) && !rrdhost_flag_check(host, RRDHOST_FLAG_INITIALIZED_HEALTH))
386
- return;
387
-
388
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
389
- "[%s]: Reloading health.",
390
- rrdhost_hostname(host));
391
-
392
- char *user_path = health_user_config_dir();
393
- char *stock_path = health_stock_config_dir();
394
-
395
- // free all running alarms
396
- rrdcalc_delete_all(host);
397
- rrdcalctemplate_delete_all(host);
398
-
399
- // invalidate all previous entries in the alarm log
400
- rw_spinlock_read_lock(&host->health_log.spinlock);
401
- ALARM_ENTRY *t;
402
- for(t = host->health_log.alarms ; t ; t = t->next) {
403
- if(t->new_status != RRDCALC_STATUS_REMOVED)
404
- t->flags |= HEALTH_ENTRY_FLAG_UPDATED;
405
- }
406
- rw_spinlock_read_unlock(&host->health_log.spinlock);
407
-
408
- // reset all thresholds to all charts
409
- RRDSET *st;
410
- rrdset_foreach_read(st, host) {
411
- st->green = NAN;
412
- st->red = NAN;
413
- }
414
- rrdset_foreach_done(st);
415
-
416
- // load the new alarms
417
- health_readdir(host, user_path, stock_path, NULL);
418
-
419
- //Discard alarms with labels that do not apply to host
420
- rrdcalc_delete_alerts_not_matching_host_labels_from_this_host(host);
421
-
422
- // link the loaded alarms to their charts
423
- rrdset_foreach_write(st, host) {
424
- rrdcalc_link_matching_alerts_to_rrdset(st);
425
- rrdcalctemplate_link_matching_templates_to_rrdset(st);
426
- }
427
- rrdset_foreach_done(st);
428
-
429
-#ifdef ENABLE_ACLK
430
- if (netdata_cloud_enabled) {
431
- struct aclk_sync_cfg_t *wc = host->aclk_config;
432
- if (likely(wc)) {
433
- wc->alert_queue_removed = SEND_REMOVED_AFTER_HEALTH_LOOPS;
434
- }
435
- }
436
-#endif
437
-}
438
-
439
-/**
440
- * Reload
441
- *
442
- * Reload the host configuration for all hosts.
443
- */
444
-void health_reload(void) {
445
- sql_refresh_hashes();
446
-
447
- RRDHOST *host;
448
- dfe_start_reentrant(rrdhost_root_index, host){
449
- health_reload_host(host);
450
- }
451
- dfe_done(host);
452
-}
453
-
454
-// ----------------------------------------------------------------------------
455
-// health main thread and friends
456
-
457
-static inline RRDCALC_STATUS rrdcalc_value2status(NETDATA_DOUBLE n) {
458
- if(isnan(n) || isinf(n)) return RRDCALC_STATUS_UNDEFINED;
459
- if(n) return RRDCALC_STATUS_RAISED;
460
- return RRDCALC_STATUS_CLEAR;
461
-}
462
-
463
-#define ACTIVE_ALARMS_LIST_EXAMINE 500
464
-#define ACTIVE_ALARMS_LIST 15
465
-
466
-static inline int compare_active_alerts(const void * a, const void * b) {
467
- active_alerts_t *active_alerts_a = (active_alerts_t *)a;
468
- active_alerts_t *active_alerts_b = (active_alerts_t *)b;
469
-
470
- return (int) ( active_alerts_b->last_status_change - active_alerts_a->last_status_change );
471
-}
472
-
473
-static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
474
- ae->flags |= HEALTH_ENTRY_FLAG_PROCESSED;
475
-
476
- if(unlikely(ae->new_status < RRDCALC_STATUS_CLEAR)) {
477
- // do not send notifications for internal statuses
478
- netdata_log_debug(D_HEALTH, "Health not sending notification for alarm '%s.%s' status %s (internal statuses)", ae_chart_id(ae), ae_name(ae), rrdcalc_status2string(ae->new_status));
479
- goto done;
480
- }
481
-
482
- if(unlikely(ae->new_status <= RRDCALC_STATUS_CLEAR && (ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION))) {
483
- // do not send notifications for disabled statuses
484
-
485
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
486
- "[%s]: Health not sending notification for alarm '%s.%s' status %s (it has no-clear-notification enabled)",
487
- rrdhost_hostname(host), ae_chart_id(ae), ae_name(ae), rrdcalc_status2string(ae->new_status));
488
-
489
- // mark it as run, so that we will send the same alarm if it happens again
490
- goto done;
491
- }
492
-
493
- // find the previous notification for the same alarm
494
- // which we have run the exec script
495
- // exception: alarms with HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION set
496
- RRDCALC_STATUS last_executed_status = -3;
497
- if(likely(!(ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION))) {
498
- int ret = sql_health_get_last_executed_event(host, ae, &last_executed_status);
499
-
500
- if (likely(ret == 1)) {
501
- // we have executed this alarm notification in the past
502
- if(last_executed_status == ae->new_status && !(ae->flags & HEALTH_ENTRY_FLAG_IS_REPEATING)) {
503
- // don't send the notification for the same status again
504
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
505
- "[%s]: Health not sending again notification for alarm '%s.%s' status %s",
506
- rrdhost_hostname(host), ae_chart_id(ae), ae_name(ae),
507
- rrdcalc_status2string(ae->new_status));
508
- goto done;
509
- }
510
- }
511
- else {
512
- // we have not executed this alarm notification in the past
513
- // so, don't send CLEAR notifications
514
- if(unlikely(ae->new_status == RRDCALC_STATUS_CLEAR)) {
515
- if((!(ae->flags & HEALTH_ENTRY_RUN_ONCE)) || (ae->flags & HEALTH_ENTRY_RUN_ONCE && ae->old_status < RRDCALC_STATUS_RAISED) ) {
516
- netdata_log_debug(D_HEALTH, "Health not sending notification for first initialization of alarm '%s.%s' status %s"
517
- , ae_chart_id(ae), ae_name(ae), rrdcalc_status2string(ae->new_status));
518
- goto done;
519
- }
520
- }
521
- }
522
- }
523
-
524
- // Check if alarm notifications are silenced
525
- if (ae->flags & HEALTH_ENTRY_FLAG_SILENCED) {
526
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
527
- "[%s]: Health not sending notification for alarm '%s.%s' status %s "
528
- "(command API has disabled notifications)",
529
- rrdhost_hostname(host), ae_chart_id(ae), ae_name(ae), rrdcalc_status2string(ae->new_status));
530
- goto done;
531
- }
532
-
533
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
534
- "[%s]: Sending notification for alarm '%s.%s' status %s.",
535
- rrdhost_hostname(host), ae_chart_id(ae), ae_name(ae), rrdcalc_status2string(ae->new_status));
536
-
537
- const char *exec = (ae->exec) ? ae_exec(ae) : string2str(host->health.health_default_exec);
538
- const char *recipient = (ae->recipient) ? ae_recipient(ae) : string2str(host->health.health_default_recipient);
539
-
540
- int n_warn=0, n_crit=0;
541
- RRDCALC *rc;
542
- EVAL_EXPRESSION *expr=NULL;
543
- BUFFER *warn_alarms, *crit_alarms;
544
- active_alerts_t *active_alerts = callocz(ACTIVE_ALARMS_LIST_EXAMINE, sizeof(active_alerts_t));
545
-
546
- warn_alarms = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, &netdata_buffers_statistics.buffers_health);
547
- crit_alarms = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, &netdata_buffers_statistics.buffers_health);
548
-
549
- foreach_rrdcalc_in_rrdhost_read(host, rc) {
550
- if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
551
- continue;
552
-
553
- if(unlikely((n_warn + n_crit) >= ACTIVE_ALARMS_LIST_EXAMINE))
554
- break;
555
-
556
- if (unlikely(rc->status == RRDCALC_STATUS_WARNING)) {
557
- if (likely(ae->alarm_id != rc->id) || likely(ae->alarm_event_id != rc->next_event_id - 1)) {
558
- active_alerts[n_warn+n_crit].name = (char *)rrdcalc_name(rc);
559
- active_alerts[n_warn+n_crit].last_status_change = rc->last_status_change;
560
- active_alerts[n_warn+n_crit].status = rc->status;
561
- n_warn++;
562
- } else if (ae->alarm_id == rc->id)
563
- expr = rc->warning;
564
- } else if (unlikely(rc->status == RRDCALC_STATUS_CRITICAL)) {
565
- if (likely(ae->alarm_id != rc->id) || likely(ae->alarm_event_id != rc->next_event_id - 1)) {
566
- active_alerts[n_warn+n_crit].name = (char *)rrdcalc_name(rc);
567
- active_alerts[n_warn+n_crit].last_status_change = rc->last_status_change;
568
- active_alerts[n_warn+n_crit].status = rc->status;
569
- n_crit++;
570
- } else if (ae->alarm_id == rc->id)
571
- expr = rc->critical;
572
- } else if (unlikely(rc->status == RRDCALC_STATUS_CLEAR)) {
573
- if (ae->alarm_id == rc->id)
574
- expr = rc->warning;
575
- }
576
- }
577
- foreach_rrdcalc_in_rrdhost_done(rc);
578
-
579
- if (n_warn+n_crit>1)
580
- qsort (active_alerts, n_warn+n_crit, sizeof(active_alerts_t), compare_active_alerts);
581
-
582
- int count_w = 0, count_c = 0;
583
- while (count_w + count_c < n_warn + n_crit && count_w + count_c < ACTIVE_ALARMS_LIST) {
584
- if (active_alerts[count_w+count_c].status == RRDCALC_STATUS_WARNING) {
585
- if (count_w)
586
- buffer_strcat(warn_alarms, ",");
587
- buffer_strcat(warn_alarms, active_alerts[count_w+count_c].name);
588
- buffer_strcat(warn_alarms, "=");
589
- buffer_snprintf(warn_alarms, 11, "%"PRId64"", (int64_t)active_alerts[count_w+count_c].last_status_change);
590
- count_w++;
591
- }
592
- else if (active_alerts[count_w+count_c].status == RRDCALC_STATUS_CRITICAL) {
593
- if (count_c)
594
- buffer_strcat(crit_alarms, ",");
595
- buffer_strcat(crit_alarms, active_alerts[count_w+count_c].name);
596
- buffer_strcat(crit_alarms, "=");
597
- buffer_snprintf(crit_alarms, 11, "%"PRId64"", (int64_t)active_alerts[count_w+count_c].last_status_change);
598
- count_c++;
599
- }
600
- }
601
-
602
- char *edit_command = ae->source ? health_edit_command_from_source(ae_source(ae)) : strdupz("UNKNOWN=0=UNKNOWN");
603
-
604
- BUFFER *wb = buffer_create(8192, &netdata_buffers_statistics.buffers_health);
605
- bool ok = prepare_command(wb,
606
- exec,
607
- recipient,
608
- rrdhost_registry_hostname(host),
609
- ae->unique_id,
610
- ae->alarm_id,
611
- ae->alarm_event_id,
612
- (unsigned long)ae->when,
613
- ae_name(ae),
614
- ae->chart?ae_chart_id(ae):"NOCHART",
615
- rrdcalc_status2string(ae->new_status),
616
- rrdcalc_status2string(ae->old_status),
617
- ae->new_value,
618
- ae->old_value,
619
- ae->source?ae_source(ae):"UNKNOWN",
620
- (uint32_t)ae->duration,
621
- (ae->flags & HEALTH_ENTRY_FLAG_IS_REPEATING && ae->new_status >= RRDCALC_STATUS_WARNING) ? (uint32_t)ae->duration : (uint32_t)ae->non_clear_duration,
622
- ae_units(ae),
623
- ae_info(ae),
624
- ae_new_value_string(ae),
625
- ae_old_value_string(ae),
626
- (expr && expr->source)?expr->source:"NOSOURCE",
627
- (expr && expr->error_msg)?buffer_tostring(expr->error_msg):"NOERRMSG",
628
- n_warn,
629
- n_crit,
630
- buffer_tostring(warn_alarms),
631
- buffer_tostring(crit_alarms),
632
- ae->classification?ae_classification(ae):"Unknown",
633
- edit_command,
634
- host->machine_guid,
635
- &ae->transition_id,
636
- host->health.use_summary_for_notifications && ae->summary?ae_summary(ae):ae_name(ae),
637
- string2str(ae->chart_context),
638
- string2str(ae->component),
639
- string2str(ae->type)
640
- );
641
-
642
- const char *command_to_run = buffer_tostring(wb);
643
- if (ok) {
644
- ae->flags |= HEALTH_ENTRY_FLAG_EXEC_RUN;
645
- ae->exec_run_timestamp = now_realtime_sec(); /* will be updated by real time after spawning */
646
-
647
- netdata_log_debug(D_HEALTH, "executing command '%s'", command_to_run);
648
- ae->flags |= HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS;
649
- ae->exec_spawn_serial = spawn_enq_cmd(command_to_run);
650
- enqueue_alarm_notify_in_progress(ae);
651
- health_alarm_log_save(host, ae);
652
- } else {
653
- netdata_log_error("Failed to format command arguments");
654
- }
655
-
656
- buffer_free(wb);
657
- freez(edit_command);
658
- buffer_free(warn_alarms);
659
- buffer_free(crit_alarms);
660
- freez(active_alerts);
661
-
662
- return; //health_alarm_wait_for_execution
663
-done:
664
- health_alarm_log_save(host, ae);
665
-}
666
-
667
-static inline void health_alarm_wait_for_execution(ALARM_ENTRY *ae) {
668
- if (!(ae->flags & HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS))
669
- return;
670
-
671
- spawn_wait_cmd(ae->exec_spawn_serial, &ae->exec_code, &ae->exec_run_timestamp);
672
- netdata_log_debug(D_HEALTH, "done executing command - returned with code %d", ae->exec_code);
673
- ae->flags &= ~HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS;
674
-
675
- if(ae->exec_code != 0)
676
- ae->flags |= HEALTH_ENTRY_FLAG_EXEC_FAILED;
677
-
678
- unlink_alarm_notify_in_progress(ae);
679
-}
680
-
681
-static inline void health_process_notifications(RRDHOST *host, ALARM_ENTRY *ae) {
682
- netdata_log_debug(D_HEALTH, "Health alarm '%s.%s' = " NETDATA_DOUBLE_FORMAT_AUTO " - changed status from %s to %s",
683
- ae->chart?ae_chart_id(ae):"NOCHART", ae_name(ae),
684
- ae->new_value,
685
- rrdcalc_status2string(ae->old_status),
686
- rrdcalc_status2string(ae->new_status)
687
- );
688
-
689
- health_alarm_execute(host, ae);
690
-}
691
-
692
-static inline void health_alarm_log_process(RRDHOST *host) {
693
- uint32_t first_waiting = (host->health_log.alarms)?host->health_log.alarms->unique_id:0;
694
- time_t now = now_realtime_sec();
695
-
696
- rw_spinlock_read_lock(&host->health_log.spinlock);
697
-
698
- ALARM_ENTRY *ae;
699
- for(ae = host->health_log.alarms; ae && ae->unique_id >= host->health_last_processed_id; ae = ae->next) {
700
- if(unlikely(
701
- !(ae->flags & HEALTH_ENTRY_FLAG_PROCESSED) &&
702
- !(ae->flags & HEALTH_ENTRY_FLAG_UPDATED)
703
- )) {
704
- if(unlikely(ae->unique_id < first_waiting))
705
- first_waiting = ae->unique_id;
706
-
707
- if(likely(now >= ae->delay_up_to_timestamp))
708
- health_process_notifications(host, ae);
709
- }
710
- }
711
-
712
- rw_spinlock_read_unlock(&host->health_log.spinlock);
713
-
714
- // remember this for the next iteration
715
- host->health_last_processed_id = first_waiting;
716
-
717
- //delete those that are updated, no in progress execution, and is not repeating
718
- rw_spinlock_write_lock(&host->health_log.spinlock);
719
-
720
- ALARM_ENTRY *prev = NULL, *next = NULL;
721
- for(ae = host->health_log.alarms; ae ; ae = next) {
722
- next = ae->next; // set it here, for the next iteration
723
-
724
- if((likely(!(ae->flags & HEALTH_ENTRY_FLAG_IS_REPEATING)) &&
725
- (ae->flags & HEALTH_ENTRY_FLAG_UPDATED) &&
726
- (ae->flags & HEALTH_ENTRY_FLAG_SAVED) &&
727
- !(ae->flags & HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS))
728
- ||
729
- ((ae->new_status == RRDCALC_STATUS_REMOVED) &&
730
- (ae->flags & HEALTH_ENTRY_FLAG_SAVED) &&
731
- (ae->when + 86400 < now_realtime_sec())))
732
- {
733
-
734
- if(host->health_log.alarms == ae) {
735
- host->health_log.alarms = next;
736
- // prev is also NULL here
737
- }
738
- else {
739
- prev->next = next;
740
- // prev should not be touched here - we need it for the next iteration
741
- // because we may have to also remove the next item
742
- }
743
-
744
- health_alarm_log_free_one_nochecks_nounlink(ae);
745
- }
746
- else
747
- prev = ae;
748
- }
749
-
750
- rw_spinlock_write_unlock(&host->health_log.spinlock);
751
-}
752
-
753
-static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run) {
754
- if(unlikely(!rc->rrdset)) {
755
- netdata_log_debug(D_HEALTH, "Health not running alarm '%s.%s'. It is not linked to a chart.", rrdcalc_chart_name(rc), rrdcalc_name(rc));
756
- return 0;
757
- }
758
-
759
- if(unlikely(rc->next_update > now)) {
760
- if (unlikely(*next_run > rc->next_update)) {
761
- // update the next_run time of the main loop
762
- // to run this alarm precisely the time required
763
- *next_run = rc->next_update;
764
- }
765
-
766
- netdata_log_debug(D_HEALTH, "Health not examining alarm '%s.%s' yet (will do in %d secs).", rrdcalc_chart_name(rc), rrdcalc_name(rc), (int) (rc->next_update - now));
767
- return 0;
768
- }
769
-
770
- if(unlikely(!rc->update_every)) {
771
- netdata_log_debug(D_HEALTH, "Health not running alarm '%s.%s'. It does not have an update frequency", rrdcalc_chart_name(rc), rrdcalc_name(rc));
772
- return 0;
773
- }
774
-
775
- if(unlikely(rrdset_flag_check(rc->rrdset, RRDSET_FLAG_OBSOLETE))) {
776
- netdata_log_debug(D_HEALTH, "Health not running alarm '%s.%s'. The chart has been marked as obsolete", rrdcalc_chart_name(rc), rrdcalc_name(rc));
777
- return 0;
778
- }
779
-
780
- if(unlikely(!rc->rrdset->last_collected_time.tv_sec || rc->rrdset->counter_done < 2)) {
781
- netdata_log_debug(D_HEALTH, "Health not running alarm '%s.%s'. Chart is not fully collected yet.", rrdcalc_chart_name(rc), rrdcalc_name(rc));
782
- return 0;
783
- }
784
-
785
- int update_every = rc->rrdset->update_every;
786
- time_t first = rrdset_first_entry_s(rc->rrdset);
787
- time_t last = rrdset_last_entry_s(rc->rrdset);
788
-
789
- if(unlikely(now + update_every < first /* || now - update_every > last */)) {
790
- netdata_log_debug(D_HEALTH
791
- , "Health not examining alarm '%s.%s' yet (wanted time is out of bounds - we need %lu but got %lu - %lu)."
792
- , rrdcalc_chart_name(rc), rrdcalc_name(rc), (unsigned long) now, (unsigned long) first
793
- , (unsigned long) last);
794
- return 0;
795
- }
796
-
797
- if(RRDCALC_HAS_DB_LOOKUP(rc)) {
798
- time_t needed = now + rc->before + rc->after;
799
-
800
- if(needed + update_every < first || needed - update_every > last) {
801
- netdata_log_debug(D_HEALTH
802
- , "Health not examining alarm '%s.%s' yet (not enough data yet - we need %lu but got %lu - %lu)."
803
- , rrdcalc_chart_name(rc), rrdcalc_name(rc), (unsigned long) needed, (unsigned long) first
804
- , (unsigned long) last);
805
- return 0;
806
- }
807
- }
808
-
809
- return 1;
810
-}
811
-
812
-static inline int check_if_resumed_from_suspension(void) {
813
- static usec_t last_realtime = 0, last_monotonic = 0;
814
- usec_t realtime = now_realtime_usec(), monotonic = now_monotonic_usec();
815
- int ret = 0;
816
-
817
- // detect if monotonic and realtime have twice the difference
818
- // in which case we assume the system was just waken from hibernation
819
-
820
- if(last_realtime && last_monotonic && realtime - last_realtime > 2 * (monotonic - last_monotonic))
821
- ret = 1;
822
-
823
- last_realtime = realtime;
824
- last_monotonic = monotonic;
825
-
826
- return ret;
827
-}
828
-
829
-static void health_main_cleanup(void *ptr) {
830
- worker_unregister();
831
-
832
- struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
833
- static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
834
- netdata_log_info("cleaning up...");
835
- static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
836
-
837
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
838
- "Health thread ended.");
839
-}
840
-
841
-static void initialize_health(RRDHOST *host)
842
-{
843
- if(!host->health.health_enabled ||
844
- rrdhost_flag_check(host, RRDHOST_FLAG_INITIALIZED_HEALTH) ||
845
- !service_running(SERVICE_HEALTH))
846
- return;
847
-
848
- rrdhost_flag_set(host, RRDHOST_FLAG_INITIALIZED_HEALTH);
849
-
850
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
851
- "[%s]: Initializing health.",
852
- rrdhost_hostname(host));
853
-
854
- host->health.health_default_warn_repeat_every = config_get_duration(CONFIG_SECTION_HEALTH, "default repeat warning", "never");
855
- host->health.health_default_crit_repeat_every = config_get_duration(CONFIG_SECTION_HEALTH, "default repeat critical", "never");
856
-
857
- host->health_log.next_log_id = 1;
858
- host->health_log.next_alarm_id = 1;
859
- host->health_log.max = 1000;
860
- host->health_log.next_log_id = (uint32_t)now_realtime_sec();
861
- host->health_log.next_alarm_id = 0;
862
-
863
- long n = config_get_number(CONFIG_SECTION_HEALTH, "in memory max health log entries", host->health_log.max);
864
- if(n < 10) {
865
- nd_log(NDLS_DAEMON, NDLP_WARNING,
866
- "Host '%s': health configuration has invalid max log entries %ld. "
867
- "Using default %u",
868
- rrdhost_hostname(host), n, host->health_log.max);
869
-
870
- config_set_number(CONFIG_SECTION_HEALTH, "in memory max health log entries", (long)host->health_log.max);
871
- }
872
- else
873
- host->health_log.max = (unsigned int)n;
874
-
875
- uint32_t m = config_get_number(CONFIG_SECTION_HEALTH, "health log history", HEALTH_LOG_DEFAULT_HISTORY);
876
- if (m < HEALTH_LOG_MINIMUM_HISTORY) {
877
- nd_log(NDLS_DAEMON, NDLP_WARNING,
878
- "Host '%s': health configuration has invalid health log history %u. "
879
- "Using minimum %d",
880
- rrdhost_hostname(host), m, HEALTH_LOG_MINIMUM_HISTORY);
881
-
882
- config_set_number(CONFIG_SECTION_HEALTH, "health log history", HEALTH_LOG_MINIMUM_HISTORY);
883
- m = HEALTH_LOG_MINIMUM_HISTORY;
884
- }
885
-
886
- //default health log history is 5 days and not less than a day
887
- if (host->health_log.health_log_history) {
888
- if (host->health_log.health_log_history < HEALTH_LOG_MINIMUM_HISTORY)
889
- host->health_log.health_log_history = HEALTH_LOG_MINIMUM_HISTORY;
890
- } else
891
- host->health_log.health_log_history = m;
892
-
893
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
894
- "[%s]: Health log history is set to %u seconds (%u days)",
895
- rrdhost_hostname(host), host->health_log.health_log_history, host->health_log.health_log_history / 86400);
896
-
897
- conf_enabled_alarms = simple_pattern_create(config_get(CONFIG_SECTION_HEALTH, "enabled alarms", "*"), NULL,
898
- SIMPLE_PATTERN_EXACT, true);
899
-
900
- rw_spinlock_init(&host->health_log.spinlock);
901
-
902
- char filename[FILENAME_MAX + 1];
903
-
904
- snprintfz(filename, FILENAME_MAX, "%s/alarm-notify.sh", netdata_configured_primary_plugins_dir);
905
- host->health.health_default_exec = string_strdupz(config_get(CONFIG_SECTION_HEALTH, "script to execute on alarm", filename));
906
- host->health.health_default_recipient = string_strdupz("root");
907
- host->health.use_summary_for_notifications = config_get_boolean(CONFIG_SECTION_HEALTH, "use summary for notifications", CONFIG_BOOLEAN_YES);
908
-
909
- sql_health_alarm_log_load(host);
910
-
911
- // ------------------------------------------------------------------------
912
- // load health configuration
913
-
914
- health_readdir(host, health_user_config_dir(), health_stock_config_dir(), NULL);
915
-
916
- // link the loaded alarms to their charts
917
- RRDSET *st;
918
- rrdset_foreach_reentrant(st, host) {
919
- rrdcalc_link_matching_alerts_to_rrdset(st);
920
- rrdcalctemplate_link_matching_templates_to_rrdset(st);
921
- }
922
- rrdset_foreach_done(st);
923
-
924
- //Discard alarms with labels that do not apply to host
925
- rrdcalc_delete_alerts_not_matching_host_labels_from_this_host(host);
926
-}
927
-
928
-static void health_sleep(time_t next_run, unsigned int loop __maybe_unused) {
929
- time_t now = now_realtime_sec();
930
- if(now < next_run) {
931
- worker_is_idle();
932
- netdata_log_debug(D_HEALTH, "Health monitoring iteration no %u done. Next iteration in %d secs", loop, (int) (next_run - now));
933
- while (now < next_run && service_running(SERVICE_HEALTH)) {
934
- sleep_usec(USEC_PER_SEC);
935
- now = now_realtime_sec();
936
- }
937
- }
938
- else {
939
- netdata_log_debug(D_HEALTH, "Health monitoring iteration no %u done. Next iteration now", loop);
940
- }
941
-}
144
+void health_plugin_init(void) {
145
+ spinlock_lock(&health_globals.initialization.spinlock);
146
943
-static SILENCE_TYPE check_silenced(RRDCALC *rc, const char *host)
944
-{
945
- SILENCER *s;
147
+ if(health_globals.initialization.done)
148
+ goto cleanup;
149
947
- for (s = silencers->silencers; s!=NULL; s=s->next){
948
- if (
949
- (!s->alarms_pattern || (rc->name && s->alarms_pattern && simple_pattern_matches_string(s->alarms_pattern, rc->name))) &&
950
- (!s->contexts_pattern || (rc->rrdset && rc->rrdset->context && s->contexts_pattern && simple_pattern_matches_string(s->contexts_pattern, rc->rrdset->context))) &&
951
- (!s->hosts_pattern || (host && s->hosts_pattern && simple_pattern_matches(s->hosts_pattern, host))) &&
952
- (!s->charts_pattern || (rc->chart && s->charts_pattern && simple_pattern_matches_string(s->charts_pattern, rc->chart)))
953
- ) {
954
- netdata_log_debug(D_HEALTH, "Alarm matches command API silence entry %s:%s:%s:%s", s->alarms,s->charts, s->contexts, s->hosts);
955
- if (unlikely(silencers->stype == STYPE_NONE)) {
956
- netdata_log_debug(D_HEALTH, "Alarm %s matched a silence entry, but no SILENCE or DISABLE command was issued via the command API. The match has no effect.", rrdcalc_name(rc));
957
- } else {
958
- netdata_log_debug(D_HEALTH, "Alarm %s via the command API - name:%s context:%s chart:%s host:%s"
959
- , (silencers->stype == STYPE_DISABLE_ALARMS)?"Disabled":"Silenced"
960
- , rrdcalc_name(rc)
961
- , (rc->rrdset)?rrdset_context(rc->rrdset):""
962
- , rrdcalc_chart_name(rc)
963
- , host
964
- );
965
- }
966
- return silencers->stype;
967
- }
968
- }
969
- return STYPE_NONE;
970
-}
150
+ health_globals.initialization.done = true;
151
972
-/**
973
- * Update Disabled Silenced
974
- *
975
- * Update the variable rrdcalc_flags of the structure RRDCALC according with the values of the host structure
976
- *
977
- * @param host structure that contains information about the host monitored.
978
- * @param rc structure with information about the alarm
979
- *
980
- * @return It returns 1 case rrdcalc_flags is DISABLED or 0 otherwise
981
- */
982
-static int update_disabled_silenced(RRDHOST *host, RRDCALC *rc) {
983
- uint32_t rrdcalc_flags_old = rc->run_flags;
984
- // Clear the flags
985
- rc->run_flags &= ~(RRDCALC_FLAG_DISABLED | RRDCALC_FLAG_SILENCED);
986
- if (unlikely(silencers->all_alarms)) {
987
- if (silencers->stype == STYPE_DISABLE_ALARMS) rc->run_flags |= RRDCALC_FLAG_DISABLED;
988
- else if (silencers->stype == STYPE_SILENCE_NOTIFICATIONS) rc->run_flags |= RRDCALC_FLAG_SILENCED;
989
- } else {
990
- SILENCE_TYPE st = check_silenced(rc, rrdhost_hostname(host));
991
- if (st == STYPE_DISABLE_ALARMS) rc->run_flags |= RRDCALC_FLAG_DISABLED;
992
- else if (st == STYPE_SILENCE_NOTIFICATIONS) rc->run_flags |= RRDCALC_FLAG_SILENCED;
993
- }
152
+ health_init_prototypes();
153
+ health_load_config_defaults();
154
995
- if (rrdcalc_flags_old != rc->run_flags) {
996
- netdata_log_info(
997
- "Alarm silencing changed for host '%s' alarm '%s': Disabled %s->%s Silenced %s->%s",
998
- rrdhost_hostname(host),
999
- rrdcalc_name(rc),
1000
- (rrdcalc_flags_old & RRDCALC_FLAG_DISABLED) ? "true" : "false",
1001
- (rc->run_flags & RRDCALC_FLAG_DISABLED) ? "true" : "false",
1002
- (rrdcalc_flags_old & RRDCALC_FLAG_SILENCED) ? "true" : "false",
1003
- (rc->run_flags & RRDCALC_FLAG_SILENCED) ? "true" : "false");
1004
- }
1005
- if (rc->run_flags & RRDCALC_FLAG_DISABLED)
1006
- return 1;
1007
- else
1008
- return 0;
1009
-}
155
+ if(!health_plugin_enabled())
156
+ goto cleanup;
157
1011
-static void sql_health_postpone_queue_removed(RRDHOST *host __maybe_unused) {
1012
-#ifdef ENABLE_ACLK
1013
- if (netdata_cloud_enabled) {
1014
- struct aclk_sync_cfg_t *wc = host->aclk_config;
1015
- if (unlikely(!wc)) {
1016
- return;
1017
- }
158
+ health_reload_prototypes();
159
+ health_silencers_init();
160
1019
- if (wc->alert_queue_removed >= 1) {
1020
- wc->alert_queue_removed+=6;
1021
- }
1022
- }
1023
-#endif
161
+cleanup:
162
+ spinlock_unlock(&health_globals.initialization.spinlock);
163
}
164
1026
-static void health_execute_delayed_initializations(RRDHOST *host) {
1027
- RRDSET *st;
1028
- bool must_postpone = false;
1029
-
1030
- if (!rrdhost_flag_check(host, RRDHOST_FLAG_PENDING_HEALTH_INITIALIZATION)) return;
1031
- rrdhost_flag_clear(host, RRDHOST_FLAG_PENDING_HEALTH_INITIALIZATION);
1032
-
1033
- rrdset_foreach_reentrant(st, host) {
1034
- if(!rrdset_flag_check(st, RRDSET_FLAG_PENDING_HEALTH_INITIALIZATION)) continue;
1035
- rrdset_flag_clear(st, RRDSET_FLAG_PENDING_HEALTH_INITIALIZATION);
1036
-
1037
- worker_is_busy(WORKER_HEALTH_JOB_DELAYED_INIT_RRDSET);
1038
-
1039
- rrdcalc_link_matching_alerts_to_rrdset(st);
1040
- rrdcalctemplate_link_matching_templates_to_rrdset(st);
1041
-
1042
- RRDDIM *rd;
1043
- rrddim_foreach_read(rd, st) {
1044
- if(!rrddim_flag_check(rd, RRDDIM_FLAG_PENDING_HEALTH_INITIALIZATION)) continue;
1045
- rrddim_flag_clear(rd, RRDDIM_FLAG_PENDING_HEALTH_INITIALIZATION);
1046
-
1047
- worker_is_busy(WORKER_HEALTH_JOB_DELAYED_INIT_RRDDIM);
1048
-
1049
- RRDCALCTEMPLATE *rt;
1050
- foreach_rrdcalctemplate_read(host, rt) {
1051
- if(!rt->foreach_dimension_pattern)
1052
- continue;
1053
-
1054
- if(rrdcalctemplate_check_rrdset_conditions(rt, st, host)) {
1055
- rrdcalctemplate_check_rrddim_conditions_and_link(rt, st, rd, host);
1056
- }
1057
- }
1058
- foreach_rrdcalctemplate_done(rt);
1059
-
1060
- if (health_variable_check(health_rrdvars, st, rd) || rrdset_flag_check(st, RRDSET_FLAG_HAS_RRDCALC_LINKED))
1061
- rrdvar_store_for_chart(host, st);
1062
- }
1063
- rrddim_foreach_done(rd);
1064
- must_postpone = true;
1065
- }
1066
- rrdset_foreach_done(st);
1067
- if (must_postpone)
1068
- sql_health_postpone_queue_removed(host);
165
+void health_plugin_destroy(void) {
166
+ ;
167
}
168
1071
-/**
1072
- * Health Main
1073
- *
1074
- * The main thread of the health system. In this function all the alarms will be processed.
1075
- *
1076
- * @param ptr is a pointer to the netdata_static_thread structure.
1077
- *
1078
- * @return It always returns NULL
1079
- */
1080
-
1081
-void *health_main(void *ptr) {
1082
- worker_register("HEALTH");
1083
- worker_register_job_name(WORKER_HEALTH_JOB_RRD_LOCK, "rrd lock");
1084
- worker_register_job_name(WORKER_HEALTH_JOB_HOST_LOCK, "host lock");
1085
- worker_register_job_name(WORKER_HEALTH_JOB_DB_QUERY, "db lookup");
1086
- worker_register_job_name(WORKER_HEALTH_JOB_CALC_EVAL, "calc eval");
1087
- worker_register_job_name(WORKER_HEALTH_JOB_WARNING_EVAL, "warning eval");
1088
- worker_register_job_name(WORKER_HEALTH_JOB_CRITICAL_EVAL, "critical eval");
1089
- worker_register_job_name(WORKER_HEALTH_JOB_ALARM_LOG_ENTRY, "alarm log entry");
1090
- worker_register_job_name(WORKER_HEALTH_JOB_ALARM_LOG_PROCESS, "alarm log process");
1091
- worker_register_job_name(WORKER_HEALTH_JOB_DELAYED_INIT_RRDSET, "rrdset init");
1092
- worker_register_job_name(WORKER_HEALTH_JOB_DELAYED_INIT_RRDDIM, "rrddim init");
1093
-
1094
- netdata_thread_cleanup_push(health_main_cleanup, ptr);
1095
-
1096
- int min_run_every = (int)config_get_number(CONFIG_SECTION_HEALTH, "run at least every seconds", 10);
1097
- if(min_run_every < 1) min_run_every = 1;
1098
-
1099
- time_t hibernation_delay = config_get_number(CONFIG_SECTION_HEALTH, "postpone alarms during hibernation for seconds", 60);
1100
-
1101
- bool health_running_logged = false;
1102
-
1103
- rrdcalc_delete_alerts_not_matching_host_labels_from_all_hosts();
1104
-
1105
- unsigned int loop = 0;
1106
-
1107
- while(service_running(SERVICE_HEALTH)) {
1108
- loop++;
1109
- netdata_log_debug(D_HEALTH, "Health monitoring iteration no %u started", loop);
1110
-
1111
- time_t now = now_realtime_sec();
1112
- int runnable = 0, apply_hibernation_delay = 0;
1113
- time_t next_run = now + min_run_every;
1114
- RRDCALC *rc;
1115
- RRDHOST *host;
1116
-
1117
- if (unlikely(check_if_resumed_from_suspension())) {
1118
- apply_hibernation_delay = 1;
1119
-
1120
- nd_log(NDLS_DAEMON, NDLP_NOTICE,
1121
- "Postponing alarm checks for %"PRId64" seconds, "
1122
- "because it seems that the system was just resumed from suspension.",
1123
- (int64_t)hibernation_delay);
1124
- }
1125
-
1126
- if (unlikely(silencers->all_alarms && silencers->stype == STYPE_DISABLE_ALARMS)) {
1127
- static int logged=0;
1128
- if (!logged) {
1129
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
1130
- "Skipping health checks, because all alarms are disabled via a %s command.",
1131
- HEALTH_CMDAPI_CMD_DISABLEALL);
1132
- logged = 1;
1133
- }
1134
- }
1135
-
1136
- worker_is_busy(WORKER_HEALTH_JOB_RRD_LOCK);
1137
- dfe_start_reentrant(rrdhost_root_index, host) {
1138
-
1139
- if(unlikely(!service_running(SERVICE_HEALTH)))
1140
- break;
1141
-
1142
- if (unlikely(!host->health.health_enabled))
1143
- continue;
1144
-
1145
- if (unlikely(!rrdhost_flag_check(host, RRDHOST_FLAG_INITIALIZED_HEALTH)))
1146
- initialize_health(host);
1147
-
1148
- health_execute_delayed_initializations(host);
1149
-
1150
- rrdcalc_delete_alerts_not_matching_host_labels_from_this_host(host);
1151
-
1152
- if (unlikely(apply_hibernation_delay)) {
1153
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
1154
- "[%s]: Postponing health checks for %"PRId64" seconds.",
1155
- rrdhost_hostname(host),
1156
- (int64_t)hibernation_delay);
1157
-
1158
- host->health.health_delay_up_to = now + hibernation_delay;
1159
- }
1160
-
1161
- if (unlikely(host->health.health_delay_up_to)) {
1162
- if (unlikely(now < host->health.health_delay_up_to)) {
1163
- continue;
1164
- }
1165
-
1166
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
1167
- "[%s]: Resuming health checks after delay.",
1168
- rrdhost_hostname(host));
1169
-
1170
- host->health.health_delay_up_to = 0;
1171
- }
1172
-
1173
- // wait until cleanup of obsolete charts on children is complete
1174
- if (host != localhost) {
1175
- if (unlikely(host->trigger_chart_obsoletion_check == 1)) {
1176
-
1177
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
1178
- "[%s]: Waiting for chart obsoletion check.",
1179
- rrdhost_hostname(host));
1180
-
1181
- continue;
1182
- }
1183
- }
1184
-
1185
- if (!health_running_logged) {
1186
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
1187
- "[%s]: Health is running.",
1188
- rrdhost_hostname(host));
1189
-
1190
- health_running_logged = true;
1191
- }
1192
-
1193
- worker_is_busy(WORKER_HEALTH_JOB_HOST_LOCK);
1194
-
1195
- // the first loop is to lookup values from the db
1196
- foreach_rrdcalc_in_rrdhost_read(host, rc) {
1197
-
1198
- if(unlikely(!service_running(SERVICE_HEALTH)))
1199
- break;
1200
-
1201
- rrdcalc_update_info_using_rrdset_labels(rc);
1202
-
1203
- if (update_disabled_silenced(host, rc))
1204
- continue;
1205
-
1206
- // create an alert removed event if the chart is obsolete and
1207
- // has stopped being collected for 60 seconds
1208
- if (unlikely(rc->rrdset && rc->status != RRDCALC_STATUS_REMOVED &&
1209
- rrdset_flag_check(rc->rrdset, RRDSET_FLAG_OBSOLETE) &&
1210
- now > (rc->rrdset->last_collected_time.tv_sec + 60))) {
1211
- if (!rrdcalc_isrepeating(rc)) {
1212
- worker_is_busy(WORKER_HEALTH_JOB_ALARM_LOG_ENTRY);
1213
- time_t now = now_realtime_sec();
1214
-
1215
- ALARM_ENTRY *ae = health_create_alarm_entry(
1216
- host,
1217
- rc->id,
1218
- rc->next_event_id++,
1219
- rc->config_hash_id,
1220
- now,
1221
- rc->name,
1222
- rc->rrdset->id,
1223
- rc->rrdset->context,
1224
- rc->rrdset->name,
1225
- rc->classification,
1226
- rc->component,
1227
- rc->type,
1228
- rc->exec,
1229
- rc->recipient,
1230
- now - rc->last_status_change,
1231
- rc->value,
1232
- NAN,
1233
- rc->status,
1234
- RRDCALC_STATUS_REMOVED,
1235
- rc->source,
1236
- rc->units,
1237
- rc->summary,
1238
- rc->info,
1239
- 0,
1240
- rrdcalc_isrepeating(rc)?HEALTH_ENTRY_FLAG_IS_REPEATING:0);
1241
-
1242
- if (ae) {
1243
- health_log_alert(host, ae);
1244
- health_alarm_log_add_entry(host, ae);
1245
- rc->old_status = rc->status;
1246
- rc->status = RRDCALC_STATUS_REMOVED;
1247
- rc->last_status_change = now;
1248
- rc->last_status_change_value = rc->value;
1249
- rc->last_updated = now;
1250
- rc->value = NAN;
1251
-
1252
-#ifdef ENABLE_ACLK
1253
- if (netdata_cloud_enabled)
1254
- sql_queue_alarm_to_aclk(host, ae, true);
1255
-#endif
1256
- }
1257
- }
1258
- }
1259
-
1260
- if (unlikely(!rrdcalc_isrunnable(rc, now, &next_run))) {
1261
- if (unlikely(rc->run_flags & RRDCALC_FLAG_RUNNABLE))
1262
- rc->run_flags &= ~RRDCALC_FLAG_RUNNABLE;
1263
- continue;
1264
- }
1265
-
1266
- runnable++;
1267
- rc->old_value = rc->value;
1268
- rc->run_flags |= RRDCALC_FLAG_RUNNABLE;
1269
-
1270
- // ------------------------------------------------------------
1271
- // if there is database lookup, do it
1272
-
1273
- if (unlikely(RRDCALC_HAS_DB_LOOKUP(rc))) {
1274
- worker_is_busy(WORKER_HEALTH_JOB_DB_QUERY);
1275
-
1276
- /* time_t old_db_timestamp = rc->db_before; */
1277
- int value_is_null = 0;
1278
-
1279
- int ret = rrdset2value_api_v1(rc->rrdset, NULL, &rc->value, rrdcalc_dimensions(rc), 1,
1280
- rc->after, rc->before, rc->group, NULL,
1281
- 0, rc->options | RRDR_OPTION_SELECTED_TIER,
1282
- &rc->db_after,&rc->db_before,
1283
- NULL, NULL, NULL,
1284
- &value_is_null, NULL, 0, 0,
1285
- QUERY_SOURCE_HEALTH, STORAGE_PRIORITY_LOW);
1286
-
1287
- if (unlikely(ret != 200)) {
1288
- // database lookup failed
1289
- rc->value = NAN;
1290
- rc->run_flags |= RRDCALC_FLAG_DB_ERROR;
1291
-
1292
- netdata_log_debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': database lookup returned error %d",
1293
- rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc), ret
1294
- );
1295
- } else
1296
- rc->run_flags &= ~RRDCALC_FLAG_DB_ERROR;
1297
-
1298
- if (unlikely(value_is_null)) {
1299
- // collected value is null
1300
- rc->value = NAN;
1301
- rc->run_flags |= RRDCALC_FLAG_DB_NAN;
1302
-
1303
- netdata_log_debug(D_HEALTH,
1304
- "Health on host '%s', alarm '%s.%s': database lookup returned empty value (possibly value is not collected yet)",
1305
- rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc)
1306
- );
1307
- } else
1308
- rc->run_flags &= ~RRDCALC_FLAG_DB_NAN;
1309
-
1310
- netdata_log_debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': database lookup gave value " NETDATA_DOUBLE_FORMAT,
1311
- rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc), rc->value
1312
- );
1313
- }
1314
-
1315
- // ------------------------------------------------------------
1316
- // if there is calculation expression, run it
1317
-
1318
- if (unlikely(rc->calculation)) {
1319
- worker_is_busy(WORKER_HEALTH_JOB_CALC_EVAL);
1320
-
1321
- if (unlikely(!expression_evaluate(rc->calculation))) {
1322
- // calculation failed
1323
- rc->value = NAN;
1324
- rc->run_flags |= RRDCALC_FLAG_CALC_ERROR;
1325
-
1326
- netdata_log_debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': expression '%s' failed: %s",
1327
- rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc),
1328
- rc->calculation->parsed_as, buffer_tostring(rc->calculation->error_msg)
1329
- );
1330
- } else {
1331
- rc->run_flags &= ~RRDCALC_FLAG_CALC_ERROR;
1332
-
1333
- netdata_log_debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': expression '%s' gave value "
1334
- NETDATA_DOUBLE_FORMAT
1335
- ": %s (source: %s)", rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc),
1336
- rc->calculation->parsed_as, rc->calculation->result,
1337
- buffer_tostring(rc->calculation->error_msg), rrdcalc_source(rc)
1338
- );
1339
-
1340
- rc->value = rc->calculation->result;
1341
- }
1342
- }
1343
- }
1344
- foreach_rrdcalc_in_rrdhost_done(rc);
1345
-
1346
- if (unlikely(runnable && service_running(SERVICE_HEALTH))) {
1347
- foreach_rrdcalc_in_rrdhost_read(host, rc) {
1348
- if(unlikely(!service_running(SERVICE_HEALTH)))
1349
- break;
1350
-
1351
- if (unlikely(!(rc->run_flags & RRDCALC_FLAG_RUNNABLE)))
1352
- continue;
1353
-
1354
- if (rc->run_flags & RRDCALC_FLAG_DISABLED) {
1355
- continue;
1356
- }
1357
- RRDCALC_STATUS warning_status = RRDCALC_STATUS_UNDEFINED;
1358
- RRDCALC_STATUS critical_status = RRDCALC_STATUS_UNDEFINED;
1359
-
1360
- // --------------------------------------------------------
1361
- // check the warning expression
1362
-
1363
- if (likely(rc->warning)) {
1364
- worker_is_busy(WORKER_HEALTH_JOB_WARNING_EVAL);
1365
-
1366
- if (unlikely(!expression_evaluate(rc->warning))) {
1367
- // calculation failed
1368
- rc->run_flags |= RRDCALC_FLAG_WARN_ERROR;
1369
-
1370
- netdata_log_debug(D_HEALTH,
1371
- "Health on host '%s', alarm '%s.%s': warning expression failed with error: %s",
1372
- rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc),
1373
- buffer_tostring(rc->warning->error_msg)
1374
- );
1375
- } else {
1376
- rc->run_flags &= ~RRDCALC_FLAG_WARN_ERROR;
1377
- netdata_log_debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': warning expression gave value "
1378
- NETDATA_DOUBLE_FORMAT
1379
- ": %s (source: %s)", rrdhost_hostname(host), rrdcalc_chart_name(rc),
1380
- rrdcalc_name(rc), rc->warning->result, buffer_tostring(rc->warning->error_msg), rrdcalc_source(rc)
1381
- );
1382
- warning_status = rrdcalc_value2status(rc->warning->result);
1383
- }
1384
- }
1385
-
1386
- // --------------------------------------------------------
1387
- // check the critical expression
1388
-
1389
- if (likely(rc->critical)) {
1390
- worker_is_busy(WORKER_HEALTH_JOB_CRITICAL_EVAL);
1391
-
1392
- if (unlikely(!expression_evaluate(rc->critical))) {
1393
- // calculation failed
1394
- rc->run_flags |= RRDCALC_FLAG_CRIT_ERROR;
1395
-
1396
- netdata_log_debug(D_HEALTH,
1397
- "Health on host '%s', alarm '%s.%s': critical expression failed with error: %s",
1398
- rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc),
1399
- buffer_tostring(rc->critical->error_msg)
1400
- );
1401
- } else {
1402
- rc->run_flags &= ~RRDCALC_FLAG_CRIT_ERROR;
1403
- netdata_log_debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': critical expression gave value "
1404
- NETDATA_DOUBLE_FORMAT
1405
- ": %s (source: %s)", rrdhost_hostname(host), rrdcalc_chart_name(rc),
1406
- rrdcalc_name(rc), rc->critical->result, buffer_tostring(rc->critical->error_msg),
1407
- rrdcalc_source(rc)
1408
- );
1409
- critical_status = rrdcalc_value2status(rc->critical->result);
1410
- }
1411
- }
1412
-
1413
- // --------------------------------------------------------
1414
- // decide the final alarm status
1415
-
1416
- RRDCALC_STATUS status = RRDCALC_STATUS_UNDEFINED;
1417
-
1418
- switch (warning_status) {
1419
- case RRDCALC_STATUS_CLEAR:
1420
- status = RRDCALC_STATUS_CLEAR;
1421
- break;
1422
-
1423
- case RRDCALC_STATUS_RAISED:
1424
- status = RRDCALC_STATUS_WARNING;
1425
- break;
1426
-
1427
- default:
1428
- break;
1429
- }
1430
-
1431
- switch (critical_status) {
1432
- case RRDCALC_STATUS_CLEAR:
1433
- if (status == RRDCALC_STATUS_UNDEFINED)
1434
- status = RRDCALC_STATUS_CLEAR;
1435
- break;
1436
-
1437
- case RRDCALC_STATUS_RAISED:
1438
- status = RRDCALC_STATUS_CRITICAL;
1439
- break;
1440
-
1441
- default:
1442
- break;
1443
- }
1444
-
1445
- // --------------------------------------------------------
1446
- // check if the new status and the old differ
1447
-
1448
- if (status != rc->status) {
1449
-
1450
- worker_is_busy(WORKER_HEALTH_JOB_ALARM_LOG_ENTRY);
1451
- int delay = 0;
1452
-
1453
- // apply trigger hysteresis
1454
-
1455
- if (now > rc->delay_up_to_timestamp) {
1456
- rc->delay_up_current = rc->delay_up_duration;
1457
- rc->delay_down_current = rc->delay_down_duration;
1458
- rc->delay_last = 0;
1459
- rc->delay_up_to_timestamp = 0;
1460
- } else {
1461
- rc->delay_up_current = (int) (rc->delay_up_current * rc->delay_multiplier);
1462
- if (rc->delay_up_current > rc->delay_max_duration)
1463
- rc->delay_up_current = rc->delay_max_duration;
1464
-
1465
- rc->delay_down_current = (int) (rc->delay_down_current * rc->delay_multiplier);
1466
- if (rc->delay_down_current > rc->delay_max_duration)
1467
- rc->delay_down_current = rc->delay_max_duration;
1468
- }
1469
-
1470
- if (status > rc->status)
1471
- delay = rc->delay_up_current;
1472
- else
1473
- delay = rc->delay_down_current;
1474
-
1475
- // COMMENTED: because we do need to send raising alarms
1476
- // if(now + delay < rc->delay_up_to_timestamp)
1477
- // delay = (int)(rc->delay_up_to_timestamp - now);
1478
-
1479
- rc->delay_last = delay;
1480
- rc->delay_up_to_timestamp = now + delay;
1481
-
1482
- ALARM_ENTRY *ae = health_create_alarm_entry(
1483
- host,
1484
- rc->id,
1485
- rc->next_event_id++,
1486
- rc->config_hash_id,
1487
- now,
1488
- rc->name,
1489
- rc->rrdset->id,
1490
- rc->rrdset->context,
1491
- rc->rrdset->name,
1492
- rc->classification,
1493
- rc->component,
1494
- rc->type,
1495
- rc->exec,
1496
- rc->recipient,
1497
- now - rc->last_status_change,
1498
- rc->old_value,
1499
- rc->value,
1500
- rc->status,
1501
- status,
1502
- rc->source,
1503
- rc->units,
1504
- rc->summary,
1505
- rc->info,
1506
- rc->delay_last,
1507
- (
1508
- ((rc->options & RRDCALC_OPTION_NO_CLEAR_NOTIFICATION)? HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION : 0) |
1509
- ((rc->run_flags & RRDCALC_FLAG_SILENCED)? HEALTH_ENTRY_FLAG_SILENCED : 0) |
1510
- (rrdcalc_isrepeating(rc)?HEALTH_ENTRY_FLAG_IS_REPEATING:0)
1511
- )
1512
- );
1513
-
1514
- health_log_alert(host, ae);
1515
- health_alarm_log_add_entry(host, ae);
1516
-
1517
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
1518
- "[%s]: Alert event for [%s.%s], value [%s], status [%s].",
1519
- rrdhost_hostname(host), ae_chart_id(ae), ae_name(ae), ae_new_value_string(ae),
1520
- rrdcalc_status2string(ae->new_status));
1521
-
1522
- rc->last_status_change_value = rc->value;
1523
- rc->last_status_change = now;
1524
- rc->old_status = rc->status;
1525
- rc->status = status;
1526
-
1527
- if(unlikely(rrdcalc_isrepeating(rc))) {
1528
- rc->last_repeat = now;
1529
- if (rc->status == RRDCALC_STATUS_CLEAR)
1530
- rc->run_flags |= RRDCALC_FLAG_RUN_ONCE;
1531
- }
1532
- }
1533
-
1534
- rc->last_updated = now;
1535
- rc->next_update = now + rc->update_every;
1536
-
1537
- if (next_run > rc->next_update)
1538
- next_run = rc->next_update;
1539
- }
1540
- foreach_rrdcalc_in_rrdhost_done(rc);
1541
-
1542
- // process repeating alarms
1543
- foreach_rrdcalc_in_rrdhost_read(host, rc) {
1544
- if(unlikely(!service_running(SERVICE_HEALTH)))
1545
- break;
1546
-
1547
- int repeat_every = 0;
1548
- if(unlikely(rrdcalc_isrepeating(rc) && rc->delay_up_to_timestamp <= now)) {
1549
- if(unlikely(rc->status == RRDCALC_STATUS_WARNING)) {
1550
- rc->run_flags &= ~RRDCALC_FLAG_RUN_ONCE;
1551
- repeat_every = rc->warn_repeat_every;
1552
- } else if(unlikely(rc->status == RRDCALC_STATUS_CRITICAL)) {
1553
- rc->run_flags &= ~RRDCALC_FLAG_RUN_ONCE;
1554
- repeat_every = rc->crit_repeat_every;
1555
- } else if(unlikely(rc->status == RRDCALC_STATUS_CLEAR)) {
1556
- if(!(rc->run_flags & RRDCALC_FLAG_RUN_ONCE)) {
1557
- if(rc->old_status == RRDCALC_STATUS_CRITICAL) {
1558
- repeat_every = 1;
1559
- } else if (rc->old_status == RRDCALC_STATUS_WARNING) {
1560
- repeat_every = 1;
1561
- }
1562
- }
1563
- }
1564
- } else {
1565
- continue;
1566
- }
1567
-
1568
- if(unlikely(repeat_every > 0 && (rc->last_repeat + repeat_every) <= now)) {
1569
- worker_is_busy(WORKER_HEALTH_JOB_ALARM_LOG_ENTRY);
1570
- rc->last_repeat = now;
1571
- if (likely(rc->times_repeat < UINT32_MAX)) rc->times_repeat++;
1572
- ALARM_ENTRY *ae = health_create_alarm_entry(
1573
- host,
1574
- rc->id,
1575
- rc->next_event_id++,
1576
- rc->config_hash_id,
1577
- now,
1578
- rc->name,
1579
- rc->rrdset->id,
1580
- rc->rrdset->context,
1581
- rc->rrdset->name,
1582
- rc->classification,
1583
- rc->component,
1584
- rc->type,
1585
- rc->exec,
1586
- rc->recipient,
1587
- now - rc->last_status_change,
1588
- rc->old_value,
1589
- rc->value,
1590
- rc->old_status,
1591
- rc->status,
1592
- rc->source,
1593
- rc->units,
1594
- rc->summary,
1595
- rc->info,
1596
- rc->delay_last,
1597
- (
1598
- ((rc->options & RRDCALC_OPTION_NO_CLEAR_NOTIFICATION)? HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION : 0) |
1599
- ((rc->run_flags & RRDCALC_FLAG_SILENCED)? HEALTH_ENTRY_FLAG_SILENCED : 0) |
1600
- (rrdcalc_isrepeating(rc)?HEALTH_ENTRY_FLAG_IS_REPEATING:0)
1601
- )
1602
- );
1603
-
1604
- health_log_alert(host, ae);
1605
- ae->last_repeat = rc->last_repeat;
1606
- if (!(rc->run_flags & RRDCALC_FLAG_RUN_ONCE) && rc->status == RRDCALC_STATUS_CLEAR) {
1607
- ae->flags |= HEALTH_ENTRY_RUN_ONCE;
1608
- }
1609
- rc->run_flags |= RRDCALC_FLAG_RUN_ONCE;
1610
- health_process_notifications(host, ae);
1611
- netdata_log_debug(D_HEALTH, "Notification sent for the repeating alarm %u.", ae->alarm_id);
1612
- health_alarm_wait_for_execution(ae);
1613
- health_alarm_log_free_one_nochecks_nounlink(ae);
1614
- }
1615
- }
1616
- foreach_rrdcalc_in_rrdhost_done(rc);
1617
- }
1618
-
1619
- if (unlikely(!service_running(SERVICE_HEALTH)))
1620
- break;
1621
-
1622
- // execute notifications
1623
- // and cleanup
1624
- worker_is_busy(WORKER_HEALTH_JOB_ALARM_LOG_PROCESS);
1625
- health_alarm_log_process(host);
1626
-
1627
- if (unlikely(!service_running(SERVICE_HEALTH))) {
1628
- // wait for all notifications to finish before allowing health to be cleaned up
1629
- ALARM_ENTRY *ae;
1630
- while (NULL != (ae = alarm_notifications_in_progress.head)) {
1631
- if(unlikely(!service_running(SERVICE_HEALTH)))
1632
- break;
1633
-
1634
- health_alarm_wait_for_execution(ae);
1635
- }
1636
- break;
1637
- }
1638
-#ifdef ENABLE_ACLK
1639
- if (netdata_cloud_enabled) {
1640
- struct aclk_sync_cfg_t *wc = host->aclk_config;
1641
- if (unlikely(!wc))
1642
- continue;
1643
-
1644
- if (wc->alert_queue_removed == 1) {
1645
- sql_queue_removed_alerts_to_aclk(host);
1646
- } else if (wc->alert_queue_removed > 1) {
1647
- wc->alert_queue_removed--;
1648
- }
1649
-
1650
- if (wc->alert_checkpoint_req == 1) {
1651
- aclk_push_alarm_checkpoint(host);
1652
- } else if (wc->alert_checkpoint_req > 1) {
1653
- wc->alert_checkpoint_req--;
1654
- }
1655
- }
1656
-#endif
1657
- }
1658
- dfe_done(host);
1659
-
1660
- // wait for all notifications to finish before allowing health to be cleaned up
1661
- ALARM_ENTRY *ae;
1662
- while (NULL != (ae = alarm_notifications_in_progress.head)) {
1663
- if(unlikely(!service_running(SERVICE_HEALTH)))
1664
- break;
1665
-
1666
- health_alarm_wait_for_execution(ae);
1667
- }
1668
-
1669
- if(unlikely(!service_running(SERVICE_HEALTH)))
1670
- break;
1671
-
1672
- health_sleep(next_run, loop);
1673
-
1674
- } // forever
1675
-
1676
- netdata_thread_cleanup_pop(1);
1677
- return NULL;
169
+void health_plugin_reload(void) {
170
+ health_reload_prototypes();
171
+ health_apply_prototypes_to_all_hosts();
172
}