diff options
Diffstat (limited to 'libnetdata/log')
-rw-r--r-- | libnetdata/log/Makefile.am | 1 | ||||
-rw-r--r-- | libnetdata/log/README.md | 194 | ||||
-rw-r--r-- | libnetdata/log/journal.c | 138 | ||||
-rw-r--r-- | libnetdata/log/journal.h | 18 | ||||
-rw-r--r-- | libnetdata/log/log.c | 3006 | ||||
-rw-r--r-- | libnetdata/log/log.h | 300 | ||||
-rw-r--r-- | libnetdata/log/log2journal.c | 1015 | ||||
-rw-r--r-- | libnetdata/log/log2journal.md | 518 | ||||
-rw-r--r-- | libnetdata/log/systemd-cat-native.c | 781 | ||||
-rw-r--r-- | libnetdata/log/systemd-cat-native.h | 8 |
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 |