[PATCH v19 13/15] log: add optional support of syslog

Stephen Hemminger stephen at networkplumber.org
Sat Mar 30 04:00:56 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                                 | 25 +++---
 lib/log/log_private.h                         |  4 +
 lib/log/log_stubs.c                           | 28 ++++++
 lib/log/log_syslog.c                          | 89 +++++++++++++++++++
 lib/log/meson.build                           |  6 ++
 9 files changed, 165 insertions(+), 41 deletions(-)
 create mode 100644 lib/log/log_stubs.c
 create mode 100644 lib/log/log_syslog.c

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 3c15f2a560..ddb8400d73 100644
--- a/lib/log/log.c
+++ b/lib/log/log.c
@@ -12,18 +12,19 @@
 #include <regex.h>
 #include <fnmatch.h>
 #include <sys/queue.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
 #include <rte_per_lcore.h>
 
-#include "log_internal.h"
-#include "log_private.h"
-
 #ifdef RTE_EXEC_ENV_WINDOWS
 #include <rte_os_shim.h>
 #endif
 
+#include "log_internal.h"
+#include "log_private.h"
+
 struct rte_log_dynamic_type {
 	const char *name;
 	uint32_t loglevel;
@@ -496,13 +497,6 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...)
 	return ret;
 }
 
-/* Placeholder */
-int
-eal_log_syslog(const char *mode __rte_unused)
-{
-	return -1;
-}
-
 /* default log print function */
 int
 log_print(FILE *f, uint32_t level __rte_unused,  const char *format, va_list ap)
@@ -514,8 +508,17 @@ log_print(FILE *f, uint32_t level __rte_unused,  const char *format, va_list ap)
  * Called by rte_eal_init
  */
 void
-eal_log_init(const char *id __rte_unused)
+eal_log_init(const char *id)
 {
+#ifdef RTE_EXEC_ENV_WINDOWS
+	RTE_SET_USED(id);
+#else
+	bool is_terminal = isatty(STDERR_FILENO);
+
+	if (log_syslog_enabled(is_terminal))
+		log_syslog_open(id, is_terminal);
+	else
+#endif
 	if (log_timestamp_enabled())
 		rte_logs.print_func = log_print_with_timestamp;
 	else
diff --git a/lib/log/log_private.h b/lib/log/log_private.h
index 070baee8dd..0e7d10ffca 100644
--- a/lib/log/log_private.h
+++ b/lib/log/log_private.h
@@ -15,4 +15,8 @@ ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 __rte_format_printf(3, 0)
 int log_print_with_timestamp(FILE *f, uint32_t level, const char *format, va_list ap);
 
+bool log_syslog_enabled(bool is_tty);
+void log_syslog_open(const char *id, bool is_terminal);
+
+
 #endif /* LOG_PRIVATE_H */
diff --git a/lib/log/log_stubs.c b/lib/log/log_stubs.c
new file mode 100644
index 0000000000..cb34217af8
--- /dev/null
+++ b/lib/log/log_stubs.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <regex.h>
+#include <fnmatch.h>
+#include <sys/queue.h>
+#include <unistd.h>
+#include <rte_os_shim.h>
+
+#include <rte_log.h>
+#include <rte_per_lcore.h>
+
+#include "log_internal.h"
+#include "log_private.h"
+
+/* Stubs for Windows */
+int
+eal_log_syslog(const char *str __rte_unused)
+{
+	return -1;
+}
diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c
new file mode 100644
index 0000000000..33eff3a1cf
--- /dev/null
+++ b/lib/log/log_syslog.c
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+
+#include "log_internal.h"
+#include "log_private.h"
+
+static enum {
+	LOG_SYSLOG_NONE = 0,	/* do not use syslog */
+	LOG_SYSLOG_AUTO,	/* use syslog only if not a terminal */
+	LOG_SYSLOG_ALWAYS,	/* always use syslog */
+	LOG_SYSLOG_BOTH,	/* log to both syslog and stderr */
+} log_syslog_opt;
+
+int
+eal_log_syslog(const char *str)
+{
+	if (str == NULL || strcmp(str, "auto") == 0)
+		log_syslog_opt = LOG_SYSLOG_AUTO;
+	else if (strcmp(str, "both") == 0)
+		log_syslog_opt = LOG_SYSLOG_BOTH;
+	else if (strcmp(str, "always") == 0)
+		log_syslog_opt = LOG_SYSLOG_ALWAYS;
+	else
+		return -1;
+	return 0;
+}
+
+bool
+log_syslog_enabled(bool is_terminal)
+{
+	switch (log_syslog_opt) {
+	default:
+		return false;
+
+	case LOG_SYSLOG_ALWAYS:
+	case LOG_SYSLOG_BOTH:
+		return true;
+
+	case LOG_SYSLOG_AUTO:
+		return !is_terminal;
+	}
+}
+
+/*
+ * wrapper for log stream to put messages into syslog
+ * useful for cases like:
+ *   rte_hex_dump(rte_get_log_stream(), ...)
+ */
+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,
+};
+
+void
+log_syslog_open(const char *id, bool is_terminal)
+{
+	int flags = LOG_NDELAY | LOG_PID;
+
+	if (log_syslog_opt == LOG_SYSLOG_BOTH)
+		flags |= LOG_PERROR;
+
+	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)
+		rte_openlog_stream(log_stream);
+}
diff --git a/lib/log/meson.build b/lib/log/meson.build
index 04235f6ee5..37507299e7 100644
--- a/lib/log/meson.build
+++ b/lib/log/meson.build
@@ -7,4 +7,10 @@ sources = files(
         'log_timestamp.c',
 )
 
+if is_windows
+	sources += files('log_stubs.c')
+else
+	sources += files('log_syslog.c')
+endif
+
 headers = files('rte_log.h')
-- 
2.43.0



More information about the dev mailing list