diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 12:08:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 12:08:18 +0000 |
commit | 5da14042f70711ea5cf66e034699730335462f66 (patch) | |
tree | 0f6354ccac934ed87a2d555f45be4c831cf92f4a /src/libnetdata/log | |
parent | Releasing debian version 1.44.3-2. (diff) | |
download | netdata-5da14042f70711ea5cf66e034699730335462f66.tar.xz netdata-5da14042f70711ea5cf66e034699730335462f66.zip |
Merging upstream version 1.45.3+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/libnetdata/log/README.md | 223 | ||||
-rw-r--r-- | src/libnetdata/log/journal.c (renamed from libnetdata/log/journal.c) | 14 | ||||
-rw-r--r-- | src/libnetdata/log/journal.h (renamed from libnetdata/log/journal.h) | 0 | ||||
-rw-r--r-- | src/libnetdata/log/log.c (renamed from libnetdata/log/log.c) | 178 | ||||
-rw-r--r-- | src/libnetdata/log/log.h (renamed from libnetdata/log/log.h) | 11 | ||||
-rw-r--r-- | src/libnetdata/log/systemd-cat-native.c (renamed from libnetdata/log/systemd-cat-native.c) | 10 | ||||
-rw-r--r-- | src/libnetdata/log/systemd-cat-native.h (renamed from libnetdata/log/systemd-cat-native.h) | 0 | ||||
-rw-r--r-- | src/libnetdata/log/systemd-cat-native.md (renamed from libnetdata/log/systemd-cat-native.md) | 0 |
8 files changed, 347 insertions, 89 deletions
diff --git a/src/libnetdata/log/README.md b/src/libnetdata/log/README.md new file mode 100644 index 000000000..ef9ca1ef3 --- /dev/null +++ b/src/libnetdata/log/README.md @@ -0,0 +1,223 @@ +<!-- +title: "Log" +custom_edit_url: https://github.com/netdata/netdata/edit/master/src/libnetdata/log/README.md +sidebar_label: "Log" +learn_status: "Published" +learn_topic_type: "Tasks" +learn_rel_path: "Developers/libnetdata" +--> + +# Netdata Logging + +This document describes how Netdata generates its own logs, not how Netdata manages and queries logs databases. + +## Log sources + +Netdata supports the following log sources: + +1. **daemon**, logs generated by Netdata daemon. +2. **collector**, logs generated by Netdata collectors, including internal and external ones. +3. **access**, API requests received by Netdata +4. **health**, all alert transitions and notifications + +## Log outputs + +For each log source, Netdata supports the following output methods: + +- **off**, to disable this log source +- **journal**, to send the logs to systemd-journal. +- **syslog**, to send the logs to syslog. +- **system**, to send the output to `stderr` or `stdout` depending on the log source. +- **stdout**, to write the logs to Netdata's `stdout`. +- **stderr**, to write the logs to Netdata's `stderr`. +- **filename**, to send the logs to a file. + +For `daemon` and `collector` the default is `journal` when systemd-journal is available. +To decide if systemd-journal is available, Netdata checks: + +1. `stderr` is connected to systemd-journald +2. `/run/systemd/journal/socket` exists +3. `/host/run/systemd/journal/socket` exists (`/host` is configurable in containers) + +If any of the above is detected, Netdata will select `journal` for `daemon` and `collector` sources. + +All other sources default to a file. + +## Log formats + +| Format | Description | +|---------|--------------------------------------------------------------------------------------------------------| +| journal | journald-specific log format. Automatically selected when logging to systemd-journal. | +| logfmt | logs data as a series of key/value pairs. The default when logging to any output other than `journal`. | +| json | logs data in JSON format. | + +## Log levels + +Each time Netdata logs, it assigns a priority to the log. It can be one of this (in order of importance): + +| Level | Description | +|-----------|----------------------------------------------------------------------------------------| +| emergency | a fatal condition, Netdata will most likely exit immediately after. | +| alert | a very important issue that may affect how Netdata operates. | +| critical | a very important issue the user should know which, Netdata thinks it can survive. | +| error | an error condition indicating that Netdata is trying to do something, but it fails. | +| warning | something unexpected has happened that may or may not affect the operation of Netdata. | +| notice | something that does not affect the operation of Netdata, but the user should notice. | +| info | the default log level about information the user should know. | +| debug | these are more verbose logs that can be ignored. | + +## Logs Configuration + +In `netdata.conf`, there are the following settings: + +``` +[logs] + # logs to trigger flood protection = 1000 + # logs flood protection period = 60 + # facility = daemon + # level = info + # daemon = journal + # collector = journal + # access = /var/log/netdata/access.log + # health = /var/log/netdata/health.log +``` + +- `logs to trigger flood protection` and `logs flood protection period` enable logs flood protection for `daemon` and `collector` sources. It can also be configured per log source. +- `facility` is used only when Netdata logs to syslog. +- `level` defines the minimum [log level](#log-levels) of logs that will be logged. This setting is applied only to `daemon` and `collector` sources. It can also be configured per source. + +### Configuring log sources + +Each for the sources (`daemon`, `collector`, `access`, `health`), accepts the following: + +``` +source = {FORMAT},level={LEVEL},protection={LOG}/{PERIOD}@{OUTPUT} +``` + +Where: + +- `{FORMAT}`, is one of the [log formats](#log-formats), +- `{LEVEL}`, is the minimum [log level](#log-levels) to be logged, +- `{LOGS}` is the number of `logs to trigger flood protection` configured per output, +- `{PERIOD}` is the equivalent of `logs flood protection period` configured per output, +- `{OUTPUT}` is one of the `[log outputs](#log-outputs), + +All parameters can be omitted, except `{OUTPUT}`. If `{OUTPUT}` is the only given parameter, `@` can be omitted. + +### Logs rotation + +Netdata comes with `logrotate` configuration to rotate its log files periodically. + +The default is usually found in `/etc/logrotate.d/netdata`. + +Sending a `SIGHUP` to Netdata, will instruct it to re-open all its log files. + +## Log Fields + +<details> +<summary>All fields exposed by Netdata</summary> + +| journal | logfmt | json | Description | +|:--------------------------------------:|:------------------------------:|:------------------------------:|:---------------------------------------------------------------------------------------------------------:| +| `_SOURCE_REALTIME_TIMESTAMP` | `time` | `time` | the timestamp of the event | +| `SYSLOG_IDENTIFIER` | `comm` | `comm` | the program logging the event | +| `ND_LOG_SOURCE` | `source` | `source` | one of the [log sources](#log-sources) | +| `PRIORITY`<br/>numeric | `level`<br/>text | `level`<br/>numeric | one of the [log levels](#log-levels) | +| `ERRNO` | `errno` | `errno` | the numeric value of `errno` | +| `INVOCATION_ID` | - | - | a unique UUID of the Netdata session, reset on every Netdata restart, inherited by systemd when available | +| `CODE_LINE` | - | - | the line number of of the source code logging this event | +| `CODE_FILE` | - | - | the filename of the source code logging this event | +| `CODE_FUNCTION` | - | - | the function name of the source code logging this event | +| `TID` | `tid` | `tid` | the thread id of the thread logging this event | +| `THREAD_TAG` | `thread` | `thread` | the name of the thread logging this event | +| `MESSAGE_ID` | `msg_id` | `msg_id` | see [message IDs](#message-ids) | +| `ND_MODULE` | `module` | `module` | the Netdata module logging this event | +| `ND_NIDL_NODE` | `node` | `node` | the hostname of the node the event is related to | +| `ND_NIDL_INSTANCE` | `instance` | `instance` | the instance of the node the event is related to | +| `ND_NIDL_CONTEXT` | `context` | `context` | the context the event is related to (this is usually the chart name, as shown on netdata dashboards | +| `ND_NIDL_DIMENSION` | `dimension` | `dimension` | the dimension the event is related to | +| `ND_SRC_TRANSPORT` | `src_transport` | `src_transport` | when the event happened during a request, this is the request transport | +| `ND_SRC_IP` | `src_ip` | `src_ip` | when the event happened during an inbound request, this is the IP the request came from | +| `ND_SRC_PORT` | `src_port` | `src_port` | when the event happened during an inbound request, this is the port the request came from | +| `ND_SRC_FORWARDED_HOST` | `src_forwarded_host` | `src_forwarded_host` | the contents of the HTTP header `X-Forwarded-Host` | +| `ND_SRC_FORWARDED_FOR` | `src_forwarded_for` | `src_forwarded_for` | the contents of the HTTP header `X-Forwarded-For` | +| `ND_SRC_CAPABILITIES` | `src_capabilities` | `src_capabilities` | when the request came from a child, this is the communication capabilities of the child | +| `ND_DST_TRANSPORT` | `dst_transport` | `dst_transport` | when the event happened during an outbound request, this is the outbound request transport | +| `ND_DST_IP` | `dst_ip` | `dst_ip` | when the event happened during an outbound request, this is the IP the request destination | +| `ND_DST_PORT` | `dst_port` | `dst_port` | when the event happened during an outbound request, this is the port the request destination | +| `ND_DST_CAPABILITIES` | `dst_capabilities` | `dst_capabilities` | when the request goes to a parent, this is the communication capabilities of the parent | +| `ND_REQUEST_METHOD` | `req_method` | `req_method` | when the event happened during an inbound request, this is the method the request was received | +| `ND_RESPONSE_CODE` | `code` | `code` | when responding to a request, this this the response code | +| `ND_CONNECTION_ID` | `conn` | `conn` | when there is a connection id for an inbound connection, this is the connection id | +| `ND_TRANSACTION_ID` | `transaction` | `transaction` | the transaction id (UUID) of all API requests | +| `ND_RESPONSE_SENT_BYTES` | `sent_bytes` | `sent_bytes` | the bytes we sent to API responses | +| `ND_RESPONSE_SIZE_BYTES` | `size_bytes` | `size_bytes` | the uncompressed bytes of the API responses | +| `ND_RESPONSE_PREP_TIME_USEC` | `prep_ut` | `prep_ut` | the time needed to prepare a response | +| `ND_RESPONSE_SENT_TIME_USEC` | `sent_ut` | `sent_ut` | the time needed to send a response | +| `ND_RESPONSE_TOTAL_TIME_USEC` | `total_ut` | `total_ut` | the total time needed to complete a response | +| `ND_ALERT_ID` | `alert_id` | `alert_id` | the alert id this event is related to | +| `ND_ALERT_EVENT_ID` | `alert_event_id` | `alert_event_id` | a sequential number of the alert transition (per host) | +| `ND_ALERT_UNIQUE_ID` | `alert_unique_id` | `alert_unique_id` | a sequential number of the alert transition (per alert) | +| `ND_ALERT_TRANSITION_ID` | `alert_transition_id` | `alert_transition_id` | the unique UUID of this alert transition | +| `ND_ALERT_CONFIG` | `alert_config` | `alert_config` | the alert configuration hash (UUID) | +| `ND_ALERT_NAME` | `alert` | `alert` | the alert name | +| `ND_ALERT_CLASS` | `alert_class` | `alert_class` | the alert classification | +| `ND_ALERT_COMPONENT` | `alert_component` | `alert_component` | the alert component | +| `ND_ALERT_TYPE` | `alert_type` | `alert_type` | the alert type | +| `ND_ALERT_EXEC` | `alert_exec` | `alert_exec` | the alert notification program | +| `ND_ALERT_RECIPIENT` | `alert_recipient` | `alert_recipient` | the alert recipient(s) | +| `ND_ALERT_VALUE` | `alert_value` | `alert_value` | the current alert value | +| `ND_ALERT_VALUE_OLD` | `alert_value_old` | `alert_value_old` | the previous alert value | +| `ND_ALERT_STATUS` | `alert_status` | `alert_status` | the current alert status | +| `ND_ALERT_STATUS_OLD` | `alert_value_old` | `alert_value_old` | the previous alert value | +| `ND_ALERT_UNITS` | `alert_units` | `alert_units` | the units of the alert | +| `ND_ALERT_SUMMARY` | `alert_summary` | `alert_summary` | the summary text of the alert | +| `ND_ALERT_INFO` | `alert_info` | `alert_info` | the info text of the alert | +| `ND_ALERT_DURATION` | `alert_duration` | `alert_duration` | the duration the alert was in its previous state | +| `ND_ALERT_NOTIFICATION_TIMESTAMP_USEC` | `alert_notification_timestamp` | `alert_notification_timestamp` | the timestamp the notification delivery is scheduled | +| `ND_REQUEST` | `request` | `request` | the full request during which the event happened | +| `MESSAGE` | `msg` | `msg` | the event message | + +</details> + +### Message IDs + +Netdata assigns specific message IDs to certain events: + +- `ed4cdb8f1beb4ad3b57cb3cae2d162fa` when a Netdata child connects to this Netdata +- `6e2e3839067648968b646045dbf28d66` when this Netdata connects to a Netdata parent +- `9ce0cb58ab8b44df82c4bf1ad9ee22de` when alerts change state +- `6db0018e83e34320ae2a659d78019fb7` when notifications are sent + +You can view these events using the Netdata systemd-journal.plugin at the `MESSAGE_ID` filter, +or using `journalctl` like this: + +```bash +# query children connection +journalctl MESSAGE_ID=ed4cdb8f1beb4ad3b57cb3cae2d162fa + +# query parent connection +journalctl MESSAGE_ID=6e2e3839067648968b646045dbf28d66 + +# query alert transitions +journalctl MESSAGE_ID=9ce0cb58ab8b44df82c4bf1ad9ee22de + +# query alert notifications +journalctl MESSAGE_ID=6db0018e83e34320ae2a659d78019fb7 +``` + +## Using journalctl to query Netdata logs + +The Netdata service's processes execute within the `netdata` journal namespace. To view the Netdata logs, you should +specify the `--namespace=netdata` option. + +```bash +# Netdata logs since the last time the service was started +journalctl _SYSTEMD_INVOCATION_ID="$(systemctl show --value --property=InvocationID netdata)" --namespace=netdata + +# All netdata logs, the oldest entries are displayed first +journalctl -u netdata --namespace=netdata + +# All netdata logs, the newest entries are displayed first +journalctl -u netdata --namespace=netdata -r +``` diff --git a/libnetdata/log/journal.c b/src/libnetdata/log/journal.c index 21978cf5f..0f1248de7 100644 --- a/libnetdata/log/journal.c +++ b/src/libnetdata/log/journal.c @@ -3,15 +3,12 @@ #include "journal.h" bool is_path_unix_socket(const char *path) { + // Check if the path is valid if(!path || !*path) return false; struct stat statbuf; - // Check if the path is valid - if (!path || !*path) - return false; - // Use stat to check if the file exists and is a socket if (stat(path, &statbuf) == -1) // The file does not exist or cannot be accessed @@ -51,9 +48,11 @@ int journal_direct_fd(const char *path) { if(!is_path_unix_socket(path)) return -1; - int fd = socket(AF_UNIX, SOCK_DGRAM, 0); + int fd = socket(AF_UNIX, SOCK_DGRAM| DEFAULT_SOCKET_FLAGS, 0); if (fd < 0) return -1; + sock_setcloexec(fd); + struct sockaddr_un addr; memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_UNIX; @@ -97,6 +96,11 @@ static inline bool journal_send_with_memfd(int fd, const char *msg, size_t msg_l msghdr.msg_controllen = sizeof(cmsgbuf); cmsghdr = CMSG_FIRSTHDR(&msghdr); + if(!cmsghdr) { + close(memfd); + return false; + } + cmsghdr->cmsg_level = SOL_SOCKET; cmsghdr->cmsg_type = SCM_RIGHTS; cmsghdr->cmsg_len = CMSG_LEN(sizeof(int)); diff --git a/libnetdata/log/journal.h b/src/libnetdata/log/journal.h index df8ece18b..df8ece18b 100644 --- a/libnetdata/log/journal.h +++ b/src/libnetdata/log/journal.h diff --git a/libnetdata/log/log.c b/src/libnetdata/log/log.c index c805716ce..bfba93ddb 100644 --- a/libnetdata/log/log.c +++ b/src/libnetdata/log/log.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later +// do not REMOVE this, it is used by systemd-journal includes to prevent saving the file, function, line of the +// source code that makes the calls, allowing our loggers to log the lines of source code that actually log #define SD_JOURNAL_SUPPRESS_LOCATION #include "../libnetdata.h" -#include <daemon/main.h> #ifdef __FreeBSD__ #include <sys/endian.h> @@ -13,7 +14,7 @@ #include <machine/endian.h> #endif -#ifdef HAVE_BACKTRACE +#if !defined(ENABLE_SENTRY) && defined(HAVE_BACKTRACE) #include <execinfo.h> #endif @@ -1117,9 +1118,33 @@ static __thread struct log_field thread_log_fields[_NDF_MAX] = { .journal = "ND_SRC_TRANSPORT", .logfmt = "src_transport", }, + [NDF_ACCOUNT_ID] = { + .journal = "ND_ACCOUNT_ID", + .logfmt = "account", + }, + [NDF_USER_NAME] = { + .journal = "ND_USER_NAME", + .logfmt = "user", + }, + [NDF_USER_ROLE] = { + .journal = "ND_USER_ROLE", + .logfmt = "role", + }, + [NDF_USER_ACCESS] = { + .journal = "ND_USER_PERMISSIONS", + .logfmt = "permissions", + }, [NDF_SRC_IP] = { - .journal = "ND_SRC_IP", - .logfmt = "src_ip", + .journal = "ND_SRC_IP", + .logfmt = "src_ip", + }, + [NDF_SRC_FORWARDED_HOST] = { + .journal = "ND_SRC_FORWARDED_HOST", + .logfmt = "src_forwarded_host", + }, + [NDF_SRC_FORWARDED_FOR] = { + .journal = "ND_SRC_FORWARDED_FOR", + .logfmt = "src_forwarded_for", }, [NDF_SRC_PORT] = { .journal = "ND_SRC_PORT", @@ -1353,11 +1378,12 @@ static void nd_logger_json(BUFFER *wb, struct log_field *fields, size_t fields_m case NDFT_DBL: buffer_json_member_add_double(wb, key, fields[i].entry.dbl); break; - case NDFT_UUID:{ - char u[UUID_COMPACT_STR_LEN]; - uuid_unparse_lower_compact(*fields[i].entry.uuid, u); - buffer_json_member_add_string(wb, key, u); - } + case NDFT_UUID: + if(!uuid_is_null(*fields[i].entry.uuid)) { + char u[UUID_COMPACT_STR_LEN]; + uuid_unparse_lower_compact(*fields[i].entry.uuid, u); + buffer_json_member_add_string(wb, key, u); + } break; case NDFT_CALLBACK: { if(!tmp) @@ -1423,10 +1449,7 @@ static int64_t log_field_to_int64(struct log_field *lf) { break; case NDFT_CALLBACK: - if(!tmp) - tmp = buffer_create(0, NULL); - else - buffer_flush(tmp); + tmp = buffer_create(0, NULL); if(lf->entry.cb.formatter(tmp, lf->entry.cb.formatter_data)) s = buffer_tostring(tmp); @@ -1435,13 +1458,13 @@ static int64_t log_field_to_int64(struct log_field *lf) { break; case NDFT_U64: - return lf->entry.u64; + return (int64_t)lf->entry.u64; case NDFT_I64: - return lf->entry.i64; + return (int64_t)lf->entry.i64; case NDFT_DBL: - return lf->entry.dbl; + return (int64_t)lf->entry.dbl; } if(s && *s) @@ -1487,10 +1510,7 @@ static uint64_t log_field_to_uint64(struct log_field *lf) { break; case NDFT_CALLBACK: - if(!tmp) - tmp = buffer_create(0, NULL); - else - buffer_flush(tmp); + tmp = buffer_create(0, NULL); if(lf->entry.cb.formatter(tmp, lf->entry.cb.formatter_data)) s = buffer_tostring(tmp); @@ -1505,7 +1525,7 @@ static uint64_t log_field_to_uint64(struct log_field *lf) { return lf->entry.i64; case NDFT_DBL: - return lf->entry.dbl; + return (uint64_t) lf->entry.dbl; } if(s && *s) @@ -1538,7 +1558,7 @@ static void errno_annotator(BUFFER *wb, const char *key, struct log_field *lf) { return; char buf[1024]; - const char *s = errno2str(errnum, buf, sizeof(buf)); + const char *s = errno2str((int)errnum, buf, sizeof(buf)); if(buffer_strlen(wb)) buffer_fast_strcat(wb, " ", 1); @@ -1562,7 +1582,8 @@ static void priority_annotator(BUFFER *wb, const char *key, struct log_field *lf buffer_strcat(wb, nd_log_id2priority(pri)); } -static bool needs_quotes_for_logfmt(const char *s) { +static bool needs_quotes_for_logfmt(const char *s) +{ static bool safe_for_logfmt[256] = { [' '] = true, ['!'] = true, ['"'] = false, ['#'] = true, ['$'] = true, ['%'] = true, ['&'] = true, ['\''] = true, ['('] = true, [')'] = true, ['*'] = true, ['+'] = true, [','] = true, ['-'] = true, @@ -1593,7 +1614,8 @@ static bool needs_quotes_for_logfmt(const char *s) { return false; } -static void string_to_logfmt(BUFFER *wb, const char *s) { +static void string_to_logfmt(BUFFER *wb, const char *s) +{ bool spaces = needs_quotes_for_logfmt(s); if(spaces) @@ -1605,7 +1627,8 @@ static void string_to_logfmt(BUFFER *wb, const char *s) { buffer_fast_strcat(wb, "\"", 1); } -static void nd_logger_logfmt(BUFFER *wb, struct log_field *fields, size_t fields_max) { +static void nd_logger_logfmt(BUFFER *wb, struct log_field *fields, size_t fields_max) +{ // --- FIELD_PARSER_VERSIONS --- // @@ -1670,13 +1693,14 @@ static void nd_logger_logfmt(BUFFER *wb, struct log_field *fields, size_t fields buffer_fast_strcat(wb, "=", 1); buffer_print_netdata_double(wb, fields[i].entry.dbl); break; - case NDFT_UUID: { - char u[UUID_COMPACT_STR_LEN]; - uuid_unparse_lower_compact(*fields[i].entry.uuid, u); - buffer_strcat(wb, key); - buffer_fast_strcat(wb, "=", 1); - buffer_fast_strcat(wb, u, sizeof(u) - 1); - } + case NDFT_UUID: + if(!uuid_is_null(*fields[i].entry.uuid)) { + char u[UUID_COMPACT_STR_LEN]; + uuid_unparse_lower_compact(*fields[i].entry.uuid, u); + buffer_strcat(wb, key); + buffer_fast_strcat(wb, "=", 1); + buffer_fast_strcat(wb, u, sizeof(u) - 1); + } break; case NDFT_CALLBACK: { if(!tmp) @@ -1745,32 +1769,34 @@ static bool nd_logger_journal_libsystemd(struct log_field *fields, size_t fields const char *key = fields[i].journal; char *value = NULL; + int rc = 0; switch (fields[i].entry.type) { case NDFT_TXT: if(*fields[i].entry.txt) - asprintf(&value, "%s=%s", key, fields[i].entry.txt); + rc = asprintf(&value, "%s=%s", key, fields[i].entry.txt); break; case NDFT_STR: - asprintf(&value, "%s=%s", key, string2str(fields[i].entry.str)); + rc = asprintf(&value, "%s=%s", key, string2str(fields[i].entry.str)); break; case NDFT_BFR: if(buffer_strlen(fields[i].entry.bfr)) - asprintf(&value, "%s=%s", key, buffer_tostring(fields[i].entry.bfr)); + rc = asprintf(&value, "%s=%s", key, buffer_tostring(fields[i].entry.bfr)); break; case NDFT_U64: - asprintf(&value, "%s=%" PRIu64, key, fields[i].entry.u64); + rc = asprintf(&value, "%s=%" PRIu64, key, fields[i].entry.u64); break; case NDFT_I64: - asprintf(&value, "%s=%" PRId64, key, fields[i].entry.i64); + rc = asprintf(&value, "%s=%" PRId64, key, fields[i].entry.i64); break; case NDFT_DBL: - asprintf(&value, "%s=%f", key, fields[i].entry.dbl); + rc = asprintf(&value, "%s=%f", key, fields[i].entry.dbl); break; - case NDFT_UUID: { - char u[UUID_COMPACT_STR_LEN]; - uuid_unparse_lower_compact(*fields[i].entry.uuid, u); - asprintf(&value, "%s=%s", key, u); - } + case NDFT_UUID: + if(!uuid_is_null(*fields[i].entry.uuid)) { + char u[UUID_COMPACT_STR_LEN]; + uuid_unparse_lower_compact(*fields[i].entry.uuid, u); + rc = asprintf(&value, "%s=%s", key, u); + } break; case NDFT_CALLBACK: { if(!tmp) @@ -1778,15 +1804,15 @@ static bool nd_logger_journal_libsystemd(struct log_field *fields, size_t fields else buffer_flush(tmp); if(fields[i].entry.cb.formatter(tmp, fields[i].entry.cb.formatter_data)) - asprintf(&value, "%s=%s", key, buffer_tostring(tmp)); + rc = asprintf(&value, "%s=%s", key, buffer_tostring(tmp)); } break; default: - asprintf(&value, "%s=%s", key, "UNHANDLED"); + rc = asprintf(&value, "%s=%s", key, "UNHANDLED"); break; } - if (value) { + if (rc != -1 && value) { iov[iov_count].iov_base = value; iov[iov_count].iov_len = strlen(value); iov_count++; @@ -1864,14 +1890,15 @@ static bool nd_logger_journal_direct(struct log_field *fields, size_t fields_max buffer_print_netdata_double(wb, fields[i].entry.dbl); buffer_putc(wb, '\n'); break; - case NDFT_UUID:{ - char u[UUID_COMPACT_STR_LEN]; - uuid_unparse_lower_compact(*fields[i].entry.uuid, u); - buffer_strcat(wb, key); - buffer_putc(wb, '='); - buffer_fast_strcat(wb, u, sizeof(u) - 1); - buffer_putc(wb, '\n'); - } + case NDFT_UUID: + if(!uuid_is_null(*fields[i].entry.uuid)) { + char u[UUID_COMPACT_STR_LEN]; + uuid_unparse_lower_compact(*fields[i].entry.uuid, u); + buffer_strcat(wb, key); + buffer_putc(wb, '='); + buffer_fast_strcat(wb, u, sizeof(u) - 1); + buffer_putc(wb, '\n'); + } break; case NDFT_CALLBACK: { if(!tmp) @@ -1913,7 +1940,7 @@ static bool nd_logger_journal_direct(struct log_field *fields, size_t fields_max // ---------------------------------------------------------------------------- // syslog logger - uses logfmt -static bool nd_logger_syslog(int priority, ND_LOG_FORMAT format, struct log_field *fields, size_t fields_max) { +static bool nd_logger_syslog(int priority, ND_LOG_FORMAT format __maybe_unused, struct log_field *fields, size_t fields_max) { CLEAN_BUFFER *wb = buffer_create(1024, NULL); nd_logger_logfmt(wb, fields, fields_max); @@ -2069,7 +2096,7 @@ static void nd_logger_merge_log_stack_to_thread_fields(void) { if((type == NDFT_TXT && (!e->txt || !*e->txt)) || (type == NDFT_BFR && (!e->bfr || !buffer_strlen(e->bfr))) || (type == NDFT_STR && !e->str) || - (type == NDFT_UUID && !e->uuid) || + (type == NDFT_UUID && (!e->uuid || uuid_is_null(*e->uuid))) || (type == NDFT_CALLBACK && !e->cb.formatter) || type == NDFT_UNSET) continue; @@ -2110,7 +2137,7 @@ static void nd_logger(const char *file, const char *function, const unsigned lon else if(thread_log_fields[NDF_LOG_SOURCE].entry.type == NDFT_U64) src = thread_log_fields[NDF_LOG_SOURCE].entry.u64; - if(src != source && src >= 0 && src < _NDLS_MAX) { + if(src != source && src < _NDLS_MAX) { source = src; output = nd_logger_select_output(source, &fp, &spinlock); if(output != NDLM_FILE && output != NDLM_JOURNAL && output != NDLM_SYSLOG) @@ -2137,13 +2164,11 @@ static void nd_logger(const char *file, const char *function, const unsigned lon char os_threadname[NETDATA_THREAD_NAME_MAX + 1]; if(likely(!thread_log_fields[NDF_THREAD_TAG].entry.set)) { const char *thread_tag = netdata_thread_tag(); - if(!netdata_thread_tag_exists()) { - if (!netdata_thread_tag_exists()) { - os_thread_get_current_name_np(os_threadname); - if ('\0' != os_threadname[0]) - /* If it is not an empty string replace "MAIN" thread_tag */ - thread_tag = os_threadname; - } + if (!netdata_thread_tag_exists()) { + os_thread_get_current_name_np(os_threadname); + if ('\0' != os_threadname[0]) + /* If it is not an empty string replace "MAIN" thread_tag */ + thread_tag = os_threadname; } thread_log_fields[NDF_THREAD_TAG].entry = ND_LOG_FIELD_TXT(NDF_THREAD_TAG, thread_tag); @@ -2224,7 +2249,8 @@ static ND_LOG_SOURCES nd_log_validate_source(ND_LOG_SOURCES source) { // ---------------------------------------------------------------------------- // public API for loggers -void netdata_logger(ND_LOG_SOURCES source, ND_LOG_FIELD_PRIORITY priority, const char *file, const char *function, unsigned long line, const char *fmt, ... ) { +void netdata_logger(ND_LOG_SOURCES source, ND_LOG_FIELD_PRIORITY priority, const char *file, const char *function, unsigned long line, const char *fmt, ... ) +{ int saved_errno = errno; source = nd_log_validate_source(source); @@ -2285,17 +2311,14 @@ void netdata_logger_fatal( const char *file, const char *function, const unsigne char action_data[70+1]; snprintfz(action_data, 70, "%04lu@%-10.10s:%-15.15s/%d", line, file, function, saved_errno); - char action_result[60+1]; char os_threadname[NETDATA_THREAD_NAME_MAX + 1]; const char *thread_tag = netdata_thread_tag(); - if(!netdata_thread_tag_exists()) { - if (!netdata_thread_tag_exists()) { - os_thread_get_current_name_np(os_threadname); - if ('\0' != os_threadname[0]) - /* If it is not an empty string replace "MAIN" thread_tag */ - thread_tag = os_threadname; - } + if (!netdata_thread_tag_exists()) { + os_thread_get_current_name_np(os_threadname); + if ('\0' != os_threadname[0]) + /* If it is not an empty string replace "MAIN" thread_tag */ + thread_tag = os_threadname; } if(!thread_tag) thread_tag = "UNKNOWN"; @@ -2308,10 +2331,10 @@ void netdata_logger_fatal( const char *file, const char *function, const unsigne if(strncmp(thread_tag, THREAD_TAG_STREAM_SENDER, strlen(THREAD_TAG_STREAM_SENDER)) == 0) tag_to_send = THREAD_TAG_STREAM_SENDER; + char action_result[60+1]; snprintfz(action_result, 60, "%s:%s", program_name, tag_to_send); - send_statistics("FATAL", action_result, action_data); -#ifdef HAVE_BACKTRACE +#if !defined(ENABLE_SENTRY) && defined(HAVE_BACKTRACE) int fd = nd_log.sources[NDLS_DAEMON].fd; if(fd == -1) fd = STDERR_FILENO; @@ -2328,7 +2351,7 @@ void netdata_logger_fatal( const char *file, const char *function, const unsigne abort(); #endif - netdata_cleanup_and_exit(1); + netdata_cleanup_and_exit(1, "FATAL", action_result, action_data); } // ---------------------------------------------------------------------------- @@ -2407,7 +2430,8 @@ static bool nd_log_limit_reached(struct nd_log_source *source) { source->limits.logs_per_period, source->limits.throttle_period, program_name, - (int64_t)((source->limits.started_monotonic_ut + (source->limits.throttle_period * USEC_PER_SEC) - now_ut)) / USEC_PER_SEC); + (int64_t)(((source->limits.started_monotonic_ut + (source->limits.throttle_period * USEC_PER_SEC) - now_ut)) / USEC_PER_SEC) + ); if(source->pending_msg) freez((void *)source->pending_msg); diff --git a/libnetdata/log/log.h b/src/libnetdata/log/log.h index ad634693c..51d6c8bff 100644 --- a/libnetdata/log/log.h +++ b/src/libnetdata/log/log.h @@ -63,9 +63,17 @@ typedef enum __attribute__((__packed__)) { // web server, aclk and stream receiver NDF_SRC_TRANSPORT, // the transport we received the request, one of: http, https, pluginsd + // Netdata Cloud Related + NDF_ACCOUNT_ID, + NDF_USER_NAME, + NDF_USER_ROLE, + NDF_USER_ACCESS, + // web server and stream receiver NDF_SRC_IP, // the streaming / web server source IP NDF_SRC_PORT, // the streaming / web server source Port + NDF_SRC_FORWARDED_HOST, + NDF_SRC_FORWARDED_FOR, NDF_SRC_CAPABILITIES, // the stream receiver capabilities // stream sender (established links) @@ -286,12 +294,11 @@ typedef struct error_with_limit { #define nd_log_limit_static_global_var(var, log_every_secs, sleep_usecs) static ERROR_LIMIT var = { .last_logged = 0, .count = 0, .log_every = (log_every_secs), .sleep_ut = (sleep_usecs) } #define nd_log_limit_static_thread_var(var, log_every_secs, sleep_usecs) static __thread ERROR_LIMIT var = { .last_logged = 0, .count = 0, .log_every = (log_every_secs), .sleep_ut = (sleep_usecs) } -void netdata_logger_with_limit(ERROR_LIMIT *erl, ND_LOG_SOURCES source, ND_LOG_FIELD_PRIORITY priority, const char *file, const char *function, unsigned long line, const char *fmt, ... ) PRINTFLIKE(7, 8);; +void netdata_logger_with_limit(ERROR_LIMIT *erl, ND_LOG_SOURCES source, ND_LOG_FIELD_PRIORITY priority, const char *file, const char *function, unsigned long line, const char *fmt, ... ) PRINTFLIKE(7, 8); #define nd_log_limit(erl, NDLS, NDLP, args...) netdata_logger_with_limit(erl, NDLS, NDLP, __FILE__, __FUNCTION__, __LINE__, ##args) // ---------------------------------------------------------------------------- -void send_statistics(const char *action, const char *action_result, const char *action_data); void netdata_logger_fatal( const char *file, const char *function, unsigned long line, const char *fmt, ... ) NORETURN PRINTFLIKE(4, 5); # ifdef __cplusplus diff --git a/libnetdata/log/systemd-cat-native.c b/src/libnetdata/log/systemd-cat-native.c index de6211cc0..0c89399d3 100644 --- a/libnetdata/log/systemd-cat-native.c +++ b/src/libnetdata/log/systemd-cat-native.c @@ -11,7 +11,7 @@ #include <machine/endian.h> #endif -static void log_message_to_stderr(BUFFER *msg) { +static inline void log_message_to_stderr(BUFFER *msg) { CLEAN_BUFFER *tmp = buffer_create(0, NULL); for(size_t i = 0; i < msg->len ;i++) { @@ -436,7 +436,7 @@ cleanup: static int help(void) { fprintf(stderr, "\n" - "Netdata systemd-cat-native " PACKAGE_VERSION "\n" + "Netdata systemd-cat-native " VERSION "\n" "\n" "This program reads from its standard input, lines in the format:\n" "\n" @@ -594,7 +594,7 @@ static int log_input_as_netdata(const char *newline, int timeout_ms) { // an empty line - we are done for this message nd_log(NDLS_HEALTH, priority, - "added %d fields", // if the user supplied a MESSAGE, this will be ignored + "added %zu fields", // if the user supplied a MESSAGE, this will be ignored fields_added); lgs_reset(lgs); @@ -627,7 +627,7 @@ static int log_input_as_netdata(const char *newline, int timeout_ms) { nd_log(NDLS_COLLECTORS, NDLP_ERR, "Field '%.*s' is not a Netdata field. Ignoring it.", - field_len, field); + (int)field_len, field); lgs[NDF_MESSAGE] = backup; } @@ -648,7 +648,7 @@ static int log_input_as_netdata(const char *newline, int timeout_ms) { } if(fields_added) { - nd_log(NDLS_HEALTH, priority, "added %d fields", fields_added); + nd_log(NDLS_HEALTH, priority, "added %zu fields", fields_added); messages_logged++; } diff --git a/libnetdata/log/systemd-cat-native.h b/src/libnetdata/log/systemd-cat-native.h index 34e7a3615..34e7a3615 100644 --- a/libnetdata/log/systemd-cat-native.h +++ b/src/libnetdata/log/systemd-cat-native.h diff --git a/libnetdata/log/systemd-cat-native.md b/src/libnetdata/log/systemd-cat-native.md index b0b15f403..b0b15f403 100644 --- a/libnetdata/log/systemd-cat-native.md +++ b/src/libnetdata/log/systemd-cat-native.md |