summaryrefslogtreecommitdiffstats
path: root/src/libnetdata/log
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 12:08:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 12:08:18 +0000
commit5da14042f70711ea5cf66e034699730335462f66 (patch)
tree0f6354ccac934ed87a2d555f45be4c831cf92f4a /src/libnetdata/log
parentReleasing debian version 1.44.3-2. (diff)
downloadnetdata-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.md223
-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