master
c 825 lines 23.8 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "nd_log-internals.h"
4
5 // --------------------------------------------------------------------------------------------------------------------
6 // workaround strerror_r()
7
8 #if defined(STRERROR_R_CHAR_P)
9 // GLIBC version of strerror_r
10 static const char *strerror_result(const char *a, const char *b) { (void)b; return a; }
11 #elif defined(HAVE_STRERROR_R)
12 // POSIX version of strerror_r
13 static const char *strerror_result(int a, const char *b) { (void)a; return b; }
14 #elif defined(HAVE_C__GENERIC)
15
16 // what a trick!
17 // http://stackoverflow.com/questions/479207/function-overloading-in-c
18 static const char *strerror_result_int(int a, const char *b) { (void)a; return b; }
19 static const char *strerror_result_string(const char *a, const char *b) { (void)b; return a; }
20
21 #define strerror_result(a, b) _Generic((a), \
22 int: strerror_result_int, \
23 char *: strerror_result_string \
24 )(a, b)
25
26 #else
27 #error "cannot detect the format of function strerror_r()"
28 #endif
29
30 const char *errno2str(int errnum, char *buf, size_t size) {
31 return strerror_result(strerror_r(errnum, buf, size), buf);
32 }
33
34 // --------------------------------------------------------------------------------------------------------------------
35 // logging method
36
37 static struct {
38 ND_LOG_METHOD method;
39 const char *name;
40 } nd_log_methods[] = {
41 { .method = NDLM_DISABLED, .name = "none" },
42 { .method = NDLM_DEVNULL, .name = "/dev/null" },
43 { .method = NDLM_DEFAULT, .name = "default" },
44 { .method = NDLM_JOURNAL, .name = "journal" },
45 { .method = NDLM_SYSLOG, .name = "syslog" },
46 { .method = NDLM_STDOUT, .name = "stdout" },
47 { .method = NDLM_STDERR, .name = "stderr" },
48 { .method = NDLM_FILE, .name = "file" },
49 #if defined(OS_WINDOWS)
50 #if defined(HAVE_ETW)
51 { .method = NDLM_ETW, .name = ETW_NAME },
52 #endif
53 #if defined(HAVE_WEL)
54 { .method = NDLM_WEL, .name = WEL_NAME },
55 #endif
56 #endif
57 };
58
59 ND_LOG_METHOD nd_log_method2id(const char *method) {
60 if(!method || !*method)
61 return NDLM_DEFAULT;
62
63 size_t entries = sizeof(nd_log_methods) / sizeof(nd_log_methods[0]);
64 for(size_t i = 0; i < entries ;i++) {
65 if(strcmp(nd_log_methods[i].name, method) == 0)
66 return nd_log_methods[i].method;
67 }
68
69 return NDLM_FILE;
70 }
71
72 const char *nd_log_id2method(ND_LOG_METHOD method) {
73 size_t entries = sizeof(nd_log_methods) / sizeof(nd_log_methods[0]);
74 for(size_t i = 0; i < entries ;i++) {
75 if(method == nd_log_methods[i].method)
76 return nd_log_methods[i].name;
77 }
78
79 return "unknown";
80 }
81
82 const char *nd_log_method_for_external_plugins(const char *s) {
83 if(s && *s) {
84 ND_LOG_METHOD method = nd_log_method2id(s);
85 if(IS_VALID_LOG_METHOD_FOR_EXTERNAL_PLUGINS(method))
86 return nd_log_id2method(method);
87 }
88
89 return nd_log_id2method(NDLM_STDERR);
90 }
91
92 // --------------------------------------------------------------------------------------------------------------------
93 // facilities
94 //
95 // sys/syslog.h (Linux)
96 // sys/sys/syslog.h (FreeBSD)
97 // bsd/sys/syslog.h (darwin-xnu)
98
99 static struct {
100 int facility;
101 const char *name;
102 } nd_log_facilities[] = {
103 { LOG_AUTH, "auth" },
104 { LOG_AUTHPRIV, "authpriv" },
105 { LOG_CRON, "cron" },
106 { LOG_DAEMON, "daemon" },
107 { LOG_FTP, "ftp" },
108 { LOG_KERN, "kern" },
109 { LOG_LPR, "lpr" },
110 { LOG_MAIL, "mail" },
111 { LOG_NEWS, "news" },
112 { LOG_SYSLOG, "syslog" },
113 { LOG_USER, "user" },
114 { LOG_UUCP, "uucp" },
115 { LOG_LOCAL0, "local0" },
116 { LOG_LOCAL1, "local1" },
117 { LOG_LOCAL2, "local2" },
118 { LOG_LOCAL3, "local3" },
119 { LOG_LOCAL4, "local4" },
120 { LOG_LOCAL5, "local5" },
121 { LOG_LOCAL6, "local6" },
122 { LOG_LOCAL7, "local7" },
123
124 #ifdef __FreeBSD__
125 { LOG_CONSOLE, "console" },
126 { LOG_NTP, "ntp" },
127
128 // FreeBSD does not consider 'security' as deprecated.
129 { LOG_SECURITY, "security" },
130 #else
131 // For all other O/S 'security' is mapped to 'auth'.
132 { LOG_AUTH, "security" },
133 #endif
134
135 #ifdef __APPLE__
136 { LOG_INSTALL, "install" },
137 { LOG_NETINFO, "netinfo" },
138 { LOG_RAS, "ras" },
139 { LOG_REMOTEAUTH, "remoteauth" },
140 { LOG_LAUNCHD, "launchd" },
141
142 #endif
143 };
144
145 int nd_log_facility2id(const char *facility) {
146 size_t entries = sizeof(nd_log_facilities) / sizeof(nd_log_facilities[0]);
147 for(size_t i = 0; i < entries ;i++) {
148 if(strcmp(nd_log_facilities[i].name, facility) == 0)
149 return nd_log_facilities[i].facility;
150 }
151
152 return LOG_DAEMON;
153 }
154
155 const char *nd_log_id2facility(int facility) {
156 size_t entries = sizeof(nd_log_facilities) / sizeof(nd_log_facilities[0]);
157 for(size_t i = 0; i < entries ;i++) {
158 if(nd_log_facilities[i].facility == facility)
159 return nd_log_facilities[i].name;
160 }
161
162 return "daemon";
163 }
164
165 // --------------------------------------------------------------------------------------------------------------------
166 // priorities
167
168 static struct {
169 ND_LOG_FIELD_PRIORITY priority;
170 const char *name;
171 } nd_log_priorities[] = {
172 { .priority = NDLP_EMERG, .name = "emergency" },
173 { .priority = NDLP_EMERG, .name = "emerg" },
174 { .priority = NDLP_ALERT, .name = "alert" },
175 { .priority = NDLP_CRIT, .name = "critical" },
176 { .priority = NDLP_CRIT, .name = "crit" },
177 { .priority = NDLP_ERR, .name = "error" },
178 { .priority = NDLP_ERR, .name = "err" },
179 { .priority = NDLP_WARNING, .name = "warning" },
180 { .priority = NDLP_WARNING, .name = "warn" },
181 { .priority = NDLP_NOTICE, .name = "notice" },
182 { .priority = NDLP_INFO, .name = NDLP_INFO_STR },
183 { .priority = NDLP_DEBUG, .name = "debug" },
184 };
185
186 int nd_log_priority2id(const char *priority) {
187 size_t entries = sizeof(nd_log_priorities) / sizeof(nd_log_priorities[0]);
188 for(size_t i = 0; i < entries ;i++) {
189 if(strcmp(nd_log_priorities[i].name, priority) == 0)
190 return nd_log_priorities[i].priority;
191 }
192
193 return NDLP_INFO;
194 }
195
196 const char *nd_log_id2priority(ND_LOG_FIELD_PRIORITY priority) {
197 size_t entries = sizeof(nd_log_priorities) / sizeof(nd_log_priorities[0]);
198 for(size_t i = 0; i < entries ;i++) {
199 if(priority == nd_log_priorities[i].priority)
200 return nd_log_priorities[i].name;
201 }
202
203 return NDLP_INFO_STR;
204 }
205
206 // --------------------------------------------------------------------------------------------------------------------
207 // log sources
208
209 const char *nd_log_sources[] = {
210 [NDLS_UNSET] = "UNSET",
211 [NDLS_ACCESS] = "access",
212 [NDLS_ACLK] = "aclk",
213 [NDLS_COLLECTORS] = "collector",
214 [NDLS_DAEMON] = "daemon",
215 [NDLS_HEALTH] = "health",
216 [NDLS_DEBUG] = "debug",
217 };
218
219 size_t nd_log_source2id(const char *source, ND_LOG_SOURCES def) {
220 size_t entries = sizeof(nd_log_sources) / sizeof(nd_log_sources[0]);
221 for(size_t i = 0; i < entries ;i++) {
222 if(strcmp(nd_log_sources[i], source) == 0)
223 return i;
224 }
225
226 return def;
227 }
228
229
230 const char *nd_log_id2source(ND_LOG_SOURCES source) {
231 size_t entries = sizeof(nd_log_sources) / sizeof(nd_log_sources[0]);
232 if(source < entries)
233 return nd_log_sources[source];
234
235 return nd_log_sources[NDLS_COLLECTORS];
236 }
237
238 // --------------------------------------------------------------------------------------------------------------------
239 // log output formats
240
241 static struct {
242 ND_LOG_FORMAT format;
243 const char *name;
244 } nd_log_formats[] = {
245 { .format = NDLF_JOURNAL, .name = "journal" },
246 { .format = NDLF_LOGFMT, .name = "logfmt" },
247 { .format = NDLF_JSON, .name = "json" },
248 #if defined(OS_WINDOWS)
249 #if defined(HAVE_ETW)
250 { .format = NDLF_ETW, .name = ETW_NAME },
251 #endif
252 #if defined(HAVE_WEL)
253 { .format = NDLF_WEL, .name = WEL_NAME },
254 #endif
255 #endif
256 };
257
258 ND_LOG_FORMAT nd_log_format2id(const char *format) {
259 if(!format || !*format)
260 return NDLF_LOGFMT;
261
262 size_t entries = sizeof(nd_log_formats) / sizeof(nd_log_formats[0]);
263 for(size_t i = 0; i < entries ;i++) {
264 if(strcmp(nd_log_formats[i].name, format) == 0)
265 return nd_log_formats[i].format;
266 }
267
268 return NDLF_LOGFMT;
269 }
270
271 const char *nd_log_id2format(ND_LOG_FORMAT format) {
272 size_t entries = sizeof(nd_log_formats) / sizeof(nd_log_formats[0]);
273 for(size_t i = 0; i < entries ;i++) {
274 if(format == nd_log_formats[i].format)
275 return nd_log_formats[i].name;
276 }
277
278 return "logfmt";
279 }
280
281 // --------------------------------------------------------------------------------------------------------------------
282
283 struct nd_log nd_log = {
284 .overwrite_process_source = 0,
285 .journal = {
286 .initialized = false,
287 .first_msg = false,
288 .fd = -1,
289 },
290 .journal_direct = {
291 .initialized = false,
292 .fd = -1,
293 },
294 .syslog = {
295 .initialized = false,
296 .facility = LOG_DAEMON,
297 },
298 #if defined(OS_WINDOWS)
299 .eventlog = {
300 .initialized = false,
301 },
302 #endif
303 .std_output = {
304 .initialized = false,
305 },
306 .std_error = {
307 .initialized = false,
308 },
309 .sources = {
310 [NDLS_UNSET] = {
311 .method = NDLM_DISABLED,
312 .format = NDLF_JOURNAL,
313 .filename = NULL,
314 .fd = -1,
315 .fp = NULL,
316 .min_priority = NDLP_EMERG,
317 .limits = ND_LOG_LIMITS_UNLIMITED,
318 },
319 [NDLS_ACCESS] = {
320 .method = NDLM_DEFAULT,
321 .format = NDLF_LOGFMT,
322 .filename = LOG_DIR "/access.log",
323 .fd = -1,
324 .fp = NULL,
325 .min_priority = NDLP_DEBUG,
326 .limits = ND_LOG_LIMITS_UNLIMITED,
327 },
328 [NDLS_ACLK] = {
329 .method = NDLM_FILE,
330 .format = NDLF_LOGFMT,
331 .filename = LOG_DIR "/aclk.log",
332 .fd = -1,
333 .fp = NULL,
334 .min_priority = NDLP_DEBUG,
335 .limits = ND_LOG_LIMITS_UNLIMITED,
336 },
337 [NDLS_COLLECTORS] = {
338 .method = NDLM_DEFAULT,
339 .format = NDLF_LOGFMT,
340 .filename = LOG_DIR "/collector.log",
341 #if defined(FSANITIZE_ADDRESS)
342 .fd = -1,
343 #else
344 .fd = STDERR_FILENO,
345 #endif
346 .fp = NULL,
347 .min_priority = NDLP_INFO,
348 .limits = ND_LOG_LIMITS_DEFAULT,
349 },
350 [NDLS_DEBUG] = {
351 .method = NDLM_DISABLED,
352 .format = NDLF_LOGFMT,
353 .filename = LOG_DIR "/debug.log",
354 #if defined(FSANITIZE_ADDRESS)
355 .fd = -1,
356 #else
357 .fd = STDOUT_FILENO,
358 #endif
359 .fp = NULL,
360 .min_priority = NDLP_DEBUG,
361 .limits = ND_LOG_LIMITS_UNLIMITED,
362 },
363 [NDLS_DAEMON] = {
364 .method = NDLM_DEFAULT,
365 .filename = LOG_DIR "/daemon.log",
366 .format = NDLF_LOGFMT,
367 .fd = -1,
368 .fp = NULL,
369 .min_priority = NDLP_INFO,
370 .limits = ND_LOG_LIMITS_DEFAULT,
371 },
372 [NDLS_HEALTH] = {
373 .method = NDLM_DEFAULT,
374 .format = NDLF_LOGFMT,
375 .filename = LOG_DIR "/health.log",
376 .fd = -1,
377 .fp = NULL,
378 .min_priority = NDLP_DEBUG,
379 .limits = ND_LOG_LIMITS_UNLIMITED,
380 },
381 },
382 };
383
384 // --------------------------------------------------------------------------------------------------------------------
385
386 __thread struct log_stack_entry *thread_log_stack_base[THREAD_LOG_STACK_MAX];
387 __thread size_t thread_log_stack_next = 0;
388 __thread struct log_field thread_log_fields[_NDF_MAX] = {
389 // THE ORDER HERE IS IRRELEVANT (but keep them sorted by their number)
390
391 [NDF_STOP] = { // processing will not stop on this - so it is ok to be first
392 .journal = NULL,
393 .logfmt = NULL,
394 .eventlog = NULL,
395 .logfmt_annotator = NULL,
396 },
397 [NDF_TIMESTAMP_REALTIME_USEC] = {
398 .journal = NULL,
399 .eventlog = "Timestamp",
400 .logfmt = "time",
401 .logfmt_annotator = timestamp_usec_annotator,
402 },
403 [NDF_SYSLOG_IDENTIFIER] = {
404 .journal = "SYSLOG_IDENTIFIER", // standard journald field
405 .eventlog = "Program",
406 .logfmt = "comm",
407 },
408 [NDF_LOG_SOURCE] = {
409 .journal = "ND_LOG_SOURCE",
410 .eventlog = "NetdataLogSource",
411 .logfmt = "source",
412 },
413 [NDF_PRIORITY] = {
414 .journal = "PRIORITY", // standard journald field
415 .eventlog = "Level",
416 .logfmt = "level",
417 .logfmt_annotator = priority_annotator,
418 },
419 [NDF_ERRNO] = {
420 .journal = "ERRNO", // standard journald field
421 .eventlog = "UnixErrno",
422 .logfmt = "errno",
423 .logfmt_annotator = errno_annotator,
424 },
425 [NDF_WINERROR] = {
426 #if defined(OS_WINDOWS)
427 .journal = "WINERROR",
428 .eventlog = "WindowsLastError",
429 .logfmt = "winerror",
430 .logfmt_annotator = winerror_annotator,
431 #endif
432 },
433 [NDF_INVOCATION_ID] = {
434 .journal = "INVOCATION_ID", // standard journald field
435 .eventlog = "InvocationID",
436 .logfmt = NULL,
437 },
438 [NDF_LINE] = {
439 .journal = "CODE_LINE", // standard journald field
440 .eventlog = "CodeLine",
441 .logfmt = NULL,
442 },
443 [NDF_FILE] = {
444 .journal = "CODE_FILE", // standard journald field
445 .eventlog = "CodeFile",
446 .logfmt = NULL,
447 },
448 [NDF_FUNC] = {
449 .journal = "CODE_FUNC", // standard journald field
450 .eventlog = "CodeFunction",
451 .logfmt = NULL,
452 },
453 [NDF_TID] = {
454 .journal = "TID", // standard journald field
455 .eventlog = "ThreadID",
456 .logfmt = "tid",
457 },
458 [NDF_THREAD_TAG] = {
459 .journal = "THREAD_TAG",
460 .eventlog = "ThreadName",
461 .logfmt = "thread",
462 },
463 [NDF_MESSAGE_ID] = {
464 .journal = "MESSAGE_ID",
465 .eventlog = "MessageID",
466 .logfmt = "msg_id",
467 },
468 [NDF_MODULE] = {
469 .journal = "ND_MODULE",
470 .eventlog = "Module",
471 .logfmt = "module",
472 },
473 [NDF_NIDL_NODE] = {
474 .journal = "ND_NIDL_NODE",
475 .eventlog = "Node",
476 .logfmt = "node",
477 },
478 [NDF_NIDL_INSTANCE] = {
479 .journal = "ND_NIDL_INSTANCE",
480 .eventlog = "Instance",
481 .logfmt = "instance",
482 },
483 [NDF_NIDL_CONTEXT] = {
484 .journal = "ND_NIDL_CONTEXT",
485 .eventlog = "Context",
486 .logfmt = "context",
487 },
488 [NDF_NIDL_DIMENSION] = {
489 .journal = "ND_NIDL_DIMENSION",
490 .eventlog = "Dimension",
491 .logfmt = "dimension",
492 },
493 [NDF_SRC_TRANSPORT] = {
494 .journal = "ND_SRC_TRANSPORT",
495 .eventlog = "SourceTransport",
496 .logfmt = "src_transport",
497 },
498 [NDF_ACCOUNT_ID] = {
499 .journal = "ND_ACCOUNT_ID",
500 .eventlog = "AccountID",
501 .logfmt = "account",
502 },
503 [NDF_USER_NAME] = {
504 .journal = "ND_USER_NAME",
505 .eventlog = "UserName",
506 .logfmt = "user",
507 },
508 [NDF_USER_ROLE] = {
509 .journal = "ND_USER_ROLE",
510 .eventlog = "UserRole",
511 .logfmt = "role",
512 },
513 [NDF_USER_ACCESS] = {
514 .journal = "ND_USER_PERMISSIONS",
515 .eventlog = "UserPermissions",
516 .logfmt = "permissions",
517 },
518 [NDF_SRC_IP] = {
519 .journal = "ND_SRC_IP",
520 .eventlog = "SourceIP",
521 .logfmt = "src_ip",
522 },
523 [NDF_SRC_FORWARDED_HOST] = {
524 .journal = "ND_SRC_FORWARDED_HOST",
525 .eventlog = "SourceForwardedHost",
526 .logfmt = "src_forwarded_host",
527 },
528 [NDF_SRC_FORWARDED_FOR] = {
529 .journal = "ND_SRC_FORWARDED_FOR",
530 .eventlog = "SourceForwardedFor",
531 .logfmt = "src_forwarded_for",
532 },
533 [NDF_SRC_PORT] = {
534 .journal = "ND_SRC_PORT",
535 .eventlog = "SourcePort",
536 .logfmt = "src_port",
537 },
538 [NDF_SRC_CAPABILITIES] = {
539 .journal = "ND_SRC_CAPABILITIES",
540 .eventlog = "SourceCapabilities",
541 .logfmt = "src_capabilities",
542 },
543 [NDF_DST_TRANSPORT] = {
544 .journal = "ND_DST_TRANSPORT",
545 .eventlog = "DestinationTransport",
546 .logfmt = "dst_transport",
547 },
548 [NDF_DST_IP] = {
549 .journal = "ND_DST_IP",
550 .eventlog = "DestinationIP",
551 .logfmt = "dst_ip",
552 },
553 [NDF_DST_PORT] = {
554 .journal = "ND_DST_PORT",
555 .eventlog = "DestinationPort",
556 .logfmt = "dst_port",
557 },
558 [NDF_DST_CAPABILITIES] = {
559 .journal = "ND_DST_CAPABILITIES",
560 .eventlog = "DestinationCapabilities",
561 .logfmt = "dst_capabilities",
562 },
563 [NDF_REQUEST_METHOD] = {
564 .journal = "ND_REQUEST_METHOD",
565 .eventlog = "RequestMethod",
566 .logfmt = "req_method",
567 },
568 [NDF_RESPONSE_CODE] = {
569 .journal = "ND_RESPONSE_CODE",
570 .eventlog = "ResponseCode",
571 .logfmt = "code",
572 },
573 [NDF_CONNECTION_ID] = {
574 .journal = "ND_CONNECTION_ID",
575 .eventlog = "ConnectionID",
576 .logfmt = "conn",
577 },
578 [NDF_TRANSACTION_ID] = {
579 .journal = "ND_TRANSACTION_ID",
580 .eventlog = "TransactionID",
581 .logfmt = "transaction",
582 },
583 [NDF_RESPONSE_SENT_BYTES] = {
584 .journal = "ND_RESPONSE_SENT_BYTES",
585 .eventlog = "ResponseSentBytes",
586 .logfmt = "sent_bytes",
587 },
588 [NDF_RESPONSE_SIZE_BYTES] = {
589 .journal = "ND_RESPONSE_SIZE_BYTES",
590 .eventlog = "ResponseSizeBytes",
591 .logfmt = "size_bytes",
592 },
593 [NDF_RESPONSE_PREPARATION_TIME_USEC] = {
594 .journal = "ND_RESPONSE_PREP_TIME_USEC",
595 .eventlog = "ResponsePreparationTimeUsec",
596 .logfmt = "prep_ut",
597 },
598 [NDF_RESPONSE_SENT_TIME_USEC] = {
599 .journal = "ND_RESPONSE_SENT_TIME_USEC",
600 .eventlog = "ResponseSentTimeUsec",
601 .logfmt = "sent_ut",
602 },
603 [NDF_RESPONSE_TOTAL_TIME_USEC] = {
604 .journal = "ND_RESPONSE_TOTAL_TIME_USEC",
605 .eventlog = "ResponseTotalTimeUsec",
606 .logfmt = "total_ut",
607 },
608 [NDF_ALERT_ID] = {
609 .journal = "ND_ALERT_ID",
610 .eventlog = "AlertID",
611 .logfmt = "alert_id",
612 },
613 [NDF_ALERT_UNIQUE_ID] = {
614 .journal = "ND_ALERT_UNIQUE_ID",
615 .eventlog = "AlertUniqueID",
616 .logfmt = "alert_unique_id",
617 },
618 [NDF_ALERT_TRANSITION_ID] = {
619 .journal = "ND_ALERT_TRANSITION_ID",
620 .eventlog = "AlertTransitionID",
621 .logfmt = "alert_transition_id",
622 },
623 [NDF_ALERT_EVENT_ID] = {
624 .journal = "ND_ALERT_EVENT_ID",
625 .eventlog = "AlertEventID",
626 .logfmt = "alert_event_id",
627 },
628 [NDF_ALERT_CONFIG_HASH] = {
629 .journal = "ND_ALERT_CONFIG",
630 .eventlog = "AlertConfig",
631 .logfmt = "alert_config",
632 },
633 [NDF_ALERT_NAME] = {
634 .journal = "ND_ALERT_NAME",
635 .eventlog = "AlertName",
636 .logfmt = "alert",
637 },
638 [NDF_ALERT_CLASS] = {
639 .journal = "ND_ALERT_CLASS",
640 .eventlog = "AlertClass",
641 .logfmt = "alert_class",
642 },
643 [NDF_ALERT_COMPONENT] = {
644 .journal = "ND_ALERT_COMPONENT",
645 .eventlog = "AlertComponent",
646 .logfmt = "alert_component",
647 },
648 [NDF_ALERT_TYPE] = {
649 .journal = "ND_ALERT_TYPE",
650 .eventlog = "AlertType",
651 .logfmt = "alert_type",
652 },
653 [NDF_ALERT_EXEC] = {
654 .journal = "ND_ALERT_EXEC",
655 .eventlog = "AlertExec",
656 .logfmt = "alert_exec",
657 },
658 [NDF_ALERT_RECIPIENT] = {
659 .journal = "ND_ALERT_RECIPIENT",
660 .eventlog = "AlertRecipient",
661 .logfmt = "alert_recipient",
662 },
663 [NDF_ALERT_VALUE] = {
664 .journal = "ND_ALERT_VALUE",
665 .eventlog = "AlertValue",
666 .logfmt = "alert_value",
667 },
668 [NDF_ALERT_VALUE_OLD] = {
669 .journal = "ND_ALERT_VALUE_OLD",
670 .eventlog = "AlertOldValue",
671 .logfmt = "alert_value_old",
672 },
673 [NDF_ALERT_STATUS] = {
674 .journal = "ND_ALERT_STATUS",
675 .eventlog = "AlertStatus",
676 .logfmt = "alert_status",
677 },
678 [NDF_ALERT_STATUS_OLD] = {
679 .journal = "ND_ALERT_STATUS_OLD",
680 .eventlog = "AlertOldStatus",
681 .logfmt = "alert_value_old",
682 },
683 [NDF_ALERT_UNITS] = {
684 .journal = "ND_ALERT_UNITS",
685 .eventlog = "AlertUnits",
686 .logfmt = "alert_units",
687 },
688 [NDF_ALERT_SUMMARY] = {
689 .journal = "ND_ALERT_SUMMARY",
690 .eventlog = "AlertSummary",
691 .logfmt = "alert_summary",
692 },
693 [NDF_ALERT_INFO] = {
694 .journal = "ND_ALERT_INFO",
695 .eventlog = "AlertInfo",
696 .logfmt = "alert_info",
697 },
698 [NDF_ALERT_DURATION] = {
699 .journal = "ND_ALERT_DURATION",
700 .eventlog = "AlertDuration",
701 .logfmt = "alert_duration",
702 },
703 [NDF_ALERT_NOTIFICATION_REALTIME_USEC] = {
704 .journal = "ND_ALERT_NOTIFICATION_TIMESTAMP_USEC",
705 .eventlog = "AlertNotificationTime",
706 .logfmt = "alert_notification_timestamp",
707 .logfmt_annotator = timestamp_usec_annotator,
708 },
709 [NDF_REQUEST] = {
710 .journal = "ND_REQUEST",
711 .eventlog = "Request",
712 .logfmt = "request",
713 },
714 [NDF_MESSAGE] = {
715 .journal = "MESSAGE",
716 .eventlog = "Message",
717 .logfmt = "msg",
718 },
719 [NDF_STACK_TRACE] = {
720 .journal = "ND_STACK_TRACE",
721 .eventlog = "StackTrace",
722 .logfmt = NULL,
723 },
724
725 // put new items here
726 };
727
728 // --------------------------------------------------------------------------------------------------------------------
729
730 void log_stack_pop(void *ptr) {
731 if(!ptr) return;
732
733 struct log_stack_entry *lgs = *(struct log_stack_entry (*)[])ptr;
734
735 if(unlikely(!thread_log_stack_next || lgs != thread_log_stack_base[thread_log_stack_next - 1])) {
736 fatal("You cannot pop in the middle of the stack, or an item not in the stack");
737 return;
738 }
739
740 thread_log_stack_next--;
741 }
742
743 void log_stack_push(struct log_stack_entry *lgs) {
744 if(!lgs || thread_log_stack_next >= THREAD_LOG_STACK_MAX) return;
745 thread_log_stack_base[thread_log_stack_next++] = lgs;
746 }
747
748 // --------------------------------------------------------------------------------------------------------------------
749
750 ND_LOG_FIELD_ID nd_log_field_id_by_journal_name(const char *field, size_t len) {
751 for(size_t i = 0; i < THREAD_FIELDS_MAX ;i++) {
752 if(thread_log_fields[i].journal && strlen(thread_log_fields[i].journal) == len && strncmp(field, thread_log_fields[i].journal, len) == 0)
753 return i;
754 }
755
756 return NDF_STOP;
757 }
758
759 // --------------------------------------------------------------------------------------------------------------------
760
761 int nd_log_health_fd(void) {
762 if(nd_log.sources[NDLS_HEALTH].method == NDLM_FILE && nd_log.sources[NDLS_HEALTH].fd != -1)
763 return nd_log.sources[NDLS_HEALTH].fd;
764
765 return STDERR_FILENO;
766 }
767
768 int nd_log_collectors_fd(void) {
769 if(nd_log.sources[NDLS_COLLECTORS].method == NDLM_FILE && nd_log.sources[NDLS_COLLECTORS].fd != -1)
770 return nd_log.sources[NDLS_COLLECTORS].fd;
771
772 return STDERR_FILENO;
773 }
774
775 // --------------------------------------------------------------------------------------------------------------------
776
777 void log_date(char *buffer, size_t len, time_t now) {
778 if(unlikely(!buffer || !len))
779 return;
780
781 time_t t = now;
782 struct tm *tmp, tmbuf;
783
784 tmp = localtime_r(&t, &tmbuf);
785
786 if (unlikely(!tmp)) {
787 buffer[0] = '\0';
788 return;
789 }
790
791 if (unlikely(strftime(buffer, len, "%Y-%m-%d %H:%M:%S", tmp) == 0))
792 buffer[0] = '\0';
793
794 buffer[len - 1] = '\0';
795 }
796
797 // --------------------------------------------------------------------------------------------------------------------
798
799 bool nd_log_replace_existing_fd(struct nd_log_source *e, int new_fd) {
800 if(new_fd == -1 || e->fd == -1 ||
801 (e->fd == STDOUT_FILENO && nd_log.std_output.initialized) ||
802 (e->fd == STDERR_FILENO && nd_log.std_error.initialized))
803 return false;
804
805 if(new_fd != e->fd) {
806 int t = dup2(new_fd, e->fd);
807
808 bool ret = true;
809 if (t == -1) {
810 netdata_log_error("Cannot dup2() new fd %d to old fd %d for '%s'", new_fd, e->fd, e->filename);
811 ret = false;
812 }
813 else
814 close(new_fd);
815
816 if(e->fd == STDOUT_FILENO)
817 nd_log.std_output.initialized = true;
818 else if(e->fd == STDERR_FILENO)
819 nd_log.std_error.initialized = true;
820
821 return ret;
822 }
823
824 return false;
825 }