[PATCH v16 13/15] log: add optional support of syslog
Stephen Hemminger
stephen at networkplumber.org
Wed Mar 27 17:45:31 CET 2024
Log to syslog only if option is specified. And if syslog is used
then normally only log to syslog, don't duplicate output.
Also enables syslog support on FreeBSD.
Signed-off-by: Stephen Hemminger <stephen at networkplumber.org>
---
app/test/test_eal_flags.c | 5 +-
doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ----
doc/guides/prog_guide/log_lib.rst | 17 +++
lib/eal/common/eal_common_options.c | 5 +-
lib/log/log.c | 121 ++++++++++++++++--
5 files changed, 137 insertions(+), 38 deletions(-)
diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c
index e54f6e8b7f..08f4866461 100644
--- a/app/test/test_eal_flags.c
+++ b/app/test/test_eal_flags.c
@@ -987,9 +987,10 @@ test_misc_flags(void)
/* With empty --syslog */
const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"};
/* With valid --syslog */
- const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"};
+ const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"};
/* With invalid --syslog */
- const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"};
+ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"};
+
/* With no-sh-conf, also use no-huge to ensure this test runs on BSD */
const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE,
no_shconf, nosh_prefix, no_huge};
diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst
index ea8f381391..d86f94d8a8 100644
--- a/doc/guides/linux_gsg/linux_eal_parameters.rst
+++ b/doc/guides/linux_gsg/linux_eal_parameters.rst
@@ -108,30 +108,3 @@ Memory-related options
* ``--match-allocations``
Free hugepages back to system exactly as they were originally allocated.
-
-Other options
-~~~~~~~~~~~~~
-
-* ``--syslog <syslog facility>``
-
- Set syslog facility. Valid syslog facilities are::
-
- auth
- cron
- daemon
- ftp
- kern
- lpr
- mail
- news
- syslog
- user
- uucp
- local0
- local1
- local2
- local3
- local4
- local5
- local6
- local7
diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst
index 504eefe1d2..abaedc7212 100644
--- a/doc/guides/prog_guide/log_lib.rst
+++ b/doc/guides/prog_guide/log_lib.rst
@@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is::
/path/to/app --log-timestamp=iso
+Log output
+~~~~~~~~~~
+
+If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog``
+option. There are three possible settings for this option:
+
+*always*
+ Redirect all log output to syslog.
+
+*auto*
+ Use console if it is a terminal, and use syslog if is not.
+
+*both*
+ Print to both console and syslog.
+
+If ``--syslog`` option is not specified, then only console (stderr) will be used.
+
Using Logging APIs to Generate Log Messages
diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c
index 5173835c2c..9ca7db04aa 100644
--- a/lib/eal/common/eal_common_options.c
+++ b/lib/eal/common/eal_common_options.c
@@ -91,7 +91,7 @@ eal_long_options[] = {
{OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM },
{OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM },
{OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM },
- {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM },
+ {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM },
{OPT_VDEV, 1, NULL, OPT_VDEV_NUM },
{OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
{OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM },
@@ -2221,6 +2221,9 @@ eal_common_usage(void)
" (can be used multiple times)\n"
" --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n"
" --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n"
+#ifndef RTE_EXEC_ENV_WINDOWS
+ " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n"
+#endif
" --"OPT_LOG_LEVEL"=<level> Set global log level\n"
" --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
" Set specific log level\n"
diff --git a/lib/log/log.c b/lib/log/log.c
index 2dca91306e..ec0d55273e 100644
--- a/lib/log/log.c
+++ b/lib/log/log.c
@@ -13,15 +13,17 @@
#include <sys/queue.h>
#include <unistd.h>
+#ifdef RTE_EXEC_ENV_WINDOWS
+#include <rte_os_shim.h>
+#else
+#include <syslog.h>
+#endif
+
#include <rte_log.h>
#include <rte_per_lcore.h>
#include "log_internal.h"
-#ifdef RTE_EXEC_ENV_WINDOWS
-#include <rte_os_shim.h>
-#endif
-
struct rte_log_dynamic_type {
const char *name;
uint32_t loglevel;
@@ -36,14 +38,25 @@ enum eal_log_time_format {
EAL_LOG_TIMESTAMP_ISO,
};
+enum eal_log_syslog {
+ EAL_LOG_SYSLOG_NONE = 0, /* do not use syslog */
+ EAL_LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */
+ EAL_LOG_SYSLOG_ALWAYS, /* always use syslog */
+ EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */
+};
+
typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap);
static int log_print(FILE *f, uint32_t level, const char *format, va_list ap);
+
/** The rte_log structure. */
static struct rte_logs {
uint32_t type; /**< Bitfield with enabled logs. */
uint32_t level; /**< Log level. */
FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */
+#ifndef RTE_EXEC_ENV_WINDOWS
+ enum eal_log_syslog syslog_opt;
+#endif
log_print_t print_func;
enum eal_log_time_format time_format;
@@ -532,9 +545,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...)
/* Placeholder */
int
-eal_log_syslog(const char *mode __rte_unused)
+eal_log_syslog(const char *str)
{
+#ifdef RTE_EXEC_ENV_WINDOWS
+ RTE_SET_USED(str);
return -1;
+#else
+ if (str == NULL || strcmp(str, "auto") == 0)
+ /* log to syslog only if stderr is not a terminal */
+ rte_logs.syslog_opt = EAL_LOG_SYSLOG_AUTO;
+ else if (strcmp(str, "both") == 0)
+ rte_logs.syslog_opt = EAL_LOG_SYSLOG_BOTH;
+ else if (strcmp(str, "always") == 0)
+ rte_logs.syslog_opt = EAL_LOG_SYSLOG_ALWAYS;
+ else
+ return -1;
+ return 0;
+#endif
}
/* Set the log timestamp format */
@@ -706,17 +733,95 @@ log_print_with_timestamp(FILE *f, uint32_t level,
return log_print(f, level, format, ap);
}
+#ifndef RTE_EXEC_ENV_WINDOWS
+static bool
+using_syslog(bool is_terminal)
+{
+ switch (rte_logs.syslog_opt) {
+ default:
+ return false;
+
+ case EAL_LOG_SYSLOG_ALWAYS:
+ case EAL_LOG_SYSLOG_BOTH:
+ return true;
+
+ case EAL_LOG_SYSLOG_AUTO:
+ return !is_terminal;
+ }
+}
+
/*
- * Called by rte_eal_init
+ * wrapper for log stream to put messages into syslog
+ * useful for cases like:
+ * rte_hex_dump(rte_get_log_stream(), ...)
*/
-void
-eal_log_init(const char *id __rte_unused)
+static ssize_t
+syslog_log_write(__rte_unused void *c, const char *buf, size_t size)
{
+ /* Syslog error levels are from 0 to 7, so subtract 1 to convert */
+ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf);
+ return size;
+}
+
+static int
+syslog_log_close(__rte_unused void *c)
+{
+ closelog();
+ return 0;
+}
+
+static cookie_io_functions_t syslog_log_func = {
+ .write = syslog_log_write,
+ .close = syslog_log_close,
+};
+
+static void
+log_open_syslog(const char *id, bool is_terminal)
+{
+ int flags = LOG_NDELAY | LOG_PID;
+
+#ifdef LOG_PERROR
+ if (rte_logs.syslog_opt == EAL_LOG_SYSLOG_BOTH)
+ flags |= LOG_PERROR;
+#endif
+ openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON);
+
+ /* redirect other log messages to syslog as well */
+ FILE *log_stream = fopencookie(NULL, "w", syslog_log_func);
+ if (log_stream != NULL)
+ default_log_stream = log_stream;
+}
+#endif
+
+/* Choose how log output is directed */
+static void
+log_output_selection(const char *id)
+{
+ RTE_SET_USED(id);
+
+#ifndef RTE_EXEC_ENV_WINDOWS
+ bool is_terminal = isatty(STDERR_FILENO);
+
+ if (using_syslog(is_terminal)) {
+ log_open_syslog(id, is_terminal);
+ return;
+ }
+#endif
if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE)
rte_logs.print_func = log_print_with_timestamp;
+}
+/*
+ * Called by rte_eal_init
+ */
+void
+eal_log_init(const char *id)
+{
+ rte_logs.print_func = log_print;
default_log_stream = stderr;
+ log_output_selection(id);
+
#if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
RTE_LOG(NOTICE, EAL,
"Debug dataplane logs available - lower performance\n");
--
2.43.0
More information about the dev
mailing list