summaryrefslogtreecommitdiffstats
path: root/libnetdata/log
diff options
context:
space:
mode:
Diffstat (limited to 'libnetdata/log')
-rw-r--r--libnetdata/log/Makefile.am1
-rw-r--r--libnetdata/log/README.md194
-rw-r--r--libnetdata/log/journal.c138
-rw-r--r--libnetdata/log/journal.h18
-rw-r--r--libnetdata/log/log.c3006
-rw-r--r--libnetdata/log/log.h300
-rw-r--r--libnetdata/log/log2journal.c1015
-rw-r--r--libnetdata/log/log2journal.md518
-rw-r--r--libnetdata/log/systemd-cat-native.c781
-rw-r--r--libnetdata/log/systemd-cat-native.h8
10 files changed, 4984 insertions, 995 deletions
diff --git a/libnetdata/log/Makefile.am b/libnetdata/log/Makefile.am
index 161784b8f6..8a178bfed2 100644
--- a/libnetdata/log/Makefile.am
+++ b/libnetdata/log/Makefile.am
@@ -5,4 +5,5 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
dist_noinst_DATA = \
README.md \
+ log2journal.md \
$(NULL)
diff --git a/libnetdata/log/README.md b/libnetdata/log/README.md
index f811bb4b3a..e868de0373 100644
--- a/libnetdata/log/README.md
+++ b/libnetdata/log/README.md
@@ -7,8 +7,196 @@ learn_topic_type: "Tasks"
learn_rel_path: "Developers/libnetdata"
-->
-# Log
+# Netdata Logging
-The netdata log library supports debug, info, error and fatal error logging.
-By default we have an access log, an error log and a collectors log.
+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**, logs all alert transitions
+
+## 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
+
+Netdata supports the follow formats for its logs:
+
+- **journal**, this is automatically selected when logging to systemd-journal.
+- **logfmt**, this is the default when logging to any output other than `journal`. In this format, Netdata annotates the fields to make them human readable.
+- **json**, to write logs lines in json format. The output is machine readable, similar to `journal`.
+
+## Log levels
+
+Each time Netdata logs, it assigns a priority to the log. It can be one of this (in order of importance):
+
+- **emergency**, a fatal condition; most likely Netdata will 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 that may or may not affect the operation of Netdata, but the outcome cannot be determined at the time Netdata logs,
+- **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 = 600
+ # logs flood protection period = 3600
+ # 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
+
+Netdata exposes the following fields to its logs:
+
+| 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_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 |
+
+
+### 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
+```
diff --git a/libnetdata/log/journal.c b/libnetdata/log/journal.c
new file mode 100644
index 0000000000..21978cf5f5
--- /dev/null
+++ b/libnetdata/log/journal.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "journal.h"
+
+bool is_path_unix_socket(const char *path) {
+ 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
+ return false;
+
+ // Check if the file is a socket
+ if (S_ISSOCK(statbuf.st_mode))
+ return true;
+
+ return false;
+}
+
+bool is_stderr_connected_to_journal(void) {
+ const char *journal_stream = getenv("JOURNAL_STREAM");
+ if (!journal_stream)
+ return false; // JOURNAL_STREAM is not set
+
+ struct stat stderr_stat;
+ if (fstat(STDERR_FILENO, &stderr_stat) < 0)
+ return false; // Error in getting stderr info
+
+ // Parse device and inode from JOURNAL_STREAM
+ char *endptr;
+ long journal_dev = strtol(journal_stream, &endptr, 10);
+ if (*endptr != ':')
+ return false; // Format error in JOURNAL_STREAM
+
+ long journal_ino = strtol(endptr + 1, NULL, 10);
+
+ return (stderr_stat.st_dev == (dev_t)journal_dev) && (stderr_stat.st_ino == (ino_t)journal_ino);
+}
+
+int journal_direct_fd(const char *path) {
+ if(!path || !*path)
+ path = JOURNAL_DIRECT_SOCKET;
+
+ if(!is_path_unix_socket(path))
+ return -1;
+
+ int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (fd < 0) return -1;
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
+
+ // Connect the socket (optional, but can simplify send operations)
+ if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static inline bool journal_send_with_memfd(int fd, const char *msg, size_t msg_len) {
+#if defined(__NR_memfd_create) && defined(MFD_ALLOW_SEALING) && defined(F_ADD_SEALS) && defined(F_SEAL_SHRINK) && defined(F_SEAL_GROW) && defined(F_SEAL_WRITE)
+ // Create a memory file descriptor
+ int memfd = (int)syscall(__NR_memfd_create, "journald", MFD_ALLOW_SEALING);
+ if (memfd < 0) return false;
+
+ // Write data to the memfd
+ if (write(memfd, msg, msg_len) != (ssize_t)msg_len) {
+ close(memfd);
+ return false;
+ }
+
+ // Seal the memfd to make it immutable
+ if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE) < 0) {
+ close(memfd);
+ return false;
+ }
+
+ struct iovec iov = {0};
+ struct msghdr msghdr = {0};
+ struct cmsghdr *cmsghdr;
+ char cmsgbuf[CMSG_SPACE(sizeof(int))];
+
+ msghdr.msg_iov = &iov;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_control = cmsgbuf;
+ msghdr.msg_controllen = sizeof(cmsgbuf);
+
+ cmsghdr = CMSG_FIRSTHDR(&msghdr);
+ cmsghdr->cmsg_level = SOL_SOCKET;
+ cmsghdr->cmsg_type = SCM_RIGHTS;
+ cmsghdr->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cmsghdr), &memfd, sizeof(int));
+
+ ssize_t r = sendmsg(fd, &msghdr, 0);
+
+ close(memfd);
+ return r >= 0;
+#else
+ return false;
+#endif
+}
+
+bool journal_direct_send(int fd, const char *msg, size_t msg_len) {
+ // Send the datagram
+ if (send(fd, msg, msg_len, 0) < 0) {
+ if(errno != EMSGSIZE)
+ return false;
+
+ // datagram is too large, fallback to memfd
+ if(!journal_send_with_memfd(fd, msg, msg_len))
+ return false;
+ }
+
+ return true;
+}
+
+void journal_construct_path(char *dst, size_t dst_len, const char *host_prefix, const char *namespace_str) {
+ if(!host_prefix)
+ host_prefix = "";
+
+ if(namespace_str)
+ snprintfz(dst, dst_len, "%s/run/systemd/journal.%s/socket",
+ host_prefix, namespace_str);
+ else
+ snprintfz(dst, dst_len, "%s" JOURNAL_DIRECT_SOCKET,
+ host_prefix);
+}
diff --git a/libnetdata/log/journal.h b/libnetdata/log/journal.h
new file mode 100644
index 0000000000..df8ece18b0
--- /dev/null
+++ b/libnetdata/log/journal.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "../libnetdata.h"
+
+#ifndef NETDATA_LOG_JOURNAL_H
+#define NETDATA_LOG_JOURNAL_H
+
+#define JOURNAL_DIRECT_SOCKET "/run/systemd/journal/socket"
+
+void journal_construct_path(char *dst, size_t dst_len, const char *host_prefix, const char *namespace_str);
+
+int journal_direct_fd(const char *path);
+bool journal_direct_send(int fd, const char *msg, size_t msg_len);
+
+bool is_path_unix_socket(const char *path);
+bool is_stderr_connected_to_journal(void);
+
+#endif //NETDATA_LOG_JOURNAL_H
diff --git a/libnetdata/log/log.c b/libnetdata/log/log.c
index 02bb776c5b..b771cf96ea 100644
--- a/libnetdata/log/log.c
+++ b/libnetdata/log/log.c
@@ -1,472 +1,301 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-#include <daemon/main.h>
+#define SD_JOURNAL_SUPPRESS_LOCATION
+
#include "../libnetdata.h"
+#include <daemon/main.h>
+
+#ifdef __FreeBSD__
+#include <sys/endian.h>
+#endif
+
+#ifdef __APPLE__
+#include <machine/endian.h>
+#endif
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
#endif
-int web_server_is_multithreaded = 1;
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-journal.h>
+#endif
+
+#include <syslog.h>
const char *program_name = "";
+
uint64_t debug_flags = 0;
-int access_log_syslog = 0;
-int error_log_syslog = 0;
-int collector_log_syslog = 0;
-int output_log_syslog = 0; // debug log
-int health_log_syslog = 0;
+#ifdef ENABLE_ACLK
+int aclklog_enabled = 0;
+#endif
+
+// ----------------------------------------------------------------------------
+
+struct nd_log_source;
+static bool nd_log_limit_reached(struct nd_log_source *source);
-int stdaccess_fd = -1;
-FILE *stdaccess = NULL;
+// ----------------------------------------------------------------------------
+// logging method
+
+typedef enum __attribute__((__packed__)) {
+ NDLO_DISABLED = 0,
+ NDLO_DEVNULL,
+ NDLO_DEFAULT,
+ NDLO_JOURNAL,
+ NDLO_SYSLOG,
+ NDLO_STDOUT,
+ NDLO_STDERR,
+ NDLO_FILE,
+} ND_LOG_OUTPUT;
+
+
+static struct {
+ ND_LOG_OUTPUT output;
+ const char *name;
+} nd_log_outputs[] = {
+ { .output = NDLO_DISABLED, .name = "none" },
+ { .output = NDLO_DEVNULL, .name = "/dev/null" },
+ { .output = NDLO_DEFAULT, .name = "default" },
+ { .output = NDLO_JOURNAL, .name = "journal" },
+ { .output = NDLO_SYSLOG, .name = "syslog" },
+ { .output = NDLO_STDOUT, .name = "stdout" },
+ { .output = NDLO_STDERR, .name = "stderr" },
+ { .output = NDLO_FILE, .name = "file" },
+};
+
+static ND_LOG_OUTPUT nd_log_output2id(const char *output) {
+ if(!output || !*output)
+ return NDLO_DEFAULT;
+
+ size_t entries = sizeof(nd_log_outputs) / sizeof(nd_log_outputs[0]);
+ for(size_t i = 0; i < entries ;i++) {
+ if(strcmp(nd_log_outputs[i].name, output) == 0)
+ return nd_log_outputs[i].output;
+ }
-int stdhealth_fd = -1;
-FILE *stdhealth = NULL;
+ return NDLO_FILE;
+}
-int stdcollector_fd = -1;
-FILE *stderror = NULL;
+static const char *nd_log_id2output(ND_LOG_OUTPUT output) {
+ size_t entries = sizeof(nd_log_outputs) / sizeof(nd_log_outputs[0]);
+ for(size_t i = 0; i < entries ;i++) {
+ if(output == nd_log_outputs[i].output)
+ return nd_log_outputs[i].name;
+ }
-const char *stdaccess_filename = NULL;
-const char *stderr_filename = NULL;
-const char *stdout_filename = NULL;
-const char *facility_log = NULL;
-const char *stdhealth_filename = NULL;
-const char *stdcollector_filename = NULL;
+ return "unknown";
+}
-netdata_log_level_t global_log_severity_level = NETDATA_LOG_LEVEL_INFO;
+// ----------------------------------------------------------------------------
+// workaround strerror_r()
-#ifdef ENABLE_ACLK
-const char *aclklog_filename = NULL;
-int aclklog_fd = -1;
-FILE *aclklog = NULL;
-int aclklog_syslog = 1;
-int aclklog_enabled = 0;
+#if defined(STRERROR_R_CHAR_P)
+// GLIBC version of strerror_r
+static const char *strerror_result(const char *a, const char *b) { (void)b; return a; }
+#elif defined(HAVE_STRERROR_R)
+// POSIX version of strerror_r
+static const char *strerror_result(int a, const char *b) { (void)a; return b; }
+#elif defined(HAVE_C__GENERIC)
+
+// what a trick!
+// http://stackoverflow.com/questions/479207/function-overloading-in-c
+static const char *strerror_result_int(int a, const char *b) { (void)a; return b; }
+static const char *strerror_result_string(const char *a, const char *b) { (void)b; return a; }
+
+#define strerror_result(a, b) _Generic((a), \
+ int: strerror_result_int, \
+ char *: strerror_result_string \
+ )(a, b)
+
+#else
+#error "cannot detect the format of function strerror_r()"
#endif
+static const char *errno2str(int errnum, char *buf, size_t size) {
+ return strerror_result(strerror_r(errnum, buf, size), buf);
+}
+
// ----------------------------------------------------------------------------
-// Log facility(https://tools.ietf.org/html/rfc5424)
+// facilities
//
-// The facilities accepted in the Netdata are in according with the following
-// header files for their respective operating system:
-// sys/syslog.h (Linux )
+// sys/syslog.h (Linux)
// sys/sys/syslog.h (FreeBSD)
// bsd/sys/syslog.h (darwin-xnu)
-#define LOG_AUTH_KEY "auth"
-#define LOG_AUTHPRIV_KEY "authpriv"
-#ifdef __FreeBSD__
-# define LOG_CONSOLE_KEY "console"
-#endif
-#define LOG_CRON_KEY "cron"
-#define LOG_DAEMON_KEY "daemon"
-#define LOG_FTP_KEY "ftp"
-#ifdef __APPLE__
-# define LOG_INSTALL_KEY "install"
-#endif
-#define LOG_KERN_KEY "kern"
-#define LOG_LPR_KEY "lpr"
-#define LOG_MAIL_KEY "mail"
-//#define LOG_INTERNAL_MARK_KEY "mark"
-#ifdef __APPLE__
-# define LOG_NETINFO_KEY "netinfo"
-# define LOG_RAS_KEY "ras"
-# define LOG_REMOTEAUTH_KEY "remoteauth"
-#endif
-#define LOG_NEWS_KEY "news"
-#ifdef __FreeBSD__
-# define LOG_NTP_KEY "ntp"
-#endif
-#define LOG_SECURITY_KEY "security"
-#define LOG_SYSLOG_KEY "syslog"
-#define LOG_USER_KEY "user"
-#define LOG_UUCP_KEY "uucp"
-#ifdef __APPLE__
-# define LOG_LAUNCHD_KEY "launchd"
-#endif
-#define LOG_LOCAL0_KEY "local0"
-#define LOG_LOCAL1_KEY "local1"
-#define LOG_LOCAL2_KEY "local2"
-#define LOG_LOCAL3_KEY "local3"
-#define LOG_LOCAL4_KEY "local4"
-#define LOG_LOCAL5_KEY "local5"
-#define LOG_LOCAL6_KEY "local6"
-#define LOG_LOCAL7_KEY "local7"
-
-static int log_facility_id(const char *facility_name)
-{
- static int
- hash_auth = 0,
- hash_authpriv = 0,
-#ifdef __FreeBSD__
- hash_console = 0,
-#endif
- hash_cron = 0,
- hash_daemon = 0,
- hash_ftp = 0,
-#ifdef __APPLE__
- hash_install = 0,
-#endif
- hash_kern = 0,
- hash_lpr = 0,
- hash_mail = 0,
-// hash_mark = 0,
-#ifdef __APPLE__
- hash_netinfo = 0,
- hash_ras = 0,
- hash_remoteauth = 0,
-#endif
- hash_news = 0,
-#ifdef __FreeBSD__
- hash_ntp = 0,
-#endif
- hash_security = 0,
- hash_syslog = 0,
- hash_user = 0,
- hash_uucp = 0,
-#ifdef __APPLE__
- hash_launchd = 0,
-#endif
- hash_local0 = 0,
- hash_local1 = 0,
- hash_local2 = 0,
- hash_local3 = 0,
- hash_local4 = 0,
- hash_local5 = 0,
- hash_local6 = 0,
- hash_local7 = 0;
-
- if(unlikely(!hash_auth))
- {
- hash_auth = simple_hash(LOG_AUTH_KEY);
- hash_authpriv = simple_hash(LOG_AUTHPRIV_KEY);
-#ifdef __FreeBSD__
- hash_console = simple_hash(LOG_CONSOLE_KEY);
-#endif
- hash_cron = simple_hash(LOG_CRON_KEY);
- hash_daemon = simple_hash(LOG_DAEMON_KEY);
- hash_ftp = simple_hash(LOG_FTP_KEY);
-#ifdef __APPLE__
- hash_install = simple_hash(LOG_INSTALL_KEY);
-#endif
- hash_kern = simple_hash(LOG_KERN_KEY);
- hash_lpr = simple_hash(LOG_LPR_KEY);
- hash_mail = simple_hash(LOG_MAIL_KEY);
-// hash_mark = simple_uhash();
-#ifdef __APPLE__
- hash_netinfo = simple_hash(LOG_NETINFO_KEY);
- hash_ras = simple_hash(LOG_RAS_KEY);
- hash_remoteauth = simple_hash(LOG_REMOTEAUTH_KEY);
-#endif
- hash_news = simple_hash(LOG_NEWS_KEY);
-#ifdef __FreeBSD__
- hash_ntp = simple_hash(LOG_NTP_KEY);
-#endif
- hash_security = simple_hash(LOG_SECURITY_KEY);
- hash_syslog = simple_hash(LOG_SYSLOG_KEY);
- hash_user = simple_hash(LOG_USER_KEY);
- hash_uucp = simple_hash(LOG_UUCP_KEY);
-#ifdef __APPLE__
- hash_launchd = simple_hash(LOG_LAUNCHD_KEY);
-#endif
- hash_local0 = simple_hash(LOG_LOCAL0_KEY);
- hash_local1 = simple_hash(LOG_LOCAL1_KEY);
- hash_local2 = simple_hash(LOG_LOCAL2_KEY);
- hash_local3 = simple_hash(LOG_LOCAL3_KEY);
- hash_local4 = simple_hash(LOG_LOCAL4_KEY);
- hash_local5 = simple_hash(LOG_LOCAL5_KEY);
- hash_local6 = simple_hash(LOG_LOCAL6_KEY);
- hash_local7 = simple_hash(LOG_LOCAL7_KEY);
- }
+static struct {
+ int facility;
+ const char *name;
+} nd_log_facilities[] = {
+ { LOG_AUTH, "auth" },
+ { LOG_AUTHPRIV, "authpriv" },
+ { LOG_CRON, "cron" },
+ { LOG_DAEMON, "daemon" },
+ { LOG_FTP, "ftp" },
+ { LOG_KERN, "kern" },
+ { LOG_LPR, "lpr" },
+ { LOG_MAIL, "mail" },
+ { LOG_NEWS, "news" },
+ { LOG_SYSLOG, "syslog" },
+ { LOG_USER, "user" },
+ { LOG_UUCP, "uucp" },
+ { LOG_LOCAL0, "local0" },
+ { LOG_LOCAL1, "local1" },
+ { LOG_LOCAL2, "local2" },
+ { LOG_LOCAL3, "local3" },
+ { LOG_LOCAL4, "local4" },
+ { LOG_LOCAL5, "local5" },
+ { LOG_LOCAL6, "local6" },
+ { LOG_LOCAL7, "local7" },
- int hash = simple_hash(facility_name);
- if ( hash == hash_auth )
- {
- return LOG_AUTH;
- }
- else if ( hash == hash_authpriv )
- {
- return LOG_AUTHPRIV;
- }
#ifdef __FreeBSD__
- else if ( hash == hash_console )
- {
- return LOG_CONSOLE;
- }
-#endif
- else if ( hash == hash_cron )
- {
- return LOG_CRON;
- }
- else if ( hash == hash_daemon )
- {
- return LOG_DAEMON;
- }
- else if ( hash == hash_ftp )
- {
- return LOG_FTP;
- }
-#ifdef __APPLE__
- else if ( hash == hash_install )
- {
- return LOG_INSTALL;
- }
+ { LOG_CONSOLE, "console" },
+ { LOG_NTP, "ntp" },
+
+ // FreeBSD does not consider 'security' as deprecated.
+ { LOG_SECURITY, "security" },
+#else
+ // For all other O/S 'security' is mapped to 'auth'.
+ { LOG_AUTH, "security" },
#endif
- else if ( hash == hash_kern )
- {
- return LOG_KERN;
- }
- else if ( hash == hash_lpr )
- {
- return LOG_LPR;
- }
- else if ( hash == hash_mail )
- {
- return LOG_MAIL;
- }
- /*
- else if ( hash == hash_mark )
- {
- //this is internal for all OS
- return INTERNAL_MARK;
- }
- */
+
#ifdef __APPLE__
- else if ( hash == hash_netinfo )
- {
- return LOG_NETINFO;
- }
- else if ( hash == hash_ras )
- {
- return LOG_RAS;
- }
- else if ( hash == hash_remoteauth )
- {
- return LOG_REMOTEAUTH;
- }
-#endif
- else if ( hash == hash_news )
- {
- return LOG_NEWS;
- }
-#ifdef __FreeBSD__
- else if ( hash == hash_ntp )
- {
- return LOG_NTP;
- }
-#endif
- else if ( hash == hash_security )
- {
- //FreeBSD is the unique that does not consider
- //this facility deprecated. We are keeping
- //it for other OS while they are kept in their headers.
-#ifdef __FreeBSD__
- return LOG_SECURITY;
-#else
- ret