| 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 | } |