diff --git a/drivers/syslog/CMakeLists.txt b/drivers/syslog/CMakeLists.txt index 74da0e05f2c..33bba7a2d7a 100644 --- a/drivers/syslog/CMakeLists.txt +++ b/drivers/syslog/CMakeLists.txt @@ -25,7 +25,14 @@ set(SRCS) if(CONFIG_SYSLOG) - list(APPEND SRCS vsyslog.c syslog_channel.c syslog_write.c syslog_flush.c) + + if(CONFIG_SYSLOG_RFC5424) + list(APPEND SRCS vsyslog_rfc5424.c) + else() + list(APPEND SRCS vsyslog.c) + endif() + + list(APPEND SRCS syslog_channel.c syslog_write.c syslog_flush.c) endif() if(CONFIG_SYSLOG_INTBUFFER) diff --git a/drivers/syslog/Kconfig b/drivers/syslog/Kconfig index 4fb02bd2fd6..d6c6bbd9b27 100644 --- a/drivers/syslog/Kconfig +++ b/drivers/syslog/Kconfig @@ -140,11 +140,39 @@ config SYSLOG_INTBUFSIZE comment "Formatting options" -config SYSLOG_TIMESTAMP - bool "Prepend timestamp to syslog message" +config SYSLOG_RFC5424 + bool "Standard syslog format (RFC 5424)" default n ---help--- - Prepend timestamp to syslog message. + Forces syslog logs to follow the RFC 5424 (syslog protocol) standard. + This allows for structured data elements, standard severity levels, + standard facilities, standard timestamps and other features that allow + syslogs to be compatible with other open source programs (such as + logging servers). + +if SYSLOG_RFC5424 + +comment "RFC5424 options" + +config SYSLOG_RFC5424_HOSTNAME + bool "Enable hostname field" + default n + ---help--- + Adds the HOSTNAME field to the RFC 5424 compatible syslog output. + +config SYSLOG_RFC5424_TIMEQUALITY + bool "timeQuality structured data" + depends on SYSLOG_TIMESTAMP + default n + ---help--- + Enables the RFC 5424 'timeQuality' structured data element, which describes the + quality of the timestamp sent. + +endif # SYSLOG_RFC5424 + +if !SYSLOG_RFC5424 + +comment "Regular syslog formatting options" config SYSLOG_TIMESTAMP_REALTIME bool "Use wall-clock for syslog timestamp" @@ -198,19 +226,6 @@ config SYSLOG_PRIORITY ---help--- Prepend log priority (severity) to syslog message. -config SYSLOG_PROCESS_NAME - bool "Prepend process name to syslog message" - default n - depends on TASK_NAME_SIZE > 0 - ---help--- - Prepend Process name to syslog message. - -config SYSLOG_PROCESSID - bool "Prepend process ID to syslog message" - default n - ---help--- - Prepend Process ID to syslog message. - config SYSLOG_PREFIX bool "Prepend prefix to syslog message" default n @@ -229,6 +244,28 @@ config SYSLOG_COLOR_OUTPUT ---help--- Enables colored output in syslog, according to message priority. +endif # !SYSLOG_RFC5424 + +config SYSLOG_TIMESTAMP + bool "Timestamp in syslog message" + default n + ---help--- + Prepend timestamp to syslog message, or include the TIMESTAMP field for + RFC 5424. + +config SYSLOG_PROCESS_NAME + bool "Prepend process name to syslog message" + default n + depends on TASK_NAME_SIZE > 0 + ---help--- + Prepend Process name to syslog message. + +config SYSLOG_PROCESSID + bool "Prepend process ID to syslog message" + default n + ---help--- + Prepend Process ID to syslog message. + comment "SYSLOG channels" config SYSLOG_DEVPATH diff --git a/drivers/syslog/Make.defs b/drivers/syslog/Make.defs index 00e1e6b3c76..add6c01b802 100644 --- a/drivers/syslog/Make.defs +++ b/drivers/syslog/Make.defs @@ -24,8 +24,14 @@ # Include SYSLOG Infrastructure ifeq ($(CONFIG_SYSLOG),y) -CSRCS += vsyslog.c syslog_channel.c -CSRCS += syslog_write.c syslog_flush.c + +ifeq ($(CONFIG_SYSLOG_RFC5424),y) + CSRCS += vsyslog_rfc5424.c +else + CSRCS += vsyslog.c +endif + +CSRCS += syslog_channel.c syslog_write.c syslog_flush.c endif ifeq ($(CONFIG_SYSLOG_INTBUFFER),y) diff --git a/drivers/syslog/vsyslog.c b/drivers/syslog/vsyslog.c index fbb50779670..21a1bfe77f5 100644 --- a/drivers/syslog/vsyslog.c +++ b/drivers/syslog/vsyslog.c @@ -229,13 +229,13 @@ int nx_vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap) #if defined(CONFIG_SYSLOG_COLOR_OUTPUT) /* Set the terminal style according to message priority. */ - , g_priority_color[priority] + , g_priority_color[LOG_PRI(priority)] #endif #if defined(CONFIG_SYSLOG_PRIORITY) /* Prepend the message priority. */ - , g_priority_str[priority] + , g_priority_str[LOG_PRI(priority)] #endif #if defined(CONFIG_SYSLOG_PREFIX) diff --git a/drivers/syslog/vsyslog_rfc5424.c b/drivers/syslog/vsyslog_rfc5424.c new file mode 100644 index 00000000000..9a0282874cf --- /dev/null +++ b/drivers/syslog/vsyslog_rfc5424.c @@ -0,0 +1,238 @@ +/**************************************************************************** + * drivers/syslog/vsyslog_rfc5424.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "syslog.h" + +/**************************************************************************** + * Preprocessor definitions + ****************************************************************************/ + +/* RFC5424 NILVALUE encoding */ + +#define NILVALUE "-" +#define NILVALUE_SPACE NILVALUE " " + +/* RFC5424 timestamp format string (fractional seconds and 'Z' added by + * appending to format string) + */ + +#define RFC5424_STRFTIME "%Y-%m-%dT%H:%M:%S" + +/* RFC5424 structured data options were selected */ + +#ifdef CONFIG_SYSLOG_RFC5424_TIMEQUALITY +# define HAVE_RFC5424_SDATA 1 +#else +# define HAVE_RFC5424_SDATA 0 +#endif /* defined(CONFIG_SYSLOG_RFC5424_TIMEQUALITY) || ... */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nx_vsyslog + * + * Description: + * nx_vsyslog() handles the system logging system calls. It is functionally + * equivalent to vsyslog() except that (1) the per-process priority + * filtering has already been performed and the va_list parameter is + * passed by reference. That is because the va_list is a structure in + * some compilers and passing of structures in the NuttX sycalls does + * not work. + * + ****************************************************************************/ + +int nx_vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap) +{ + struct lib_syslograwstream_s stream; + int ret = 0; +#ifdef CONFIG_SYSLOG_PROCESS_NAME + FAR struct tcb_s *tcb = nxsched_self(); +#endif +#ifdef CONFIG_SYSLOG_TIMESTAMP + struct timespec ts = + { + 0 + }; + + struct tm tm = + { + 0 + }; + + char date_buf[64]; +#endif +#ifdef CONFIG_SYSLOG_RFC5424_HOSTNAME + char hostname_buf[HOST_NAME_MAX + 1]; +#endif + + /* Wrap the low-level output in a stream object and let lib_vsprintf + * do the work. + */ + + lib_syslograwstream_open(&stream); + +#ifdef CONFIG_SYSLOG_TIMESTAMP + + /* Get the current time. Since debug output may be generated very early + * in the start-up sequence, hardware timer support may not yet be + * available. + */ + + if (OSINIT_HW_READY()) + { + /* Use CLOCK_REALTIME if so configured */ + + clock_gettime(CLOCK_REALTIME, &ts); + + /* Prepend the message with the current time, if available */ + + gmtime_r(&ts.tv_sec, &tm); + } + + /* RFC 5424 compatible syslog output, use the required format string */ + + strftime(date_buf, sizeof(date_buf), RFC5424_STRFTIME, &tm); +#endif /* CONFIG_SYSLOG_TIMESTAMP */ + + /* Get the host name string. NuttX configures this to be empty by default, + * so if there is just an empty string, we'll set it to the NILVALUE to + * stay within RFC 5424 spec. + */ + +#ifdef CONFIG_SYSLOG_RFC5424_HOSTNAME + gethostname(hostname_buf, sizeof(hostname_buf)); + if (hostname_buf[0] == '\0') + { + memcpy(hostname_buf, NILVALUE, sizeof(NILVALUE)); + } +#endif + + /* Output the RFC5424 header */ + + ret = lib_sprintf_internal(&stream.common, + + /* Start of format string */ + + "<%d>" /* PRI */ + "1 " /* VERSION */ + + /* End of format string */ + +#ifdef CONFIG_SYSLOG_TIMESTAMP + "%s.%06ldZ " /* TIMESTAMP */ +#else + NILVALUE_SPACE /* NO TIMESTAMP */ +#endif +#ifdef CONFIG_SYSLOG_RFC5424_HOSTNAME + "%s " /* HOSTNAME */ +#else + NILVALUE_SPACE /* NO HOSTNAME */ +#endif +#ifdef CONFIG_SYSLOG_PROCESS_NAME + "%s " /* APPNAME */ +#else + NILVALUE_SPACE /* NO APPNAME */ +#endif +#ifdef CONFIG_SYSLOG_PROCESSID + "%d " /* PROCID */ +#else + NILVALUE_SPACE /* NO PROCID */ +#endif + NILVALUE_SPACE /* TODO: MSGID */ +#if !HAVE_RFC5424_SDATA + NILVALUE_SPACE /* Empty structured data, print the NILVALUE here to + * save `libsprintf` call */ +#endif +#ifdef CONFIG_SYSLOG_RFC5424_TIMEQUALITY + "[timeQuality isSynced=\"%d\" tzKnown=\"%d\"]" +#endif +#if HAVE_RFC5424_SDATA + " " /* Space at the end of structured data before message */ +#endif + + /* Beginning of formatted arguments */ + + , priority /* PRIVAL */ +#ifdef CONFIG_SYSLOG_TIMESTAMP + , date_buf, ts.tv_nsec / NSEC_PER_USEC /* TIMESTAMP */ +#endif +#ifdef CONFIG_SYSLOG_RFC5424_HOSTNAME + , hostname_buf /* HOSTNAME */ +#endif +#ifdef CONFIG_SYSLOG_PROCESS_NAME + , get_task_name(tcb) +#endif +#ifdef CONFIG_SYSLOG_PROCESSID + , nxsched_gettid() /* PROCID */ +#endif + /* TODO: MSGID */ + + /* Formatted arguments for structured data */ + +#ifdef CONFIG_SYSLOG_RFC5424_TIMEQUALITY + , 0 /* TODO: Not sure if synced */ + , 0 /* TODO: Not sure if time zone known */ +#endif + /* End of formatted arguments */ + ); + + /* MSG string is generated below from common code for all syslog + * calls since RFC5424 allows the MSG field to be a free-form string. + */ + + /* Generate the output */ + + ret += lib_vsprintf_internal(&stream.common, fmt, *ap); + + if (stream.last_ch != '\n') + { + lib_stream_putc(&stream.common, '\n'); + ret++; + } + + /* Flush and destroy the syslog stream buffer */ + + lib_syslograwstream_close(&stream); + return ret; +} diff --git a/include/syslog.h b/include/syslog.h index 14c527cbce5..d394a6474b8 100644 --- a/include/syslog.h +++ b/include/syslog.h @@ -87,26 +87,26 @@ * LOG_UUCP - UUCP subsystem */ -#define LOG_AUTH 0 -#define LOG_AUTHPRIV 0 -#define LOG_CRON 0 -#define LOG_DAEMON 0 -#define LOG_FTP 0 -#define LOG_KERN 0 -#define LOG_LOCAL0 0 -#define LOG_LOCAL1 0 -#define LOG_LOCAL2 0 -#define LOG_LOCAL3 0 -#define LOG_LOCAL4 0 -#define LOG_LOCAL5 0 -#define LOG_LOCAL6 0 -#define LOG_LOCAL7 0 -#define LOG_LPR 0 -#define LOG_MAIL 0 -#define LOG_NEWS 0 -#define LOG_SYSLOG 0 -#define LOG_USER 0 -#define LOG_UUCP 0 +#define LOG_KERN (0 << 3) +#define LOG_USER (1 << 3) +#define LOG_MAIL (2 << 3) +#define LOG_DAEMON (3 << 3) +#define LOG_AUTH (4 << 3) +#define LOG_SYSLOG (5 << 3) +#define LOG_LPR (6 << 3) +#define LOG_NEWS (7 << 3) +#define LOG_UUCP (8 << 3) +#define LOG_CRON (9 << 3) +#define LOG_AUTHPRIV (10 << 3) +#define LOG_FTP (11 << 3) +#define LOG_LOCAL0 (16 << 3) +#define LOG_LOCAL1 (17 << 3) +#define LOG_LOCAL2 (18 << 3) +#define LOG_LOCAL3 (19 << 3) +#define LOG_LOCAL4 (20 << 3) +#define LOG_LOCAL5 (21 << 3) +#define LOG_LOCAL6 (22 << 3) +#define LOG_LOCAL7 (23 << 3) /* This determines the importance of the message. The levels are, in order * of decreasing importance: @@ -127,6 +127,10 @@ #define LOG_UPTO(p) ((1 << ((p)+1)) - 1) #define LOG_ALL 0xff +#define LOG_PRIMASK 0x07 /* mask to extract priority part (internal) */ +#define LOG_PRI(p) ((p) & LOG_PRIMASK) /* extract priority */ +#define LOG_MAKEPRI(fac, pri) ((fac) | (pri)) + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ diff --git a/libs/libc/syslog/lib_syslog.c b/libs/libc/syslog/lib_syslog.c index 5cdb73c145e..439ea04ea1f 100644 --- a/libs/libc/syslog/lib_syslog.c +++ b/libs/libc/syslog/lib_syslog.c @@ -54,7 +54,7 @@ void vsyslog(int priority, FAR const IPTR char *fmt, va_list ap) { /* Check if this priority is enabled */ - if ((g_syslog_mask & LOG_MASK(priority)) != 0) + if ((g_syslog_mask & LOG_MASK(LOG_PRI(priority))) != 0) { /* Yes.. Perform the nx_vsyslog system call. *