summaryrefslogtreecommitdiffstats
path: root/src/libnetdata/log/nd_log-init.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnetdata/log/nd_log-init.c')
-rw-r--r--src/libnetdata/log/nd_log-init.c313
1 files changed, 313 insertions, 0 deletions
diff --git a/src/libnetdata/log/nd_log-init.c b/src/libnetdata/log/nd_log-init.c
new file mode 100644
index 000000000..7f846b136
--- /dev/null
+++ b/src/libnetdata/log/nd_log-init.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "nd_log-internals.h"
+
+// --------------------------------------------------------------------------------------------------------------------
+
+__attribute__((constructor)) void initialize_invocation_id(void) {
+ // check for a NETDATA_INVOCATION_ID
+ if(uuid_parse_flexi(getenv("NETDATA_INVOCATION_ID"), nd_log.invocation_id) != 0) {
+ // not found, check for systemd set INVOCATION_ID
+ if(uuid_parse_flexi(getenv("INVOCATION_ID"), nd_log.invocation_id) != 0) {
+ // not found, generate a new one
+ uuid_generate_random(nd_log.invocation_id);
+ }
+ }
+
+ char uuid[UUID_COMPACT_STR_LEN];
+ uuid_unparse_lower_compact(nd_log.invocation_id, uuid);
+ nd_setenv("NETDATA_INVOCATION_ID", uuid, 1);
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+
+void nd_log_initialize_for_external_plugins(const char *name) {
+ // if we don't run under Netdata, log to stderr,
+ // otherwise, use the logging method Netdata wants us to use.
+#if defined(OS_WINDOWS)
+#if defined(HAVE_ETW)
+ nd_setenv("NETDATA_LOG_METHOD", ETW_NAME, 0);
+ nd_setenv("NETDATA_LOG_FORMAT", ETW_NAME, 0);
+#elif defined(HAVE_WEL)
+ nd_setenv("NETDATA_LOG_METHOD", WEL_NAME, 0);
+ nd_setenv("NETDATA_LOG_FORMAT", WEL_NAME, 0);
+#else
+ nd_setenv("NETDATA_LOG_METHOD", "stderr", 0);
+ nd_setenv("NETDATA_LOG_FORMAT", "logfmt", 0);
+#endif
+#else
+ nd_setenv("NETDATA_LOG_METHOD", "stderr", 0);
+ nd_setenv("NETDATA_LOG_FORMAT", "logfmt", 0);
+#endif
+
+ nd_log.overwrite_process_source = NDLS_COLLECTORS;
+ program_name = name;
+
+ for(size_t i = 0; i < _NDLS_MAX ;i++) {
+ nd_log.sources[i].method = NDLM_DEFAULT;
+ nd_log.sources[i].fd = -1;
+ nd_log.sources[i].fp = NULL;
+ }
+
+ nd_log_set_priority_level(getenv("NETDATA_LOG_LEVEL"));
+ nd_log_set_facility(getenv("NETDATA_SYSLOG_FACILITY"));
+
+ time_t period = 1200;
+ size_t logs = 200;
+ const char *s = getenv("NETDATA_ERRORS_THROTTLE_PERIOD");
+ if(s && *s >= '0' && *s <= '9') {
+ period = str2l(s);
+ if(period < 0) period = 0;
+ }
+
+ s = getenv("NETDATA_ERRORS_PER_PERIOD");
+ if(s && *s >= '0' && *s <= '9')
+ logs = str2u(s);
+
+ nd_log_set_flood_protection(logs, period);
+
+ if(!netdata_configured_host_prefix) {
+ s = getenv("NETDATA_HOST_PREFIX");
+ if(s && *s)
+ netdata_configured_host_prefix = (char *)s;
+ }
+
+ ND_LOG_METHOD method = nd_log_method2id(getenv("NETDATA_LOG_METHOD"));
+ ND_LOG_FORMAT format = nd_log_format2id(getenv("NETDATA_LOG_FORMAT"));
+
+ if(!IS_VALID_LOG_METHOD_FOR_EXTERNAL_PLUGINS(method)) {
+ if(is_stderr_connected_to_journal()) {
+ nd_log(NDLS_COLLECTORS, NDLP_WARNING, "NETDATA_LOG_METHOD is not set. Using journal.");
+ method = NDLM_JOURNAL;
+ }
+ else {
+ nd_log(NDLS_COLLECTORS, NDLP_WARNING, "NETDATA_LOG_METHOD is not set. Using stderr.");
+ method = NDLM_STDERR;
+ }
+ }
+
+ switch(method) {
+ case NDLM_JOURNAL:
+ if(!nd_log_journal_direct_init(getenv("NETDATA_SYSTEMD_JOURNAL_PATH")) ||
+ !nd_log_journal_direct_init(NULL) || !nd_log_journal_systemd_init()) {
+ nd_log(NDLS_COLLECTORS, NDLP_WARNING, "Failed to initialize journal. Using stderr.");
+ method = NDLM_STDERR;
+ }
+ break;
+
+#if defined(OS_WINDOWS)
+#if defined(HAVE_ETW)
+ case NDLM_ETW:
+ if(!nd_log_init_etw()) {
+ nd_log(NDLS_COLLECTORS, NDLP_WARNING, "Failed to initialize Events Tracing for Windows (ETW). Using stderr.");
+ method = NDLM_STDERR;
+ }
+ break;
+#endif
+#if defined(HAVE_WEL)
+ case NDLM_WEL:
+ if(!nd_log_init_wel()) {
+ nd_log(NDLS_COLLECTORS, NDLP_WARNING, "Failed to initialize Windows Event Log (WEL). Using stderr.");
+ method = NDLM_STDERR;
+ }
+ break;
+#endif
+#endif
+
+ case NDLM_SYSLOG:
+ nd_log_init_syslog();
+ break;
+
+ default:
+ method = NDLM_STDERR;
+ break;
+ }
+
+ nd_log.sources[NDLS_COLLECTORS].method = method;
+ nd_log.sources[NDLS_COLLECTORS].format = format;
+ nd_log.sources[NDLS_COLLECTORS].fd = -1;
+ nd_log.sources[NDLS_COLLECTORS].fp = NULL;
+
+ // nd_log(NDLS_COLLECTORS, NDLP_NOTICE, "FINAL_LOG_METHOD: %s", nd_log_id2method(method));
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+
+void nd_log_open(struct nd_log_source *e, ND_LOG_SOURCES source) {
+ if(e->method == NDLM_DEFAULT)
+ nd_log_set_user_settings(source, e->filename);
+
+ if((e->method == NDLM_FILE && !e->filename) ||
+ (e->method == NDLM_DEVNULL && e->fd == -1))
+ e->method = NDLM_DISABLED;
+
+ if(e->fp)
+ fflush(e->fp);
+
+ switch(e->method) {
+ case NDLM_SYSLOG:
+ nd_log_init_syslog();
+ break;
+
+ case NDLM_JOURNAL:
+ nd_log_journal_direct_init(NULL);
+ nd_log_journal_systemd_init();
+ break;
+
+#if defined(OS_WINDOWS)
+#if defined(HAVE_ETW)
+ case NDLM_ETW:
+ nd_log_init_etw();
+ break;
+#endif
+#if defined(HAVE_WEL)
+ case NDLM_WEL:
+ nd_log_init_wel();
+ break;
+#endif
+#endif
+
+ case NDLM_STDOUT:
+ e->fp = stdout;
+ e->fd = STDOUT_FILENO;
+ break;
+
+ case NDLM_DISABLED:
+ break;
+
+ case NDLM_DEFAULT:
+ case NDLM_STDERR:
+ e->method = NDLM_STDERR;
+ e->fp = stderr;
+ e->fd = STDERR_FILENO;
+ break;
+
+ case NDLM_DEVNULL:
+ case NDLM_FILE: {
+ int fd = open(e->filename, O_WRONLY | O_APPEND | O_CREAT, 0664);
+ if(fd == -1) {
+ if(e->fd != STDOUT_FILENO && e->fd != STDERR_FILENO) {
+ e->fd = STDERR_FILENO;
+ e->method = NDLM_STDERR;
+ netdata_log_error("Cannot open log file '%s'. Falling back to stderr.", e->filename);
+ }
+ else
+ netdata_log_error("Cannot open log file '%s'. Leaving fd %d as-is.", e->filename, e->fd);
+ }
+ else {
+ if (!nd_log_replace_existing_fd(e, fd)) {
+ if(e->fd == STDOUT_FILENO || e->fd == STDERR_FILENO) {
+ if(e->fd == STDOUT_FILENO)
+ e->method = NDLM_STDOUT;
+ else if(e->fd == STDERR_FILENO)
+ e->method = NDLM_STDERR;
+
+ // we have dup2() fd, so we can close the one we opened
+ if(fd != STDOUT_FILENO && fd != STDERR_FILENO)
+ close(fd);
+ }
+ else
+ e->fd = fd;
+ }
+ }
+
+ // at this point we have e->fd set properly
+
+ if(e->fd == STDOUT_FILENO)
+ e->fp = stdout;
+ else if(e->fd == STDERR_FILENO)
+ e->fp = stderr;
+
+ if(!e->fp) {
+ e->fp = fdopen(e->fd, "a");
+ if (!e->fp) {
+ netdata_log_error("Cannot fdopen() fd %d ('%s')", e->fd, e->filename);
+
+ if(e->fd != STDOUT_FILENO && e->fd != STDERR_FILENO)
+ close(e->fd);
+
+ e->fp = stderr;
+ e->fd = STDERR_FILENO;
+ }
+ }
+ else {
+ if (setvbuf(e->fp, NULL, _IOLBF, 0) != 0)
+ netdata_log_error("Cannot set line buffering on fd %d ('%s')", e->fd, e->filename);
+ }
+ }
+ break;
+ }
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+
+void nd_log_stdin_init(int fd, const char *filename) {
+ int f = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0664);
+ if(f == -1)
+ return;
+
+ if(f != fd) {
+ dup2(f, fd);
+ close(f);
+ }
+}
+
+void nd_log_initialize(void) {
+ nd_log_stdin_init(STDIN_FILENO, "/dev/null");
+
+ for(size_t i = 0 ; i < _NDLS_MAX ; i++)
+ nd_log_open(&nd_log.sources[i], i);
+}
+
+void nd_log_reopen_log_files(bool log) {
+ if(log)
+ netdata_log_info("Reopening all log files.");
+
+ nd_log_initialize();
+
+ if(log)
+ netdata_log_info("Log files re-opened.");
+}
+
+int nd_log_systemd_journal_fd(void) {
+ return nd_log.journal.fd;
+}
+
+void nd_log_reopen_log_files_for_spawn_server(const char *name) {
+ gettid_uncached();
+
+ if(nd_log.syslog.initialized) {
+ closelog();
+ nd_log.syslog.initialized = false;
+ nd_log_init_syslog();
+ }
+
+ if(nd_log.journal_direct.initialized) {
+ close(nd_log.journal_direct.fd);
+ nd_log.journal_direct.fd = -1;
+ nd_log.journal_direct.initialized = false;
+ }
+
+ for(size_t i = 0; i < _NDLS_MAX ;i++) {
+ spinlock_init(&nd_log.sources[i].spinlock);
+ nd_log.sources[i].method = NDLM_DEFAULT;
+ nd_log.sources[i].fd = -1;
+ nd_log.sources[i].fp = NULL;
+ nd_log.sources[i].pending_msg = NULL;
+#if defined(OS_WINDOWS)
+ nd_log.sources[i].hEventLog = NULL;
+#endif
+ }
+
+ // initialize spinlocks
+ spinlock_init(&nd_log.std_output.spinlock);
+ spinlock_init(&nd_log.std_error.spinlock);
+
+ nd_log.syslog.initialized = false;
+ nd_log.eventlog.initialized = false;
+ nd_log.std_output.initialized = false;
+ nd_log.std_error.initialized = false;
+
+ nd_log_initialize_for_external_plugins(name);
+}
+