log alarm notifications to health.log (#16476)
Costa Tsaousis committed
Nov 30, 2023 at 14:46 UTC
d477387b985aa90e64292ddc3fe210aa44c4cc0b
4 files changed
+44
-10
libnetdata/log/README.md
+1
-1
@@ -18,7 +18,7 @@ Netdata supports the following log sources:
18
1. **daemon**, logs generated by Netdata daemon.
19
2. **collector**, logs generated by Netdata collectors, including internal and external ones.
20
3. **access**, API requests received by Netdata
21
-4. **health**, logs all alert transitions
21
+4. **health**, all alert transitions and notifications
22
23
## Log outputs
24
libnetdata/log/log.c
+41
-8
@@ -245,7 +245,7 @@ const char *nd_log_id2priority(ND_LOG_FIELD_PRIORITY priority) {
245
// ----------------------------------------------------------------------------
246
// log sources
247
248
-const char *log_sources_str[] = {
248
+const char *nd_log_sources[] = {
249
[NDLS_UNSET] = "UNSET",
250
[NDLS_ACCESS] = "access",
251
[NDLS_ACLK] = "aclk",
@@ -255,12 +255,23 @@ const char *log_sources_str[] = {
255
[NDLS_DEBUG] = "debug",
256
};
257
258
-static const char *nd_log_source2str(ND_LOG_SOURCES source) {
259
- size_t entries = sizeof(log_sources_str) / sizeof(log_sources_str[0]);
258
+size_t nd_log_source2id(const char *source, ND_LOG_SOURCES def) {
259
+ size_t entries = sizeof(nd_log_sources) / sizeof(nd_log_sources[0]);
260
+ for(size_t i = 0; i < entries ;i++) {
261
+ if(strcmp(nd_log_sources[i], source) == 0)
262
+ return i;
263
+ }
264
+
265
+ return def;
266
+}
267
+
268
+
269
+static const char *nd_log_id2source(ND_LOG_SOURCES source) {
270
+ size_t entries = sizeof(nd_log_sources) / sizeof(nd_log_sources[0]);
271
if(source < entries)
261
- return log_sources_str[source];
272
+ return nd_log_sources[source];
273
263
- return "UNKNOWN";
274
+ return nd_log_sources[NDLS_COLLECTORS];
275
}
276
277
// ----------------------------------------------------------------------------
@@ -503,6 +514,13 @@ __attribute__((constructor)) void initialize_invocation_id(void) {
514
setenv("NETDATA_INVOCATION_ID", uuid, 1);
515
}
516
517
+int nd_log_health_fd(void) {
518
+ if(nd_log.sources[NDLS_HEALTH].method == NDLM_FILE && nd_log.sources[NDLS_HEALTH].fd != -1)
519
+ return nd_log.sources[NDLS_HEALTH].fd;
520
+
521
+ return STDERR_FILENO;
522
+}
523
+
524
void nd_log_set_user_settings(ND_LOG_SOURCES source, const char *setting) {
525
char buf[FILENAME_MAX + 100];
526
if(setting && *setting)
@@ -563,7 +581,7 @@ void nd_log_set_user_settings(ND_LOG_SOURCES source, const char *setting) {
581
else
582
nd_log(NDLS_DAEMON, NDLP_ERR, "Error while parsing configuration of log source '%s'. "
583
"In config '%s', '%s' is not understood.",
566
- nd_log_source2str(source), setting, name);
584
+ nd_log_id2source(source), setting, name);
585
}
586
}
587
@@ -2079,7 +2097,22 @@ static void nd_logger(const char *file, const char *function, const unsigned lon
2097
thread_log_fields[NDF_INVOCATION_ID].entry = ND_LOG_FIELD_UUID(NDF_INVOCATION_ID, &nd_log.invocation_id);
2098
2099
if(likely(!thread_log_fields[NDF_LOG_SOURCE].entry.set))
2082
- thread_log_fields[NDF_LOG_SOURCE].entry = ND_LOG_FIELD_TXT(NDF_LOG_SOURCE, nd_log_source2str(source));
2100
+ thread_log_fields[NDF_LOG_SOURCE].entry = ND_LOG_FIELD_TXT(NDF_LOG_SOURCE, nd_log_id2source(source));
2101
+ else {
2102
+ ND_LOG_SOURCES src = source;
2103
+
2104
+ if(thread_log_fields[NDF_LOG_SOURCE].entry.type == NDFT_TXT)
2105
+ src = nd_log_source2id(thread_log_fields[NDF_LOG_SOURCE].entry.txt, source);
2106
+ else if(thread_log_fields[NDF_LOG_SOURCE].entry.type == NDFT_U64)
2107
+ src = thread_log_fields[NDF_LOG_SOURCE].entry.u64;
2108
+
2109
+ if(src != source && src >= 0 && src < _NDLS_MAX) {
2110
+ source = src;
2111
+ output = nd_logger_select_output(source, &fp, &spinlock);
2112
+ if(output != NDLM_FILE && output != NDLM_JOURNAL && output != NDLM_SYSLOG)
2113
+ return;
2114
+ }
2115
+ }
2116
2117
if(likely(!thread_log_fields[NDF_SYSLOG_IDENTIFIER].entry.set))
2118
thread_log_fields[NDF_SYSLOG_IDENTIFIER].entry = ND_LOG_FIELD_TXT(NDF_SYSLOG_IDENTIFIER, program_name);
@@ -2145,7 +2178,7 @@ static void nd_logger(const char *file, const char *function, const unsigned lon
2178
thread_log_fields[NDF_LOG_SOURCE].entry = (struct log_stack_entry){
2179
.set = true,
2180
.type = NDFT_TXT,
2148
- .txt = nd_log_source2str(source),
2181
+ .txt = nd_log_id2source(source),
2182
};
2183
2184
thread_log_fields[NDF_SYSLOG_IDENTIFIER].entry = (struct log_stack_entry){
libnetdata/log/log.h
+1
@@ -149,6 +149,7 @@ int nd_log_priority2id(const char *priority);
149
const char *nd_log_id2priority(ND_LOG_FIELD_PRIORITY priority);
150
const char *nd_log_method_for_external_plugins(const char *s);
151
152
+int nd_log_health_fd(void);
153
typedef bool (*log_formatter_callback_t)(BUFFER *wb, void *data);
154
155
struct log_stack_entry {
spawn/spawn.c
+1
-1
@@ -215,7 +215,7 @@ int create_spawn_server(uv_loop_t *loop, uv_pipe_t *spawn_channel, uv_process_t
215
stdio[1].flags = UV_INHERIT_FD;
216
stdio[1].data.fd = 1 /* UV_STDOUT_FD */;
217
stdio[2].flags = UV_INHERIT_FD;
218
- stdio[2].data.fd = 2 /* UV_STDERR_FD */;
218
+ stdio[2].data.fd = nd_log_health_fd() /* UV_STDERR_FD */;
219
220
ret = uv_spawn(loop, process, &options); /* execute the netdata binary again as the netdata user */
221
if (0 != ret) {