Skip to contentSkip to conversation

eal: add option to put timestamp on console output

PATCH In review Stephen Hemminger 12 participants 486 messages Aug 14, 2020 – Nov 8, 2024 Arm/Amlogic Meson SoC support Page 5 of 5

lore
Share & tools
lore
#410 lore raw

PATCH v28 9/13 log: add hook for printing log messages

In reply to Stephen Hemminger

This is useful for when decorating log output for console or journal. Provide basic version in this patch.

---
 lib/log/log.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
lib/log/log.c +7 -1
index feadcd6848..5e1eeb25c7 100644
@@ -30,16 +30,21 @@ struct rte_log_dynamic_type {
 	uint32_t loglevel;
 };
 
+/* Note: same as vfprintf() */
+typedef int (*log_print_t)(FILE *f, const char *fmt, 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. */
+	log_print_t print_func;
 	size_t dynamic_types_len;
 	struct rte_log_dynamic_type *dynamic_types;
 } rte_logs = {
 	.type = UINT32_MAX,
 	.level = RTE_LOG_DEBUG,
+	.print_func = vfprintf,
 };
 
 struct rte_eal_opt_loglevel {
@@ -76,6 +81,7 @@ int
 rte_openlog_stream(FILE *f)
 {
 	rte_logs.file = f;
+	rte_logs.print_func = vfprintf;
 	return 0;
 }
 
@@ -472,7 +478,7 @@ rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap)
 	RTE_PER_LCORE(log_cur_msg).loglevel = level;
 	RTE_PER_LCORE(log_cur_msg).logtype = logtype;
 
-	ret = vfprintf(f, format, ap);
+	ret = (*rte_logs.print_func)(f, format, ap);
 	fflush(f);
 	return ret;
 }
Signature · 1 line
2.45.2
#411 lore raw

PATCH v28 10/13 log: add timestamp option

In reply to Stephen Hemminger

When debugging driver or startup issues, it is useful to have a timestamp on each message printed. The messages in syslog already have a timestamp, but often syslog is not available during testing.

There are multiple timestamp formats similar to Linux dmesg. The default is time relative since startup (when first step of logging initialization is done by constructor). Other alternative formats are delta, ctime, reltime and iso formats.

Example:

$ dpdk-testpmd --log-timestamp -- -i
[     0.008610] EAL: Detected CPU lcores: 8
[     0.008634] EAL: Detected NUMA nodes: 1
[     0.008792] EAL: Detected static linkage of DPDK
[     0.010620] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
[     0.012618] EAL: Selected IOVA mode 'VA'
[     0.016675] testpmd: No probed ethernet devices
Interactive-mode selected
---
 app/test/test_eal_flags.c           |  26 +++
 doc/guides/prog_guide/log_lib.rst   |  30 +++-
 lib/eal/common/eal_common_options.c |  14 +-
 lib/eal/common/eal_options.h        |   2 +
 lib/eal/freebsd/eal.c               |   6 +-
 lib/eal/linux/eal.c                 |   4 +-
 lib/eal/windows/eal.c               |   4 +-
 lib/log/log.c                       |   5 +
 lib/log/log_internal.h              |   9 ++
 lib/log/log_private.h               |   6 +
 lib/log/log_timestamp.c             | 240 ++++++++++++++++++++++++++++
 lib/log/meson.build                 |   1 +
 lib/log/version.map                 |   1 +
 13 files changed, 341 insertions(+), 7 deletions(-)
 create mode 100644 lib/log/log_timestamp.c
app/test/test_eal_flags.c +26 -0
index 9fcf0d56e6..e24630edde 100644
@@ -1055,6 +1055,19 @@ test_misc_flags(void)
 	const char * const argv22[] = {prgname, prefix, mp_flag,
 				       "--huge-worker-stack=512"};
 
+	/* Try running with --log-timestamp */
+	const char * const argv23[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp" };
+
+	/* Try running with --log-timestamp=iso */
+	const char * const argv24[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=iso" };
+
+	/* Try running with invalid timestamp */
+	const char * const argv25[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=invalid" };
+
+
 	/* run all tests also applicable to FreeBSD first */
 
 	if (launch_proc(argv0) == 0) {
@@ -1162,6 +1175,19 @@ test_misc_flags(void)
 		printf("Error - process did not run ok with --huge-worker-stack=size parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv23) != 0) {
+		printf("Error - process did not run ok with --log-timestamp parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv24) != 0) {
+		printf("Error - process did not run ok with --log-timestamp=iso parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv25) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
+
 
 	rmdir(hugepath_dir3);
 	rmdir(hugepath_dir2);
doc/guides/prog_guide/log_lib.rst +29 -1
index c87830ac00..82d3b7be2b 100644
@@ -57,7 +57,6 @@ For example::
 
 Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.
 
-
 Using Logging APIs to Generate Log Messages
 -------------------------------------------
 
@@ -109,3 +108,32 @@ Throughout the cfgfile library, all logging calls are therefore of the form:
 
 	CFG_LOG(ERR, "invalid comment characters %c",
 	       params->comment_character);
+
+Log timestamp
+~~~~~~~~~~~~~
+
+An optional timestamp can be added before each message
+by adding the ``--log-timestamp`` option.
+For example::
+
+	/path/to/app --log-level=lib.*:debug --log-timestamp
+
+Multiple timestamp alternative timestamp formats are available:
+
+.. csv-table:: Log time stamp format
+   :header: "Format", "Description", "Example"
+   :widths: 6, 30, 32
+
+   "ctime", "Unix ctime", "``[Wed Mar 20 07:26:12 2024]``"
+   "delta", "Offset since last", "``[<    3.162373>]``"
+   "reltime", "Seconds since last or time if minute changed", "``[  +3.001791]`` or ``[Mar20 07:26:12]``"
+   "iso", "ISO-8601", "``[2024-03-20T07:26:12−07:00]``"
+
+To prefix all console messages with ISO format time the syntax is::
+
+	/path/to/app --log-timestamp=iso
+
+.. note::
+
+   Timestamp option has no effect if using syslog because the ``syslog()``
+   service already does timestamping internally.
lib/eal/common/eal_common_options.c +12 -2
index ca7b702e03..a70d63479a 100644
@@ -74,6 +74,7 @@ eal_long_options[] = {
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
+	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
 	{OPT_TRACE_DIR,         1, NULL, OPT_TRACE_DIR_NUM        },
 	{OPT_TRACE_BUF_SIZE,    1, NULL, OPT_TRACE_BUF_SIZE_NUM   },
@@ -1618,6 +1619,7 @@ eal_log_level_parse(int argc, char * const argv[])
 		switch (opt) {
 		case OPT_LOG_LEVEL_NUM:
 		case OPT_SYSLOG_NUM:
+		case OPT_LOG_TIMESTAMP_NUM:
 			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
 				return -1;
 			break;
@@ -1840,7 +1842,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		break;
 #endif
 
-	case OPT_LOG_LEVEL_NUM: {
+	case OPT_LOG_LEVEL_NUM:
 		if (eal_parse_log_level(optarg) < 0) {
 			EAL_LOG(ERR,
 				"invalid parameters for --"
@@ -1848,7 +1850,14 @@ eal_parse_common_option(int opt, const char *optarg,
 			return -1;
 		}
 		break;
-	}
+
+	case OPT_LOG_TIMESTAMP_NUM:
+		if (eal_log_timestamp(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_TIMESTAMP);
+			return -1;
+		}
+		break;
 
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
@@ -2215,6 +2224,7 @@ eal_common_usage(void)
 	       "  --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
+	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index f3f2e104f6..e24c9eca53 100644
@@ -35,6 +35,8 @@ enum {
 	OPT_LCORES_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
+#define OPT_LOG_TIMESTAMP     "log-timestamp"
+	OPT_LOG_TIMESTAMP_NUM,
 #define OPT_TRACE             "trace"
 	OPT_TRACE_NUM,
 #define OPT_TRACE_DIR         "trace-dir"
lib/eal/freebsd/eal.c +4 -2
index 8631a20eae..456f91522c 100644
@@ -392,8 +392,10 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled these */
-		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_LOG_SYSLOG_NUM)
+		/* eal_log_level_parse() already handled these options */
+		if (opt == OPT_LOG_LEVEL_NUM ||
+		    opt == OPT_SYSLOG_NUM ||
+		    opt == OPT_LOG_TIMESTAMP_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/eal/linux/eal.c +3 -1
index 62d3d281c4..cf2f0fcab9 100644
@@ -611,7 +611,9 @@ eal_parse_args(int argc, char **argv)
 		}
 
 		/* eal_log_level_parse() already handled these options */
-		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
+		if (opt == OPT_LOG_LEVEL_NUM ||
+		    opt == OPT_SYSLOG_NUM ||
+		    opt == OPT_LOG_TIMESTAMP_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/eal/windows/eal.c +3 -1
index 33f044d7cc..b1c59945fb 100644
@@ -121,7 +121,9 @@ eal_parse_args(int argc, char **argv)
 		}
 
 		/* eal_log_level_parse() already handled these options */
-		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
+		if (opt == OPT_LOG_LEVEL_NUM ||
+		    opt == OPT_SYSLOG_NUM ||
+		    opt == OPT_LOG_TIMESTAMP_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/log/log.c +5 -0
index 5e1eeb25c7..7bf4548858 100644
@@ -514,6 +514,11 @@ eal_log_init(const char *id)
 	if (logf)
 		rte_openlog_stream(logf);
 
+	if (log_timestamp_enabled())
+		rte_logs.print_func = log_print_with_timestamp;
+	else
+		rte_logs.print_func = vfprintf;
+
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
 		"Debug dataplane logs available - lower performance\n");
lib/log/log_internal.h +9 -0
index d5fabd7ef7..8ef195a6ec 100644
@@ -5,8 +5,10 @@
 #ifndef LOG_INTERNAL_H
 #define LOG_INTERNAL_H
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <time.h>
 
 #include <rte_compat.h>
 
@@ -45,4 +47,11 @@ const char *eal_log_level2str(uint32_t level);
 __rte_internal
 void rte_eal_log_cleanup(void);
 
+/*
+ * Add timestamp to console logs
+ */
+__rte_internal
+int eal_log_timestamp(const char *fmt);
+
+
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +6 -0
index bf87b43f7e..86eaf3f910 100644
@@ -22,4 +22,10 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+bool log_timestamp_enabled(void);
+ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
+
+__rte_format_printf(2, 0)
+int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/log_timestamp.c new file +240 -0

240 lines not on this page · raw message

lib/log/meson.build +1 -0
index 160cf34f50..4ac232786e 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_timestamp.c',
 )
 
 if not is_windows
lib/log/version.map +1 -0
index 1637fba3b9..8be6907840 100644
@@ -30,5 +30,6 @@ INTERNAL {
 	eal_log_save_pattern;
 	eal_log_save_regexp;
 	eal_log_syslog; # WINDOWS_NO_EXPORT
+	eal_log_timestamp;
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.45.2
#412 lore raw

PATCH v28 11/13 log: add support for systemd journal

In reply to Stephen Hemminger

If DPDK application is being run as a systemd service, then it can use the journal protocol which allows putting more information in the log such as priority and other information.

The use of journal protocol is automatically detected and handled. Rather than having a dependency on libsystemd, just use the protocol directly as defined in:
https://systemd.io/JOURNAL_NATIVE_PROTOCOL/

---
 lib/log/log.c          |   7 +-
 lib/log/log_internal.h |   3 +
 lib/log/log_journal.c  | 154 +++++++++++++++++++++++++++++++++++++++++
 lib/log/log_private.h  |  14 ++++
 lib/log/log_syslog.c   |   9 +++
 lib/log/meson.build    |   4 ++
 lib/log/version.map    |   1 +
 7 files changed, 189 insertions(+), 3 deletions(-)
 create mode 100644 lib/log/log_journal.c
lib/log/log.c +4 -3
index 7bf4548858..343f9d77b7 100644
@@ -508,13 +508,14 @@ eal_log_init(const char *id)
 {
 	FILE *logf = NULL;
 
-	if (log_syslog_enabled())
+	if (log_journal_enabled())
+		logf = log_journal_open(id);
+	else if (log_syslog_enabled())
 		logf = log_syslog_open(id);
 
 	if (logf)
 		rte_openlog_stream(logf);
-
-	if (log_timestamp_enabled())
+	else if (log_timestamp_enabled())
 		rte_logs.print_func = log_print_with_timestamp;
 	else
 		rte_logs.print_func = vfprintf;
lib/log/log_internal.h +3 -0
index 8ef195a6ec..731c099984 100644
@@ -35,6 +35,9 @@ int eal_log_save_pattern(const char *pattern, uint32_t level);
 __rte_internal
 int eal_log_syslog(const char *name);
 
+__rte_internal
+int eal_log_journal(const char *opt);
+
 /*
  * Convert log level to string.
  */
lib/log/log_journal.c new file +154 -0

154 lines not on this page · raw message

lib/log/log_private.h +14 -0
index 86eaf3f910..37895949f6 100644
@@ -22,6 +22,20 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+#ifdef RTE_EXEC_ENV_LINUX
+bool log_journal_enabled(void);
+FILE *log_journal_open(const char *id);
+#else
+static inline bool log_journal_enabled(void)
+{
+	return false;
+}
+static inline FILE *log_journal_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#endif /* !RTE_EXEC_ENV_LINUX */
+
 bool log_timestamp_enabled(void);
 ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 
lib/log/log_syslog.c +9 -0
index 7d29e3a00f..c23b19fe89 100644
@@ -18,6 +18,10 @@
 
 static int log_facility;
 
+/*
+ * Usable list of facilities
+ * Skip kern, mark, and security
+ */
 static const struct {
 	const char *name;
 	int value;
@@ -48,6 +52,11 @@ eal_log_syslog(const char *name)
 {
 	unsigned int i;
 
+	if (name == NULL) {
+		log_facility = LOG_DAEMON;
+		return 0;
+	}
+
 	for (i = 0; i < RTE_DIM(facilitys); i++) {
 		if (!strcmp(name, facilitys[i].name)) {
 			log_facility = facilitys[i].value;
lib/log/meson.build +4 -0
index 4ac232786e..86e4452b19 100644
@@ -11,4 +11,8 @@ if not is_windows
     sources += files('log_syslog.c')
 endif
 
+if is_linux
+    sources += files('log_journal.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -0
index 8be6907840..800d3943bc 100644
@@ -26,6 +26,7 @@ INTERNAL {
 	global:
 
 	eal_log_init;
+	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
Signature · 1 line
2.45.2
#413 lore raw

Re: [PATCH v28 11/13] log: add support for systemd journal

Can we have an option to disable journal auto-detection?
In my case I want to redirect the DPDK to our own tracing infrastructure and for that I use the fopencookie myself and redirect it to our own system. The journal will force it out and I'll need to ensure that the environment variable is not set, which is doable but I'd rather not need to mess with the environment and just set a flag in dpdk options to disable the journal.

Quoted 306 lines · Stephen Hemminger

If DPDK application is being run as a systemd service, then it can use the journal protocol which allows putting more information in the log such as priority and other information.

The use of journal protocol is automatically detected and handled. Rather than having a dependency on libsystemd, just use the protocol directly as defined in:

https://url.avanan.click/v2/r01/___https://systemd.io/JOURNAL_NATIVE_PROTOCOL/___.YXAzOndla2E6YTpnOjc1MmU1YTVhODIzMWJiMTdkNTBhNzE4MDVhNDc2MTBhOjc6MTNlMjpkODkwMzM0ZTExZTQyZTBmZDY2NmI4YmRjMzY1Nzk1NTJlZjYyMWI0MjE1MjYyOTU4MTg3YjE3YjA1Y2NjMDA4OnA6VDpO

---
 lib/log/log.c          |   7 +-
 lib/log/log_internal.h |   3 +
 lib/log/log_journal.c  | 154 +++++++++++++++++++++++++++++++++++++++++
 lib/log/log_private.h  |  14 ++++
 lib/log/log_syslog.c   |   9 +++
 lib/log/meson.build    |   4 ++
 lib/log/version.map    |   1 +
 7 files changed, 189 insertions(+), 3 deletions(-)
 create mode 100644 lib/log/log_journal.c
lib/log/log.c +4 -3
index 7bf4548858..343f9d77b7 100644
@@ -508,13 +508,14 @@ eal_log_init(const char *id)
 {
        FILE *logf = NULL;
 
-       if (log_syslog_enabled())
+       if (log_journal_enabled())
+               logf = log_journal_open(id);
+       else if (log_syslog_enabled())
                logf = log_syslog_open(id);
 
        if (logf)
                rte_openlog_stream(logf);
-
-       if (log_timestamp_enabled())
+       else if (log_timestamp_enabled())
                rte_logs.print_func = log_print_with_timestamp;
        else
                rte_logs.print_func = vfprintf;
lib/log/log_internal.h +3 -0
index 8ef195a6ec..731c099984 100644
@@ -35,6 +35,9 @@ int eal_log_save_pattern(const char *pattern, uint32_t
 level);
 __rte_internal
 int eal_log_syslog(const char *name);
 
+__rte_internal
+int eal_log_journal(const char *opt);
+
 /*
  * Convert log level to string.

*/

lib/log/log_journal.c new file +23 -0
new file mode 100644
index 0000000000..43341aa233
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+
+#include "log_internal.h"
+#include "log_private.h"
+
+/*
+ * Send structured message using journal protocol
+ * See:

https://url.avanan.click/v2/r01/___https://systemd.io/JOURNAL_NATIVE_PROTOCOL/___.YXAzOndla2E6YTpnOjc1MmU1YTVhODIzMWJiMTdkNTBhNzE4MDVhNDc2MTBhOjc6NTQxZDoyMWQ3NGFjZGMwYWE0M2RhZTM4OTc0ZmJjNGY1NzFkZTFlNTZmMTEwM2I3ZDNhN2U3ZDkxNzFmZjg4ODU3NGQxOnA6VDpO
+ *
+ * Uses writev() to ensure that whole log message is in one datagram
+ */

lib/log/log_journal.c new file +58 -0
+static int
+journal_send(int fd, const char *buf, size_t len)
+{
+       struct iovec iov[4];
+       unsigned int n = 0;
+       int priority = rte_log_cur_msg_loglevel() - 1;
+       char msg[] = "MESSAGE=";
+       char newline = '\n';
+       char pbuf[32];  /* "PRIORITY=N\n" */
+
+       iov[n].iov_base = msg;
+       iov[n++].iov_len = strlen(msg);
+
+       iov[n].iov_base = (char *)(uintptr_t)buf;
+       iov[n++].iov_len = len;
+
+       /* if message doesn't end with newline, one will be applied. */
+       if (buf[len - 1] != '\n') {
+               iov[n].iov_base = &newline;
+               iov[n++].iov_len = 1;
+       }
+
+       /* priority value between 0 ("emerg") and 7 ("debug") */
+       iov[n].iov_base = pbuf;
+       iov[n++].iov_len = snprintf(pbuf, sizeof(pbuf),
+                                   "PRIORITY=%d\n", priority);
+       return writev(fd, iov, n);
+}
+
+
+/* wrapper for log stream to put messages into journal */
+static ssize_t
+journal_log_write(void *c, const char *buf, size_t size)
+{
+       int fd = (uintptr_t)c;
+
+       return journal_send(fd, buf, size);
+}
+
+static int
+journal_log_close(void *c)
+{
+       int fd = (uintptr_t)c;
+
+       close(fd);
+       return 0;
+}
+
+static cookie_io_functions_t journal_log_func = {
+       .write = journal_log_write,
+       .close = journal_log_close,
+};
+
+/*
+ * Check if stderr is going to system journal.
+ * This is the documented way to handle systemd journal
+ *
+ * See:

https://url.avanan.click/v2/r01/___https://systemd.io/JOURNAL_NATIVE_PROTOCOL/___.YXAzOndla2E6YTpnOjc1MmU1YTVhODIzMWJiMTdkNTBhNzE4MDVhNDc2MTBhOjc6NjA4MzpiZGFiZDNiOGRhZDVhMDBkOGI1N2NmZTBjYjUyYjYzNmY5NTU3NGMyZjVmOTk2MTA4YjQxNzMxNDBmNzZhYWE4OnA6VDpO
+ */

lib/log/log_journal.c new file +38 -0
+bool
+log_journal_enabled(void)
+{
+       char *jenv, *endp = NULL;
+       struct stat st;
+       unsigned long dev, ino;
+
+       jenv = getenv("JOURNAL_STREAM");
+       if (jenv == NULL)
+               return false;
+
+       if (fstat(STDERR_FILENO, &st) < 0)
+               return false;
+
+       /* systemd sets colon-separated list of device and inode number */
+       dev = strtoul(jenv, &endp, 10);
+       if (endp == NULL || *endp != ':')
+               return false;   /* missing colon */
+
+       ino = strtoul(endp + 1, NULL, 10);
+
+       return dev == st.st_dev && ino == st.st_ino;
+}
+
+/* Connect to systemd's journal service */
+FILE *log_journal_open(const char *id)
+{
+       char syslog_id[PATH_MAX];
+       FILE *log_stream;
+       int len;
+       struct sockaddr_un sun = {
+               .sun_family = AF_UNIX,
+               .sun_path = "/run/systemd/journal/socket",
+       };
+       int jfd = -1;
+
+       len = snprintf(syslog_id, sizeof(syslog_id),
+                      "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", id,

getpid());

lib/log/log_journal.c new file +24 -0
+
+       /* Detect truncation of message and fallback to no journal */
+       if (len >= (int)sizeof(syslog_id))
+               return NULL;
+
+       jfd = socket(AF_UNIX, SOCK_DGRAM, 0);
+       if (jfd < 0) {
+               perror("socket");
+               goto error;
+       }
+
+       if (connect(jfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
+               perror("connect");
+               goto error;
+       }
+
+       /* Send identifier as first message */
+       if (write(jfd, syslog_id, len) != len) {
+               perror("write");
+               goto error;
+       }
+
+       /* redirect other log messages to journal */
+       log_stream = fopencookie((void *)(uintptr_t)jfd, "w",

journal_log_func);

lib/log/log_journal.c new file +7 -0
+       if (log_stream != NULL)
+               return log_stream;
+
+error:
+       close(jfd);
+       return NULL;
+}
lib/log/log_private.h +14 -0
index 86eaf3f910..37895949f6 100644
@@ -22,6 +22,20 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+#ifdef RTE_EXEC_ENV_LINUX
+bool log_journal_enabled(void);
+FILE *log_journal_open(const char *id);
+#else
+static inline bool log_journal_enabled(void)
+{
+       return false;
+}
+static inline FILE *log_journal_open(const char *id __rte_unused)
+{
+       return NULL;
+}
+#endif /* !RTE_EXEC_ENV_LINUX */
+
 bool log_timestamp_enabled(void);
 ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 
lib/log/log_syslog.c +9 -0
index 7d29e3a00f..c23b19fe89 100644
@@ -18,6 +18,10 @@
 
 static int log_facility;
 
+/*
+ * Usable list of facilities
+ * Skip kern, mark, and security
+ */
 static const struct {
        const char *name;
        int value;
@@ -48,6 +52,11 @@ eal_log_syslog(const char *name)
 {
        unsigned int i;
 
+       if (name == NULL) {
+               log_facility = LOG_DAEMON;
+               return 0;
+       }
+
        for (i = 0; i < RTE_DIM(facilitys); i++) {
                if (!strcmp(name, facilitys[i].name)) {
                        log_facility = facilitys[i].value;
lib/log/meson.build +4 -0
index 4ac232786e..86e4452b19 100644
@@ -11,4 +11,8 @@ if not is_windows
     sources += files('log_syslog.c')
 endif
 
+if is_linux
+    sources += files('log_journal.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -1
index 8be6907840..800d3943bc 100644
@@ -26,6 +26,7 @@ INTERNAL {
        global:
 
        eal_log_init;
+       eal_log_journal; # WINDOWS_NO_EXPORT
        eal_log_level2str;
        eal_log_save_pattern;
        eal_log_save_regexp;
--

2.45.2

Signature · 6 lines
Baruch Even
Platform Technical Lead at WEKA
E [email protected]* ­*W https://www.weka.io* ­*

[image: App Banner Image]
<https://www.weka.io/trends-in-AI-emsig?utm_campaign=signature&utm_source=WiseStamp&utm_medium=email>
#414 lore raw

Re: [PATCH v28 11/13] log: add support for systemd journal

Quoted 8 lines · On Fri, 25 Oct 2024 18:33:40 +0300 Baruch Even <[email protected]> wrote:

Can we have an option to disable journal auto-detection?
In my case I want to redirect the DPDK to our own tracing infrastructure and for that I use the fopencookie myself and redirect it to our own system. The journal will force it out and I'll need to ensure that the environment variable is not set, which is doable but I'd rather not need to mess with the environment and just set a flag in dpdk options to disable the journal.

The detection works on stderr being associated with a specific device that is passed in by environment variable. Only systemd service is going to get this. If you wanted to override, either change the service file.

If you redirect the with rte_openlog_stream() that should already override the stderr. Stuff, probably need to add a check for that.

#415 lore raw

PATCH v28 12/13 log: colorize log output

In reply to Stephen Hemminger

Like dmesg, colorize the log output (unless redirected to file). Timestamp is green, the subsystem is in yellow and the message is red if urgent, boldface if an error, and normal for info and debug messages.

The default is to not use color since it may disturb automatic tests and other embedded usage.

---
 app/test/test_eal_flags.c           |  24 ++++
 doc/guides/prog_guide/log_lib.rst   |  24 ++++
 lib/eal/common/eal_common_options.c |  11 ++
 lib/eal/common/eal_options.h        |   2 +
 lib/log/log.c                       |  20 ++-
 lib/log/log_color.c                 | 214 ++++++++++++++++++++++++++++
 lib/log/log_internal.h              |   5 +
 lib/log/log_private.h               |   8 ++
 lib/log/meson.build                 |   1 +
 lib/log/version.map                 |   1 +
 10 files changed, 306 insertions(+), 4 deletions(-)
 create mode 100644 lib/log/log_color.c
app/test/test_eal_flags.c +24 -0
index e24630edde..cd73711da6 100644
@@ -1067,6 +1067,18 @@ test_misc_flags(void)
 	const char * const argv25[] = {prgname, prefix, mp_flag,
 				       "--log-timestamp=invalid" };
 
+	/* Try running with --log-color */
+	const char * const argv26[] = {prgname, prefix, mp_flag,
+				       "--log-color" };
+
+	/* Try running with --log-color=never */
+	const char * const argv27[] = {prgname, prefix, mp_flag,
+				       "--log-color=never" };
+
+	/* Try running with --log-color=invalid */
+	const char * const argv28[] = {prgname, prefix, mp_flag,
+				       "--log-color=invalid" };
+
 
 	/* run all tests also applicable to FreeBSD first */
 
@@ -1187,6 +1199,18 @@ test_misc_flags(void)
 		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv26) != 0) {
+		printf("Error - process did not run ok with --log-color parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv27) != 0) {
+		printf("Error - process did not run ok with --log-color=none parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv28) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
 
 
 	rmdir(hugepath_dir3);
doc/guides/prog_guide/log_lib.rst +24 -0
index 82d3b7be2b..a4f880037b 100644
@@ -57,6 +57,7 @@ For example::
 
 Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.
 
+
 Using Logging APIs to Generate Log Messages
 -------------------------------------------
 
@@ -137,3 +138,26 @@ To prefix all console messages with ISO format time the syntax is::
 
    Timestamp option has no effect if using syslog because the ``syslog()``
    service already does timestamping internally.
+
+
+Color output
+~~~~~~~~~~~~
+
+The log library will highlight important messages.
+This is controlled by the ``--log-color`` option.
+The optional argument describes when color is enabled:
+
+:never: Do not enable color. This is the default behavior.
+
+:auto: Enable color only when printing to a terminal.
+       This is the same as ``--log-color`` with no argument
+
+:always: Always print color
+
+For example to enable color in logs if using terminal::
+
+	/path/to/app --log-color
+
+.. note::
+
+   Color output is never used for syslog or systemd journal logging.
lib/eal/common/eal_common_options.c +11 -0
index a70d63479a..6965666a7c 100644
@@ -73,6 +73,7 @@ eal_long_options[] = {
 	{OPT_HUGE_UNLINK,       2, NULL, OPT_HUGE_UNLINK_NUM      },
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
+	{OPT_LOG_COLOR,		2, NULL, OPT_LOG_COLOR_NUM	  },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
 	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
@@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[])
 		case OPT_LOG_LEVEL_NUM:
 		case OPT_SYSLOG_NUM:
 		case OPT_LOG_TIMESTAMP_NUM:
+		case OPT_LOG_COLOR_NUM:
 			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
 				return -1;
 			break;
@@ -1859,6 +1861,14 @@ eal_parse_common_option(int opt, const char *optarg,
 		}
 		break;
 
+	case OPT_LOG_COLOR_NUM:
+		if (eal_log_color(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_COLOR);
+			return -1;
+		}
+		break;
+
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
 		if (eal_trace_args_save(optarg) < 0) {
@@ -2225,6 +2235,7 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
 	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
+	       "  --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index e24c9eca53..87c3c32f86 100644
@@ -33,6 +33,8 @@ enum {
 	OPT_HUGE_UNLINK_NUM,
 #define OPT_LCORES            "lcores"
 	OPT_LCORES_NUM,
+#define OPT_LOG_COLOR	      "log-color"
+	OPT_LOG_COLOR_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
 #define OPT_LOG_TIMESTAMP     "log-timestamp"
lib/log/log.c +16 -4
index 343f9d77b7..f1bd408bee 100644
@@ -515,10 +515,22 @@ eal_log_init(const char *id)
 
 	if (logf)
 		rte_openlog_stream(logf);
-	else if (log_timestamp_enabled())
-		rte_logs.print_func = log_print_with_timestamp;
-	else
-		rte_logs.print_func = vfprintf;
+	else {
+		bool is_terminal = isatty(fileno(stderr));
+		bool use_color = log_color_enabled(is_terminal);
+
+		if (log_timestamp_enabled()) {
+			if (use_color)
+				rte_logs.print_func = color_print_with_timestamp;
+			else
+				rte_logs.print_func = log_print_with_timestamp;
+		} else {
+			if (use_color)
+				rte_logs.print_func = color_print;
+			else
+				rte_logs.print_func = vfprintf;
+		}
+	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
lib/log/log_color.c new file +214 -0

214 lines not on this page · raw message

lib/log/log_internal.h +5 -0
index 731c099984..00dde59211 100644
@@ -56,5 +56,10 @@ void rte_eal_log_cleanup(void);
 __rte_internal
 int eal_log_timestamp(const char *fmt);
 
+/*
+ * Enable or disable color in log messages
+ */
+__rte_internal
+int eal_log_color(const char *mode);
 
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +8 -0
index 37895949f6..5755cbf71f 100644
@@ -42,4 +42,12 @@ ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 __rte_format_printf(2, 0)
 int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
 
+bool log_color_enabled(bool is_tty);
+
+__rte_format_printf(2, 0)
+int color_print(FILE *f, const char *format, va_list ap);
+
+__rte_format_printf(2, 0)
+int color_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/meson.build +1 -0
index 86e4452b19..b3de57b9c7 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_color.c',
         'log_timestamp.c',
 )
 
lib/log/version.map +1 -0
index 800d3943bc..09d8a4289b 100644
@@ -25,6 +25,7 @@ DPDK_25 {
 INTERNAL {
 	global:
 
+	eal_log_color;
 	eal_log_init;
 	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
Signature · 1 line
2.45.2
#416 lore raw

PATCH v28 13/13 doc: add release note about log library

In reply to Stephen Hemminger

Significant enough to add some documentation.

---
 doc/guides/rel_notes/release_24_11.rst | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
doc/guides/rel_notes/release_24_11.rst +19 -0
index fa4822d928..ec4b7ba2a4 100644
@@ -349,6 +349,25 @@ API Changes
   and replaced it with a new shared devarg ``llq_policy`` that keeps the same logic.
 
 
+* **Logging library changes**
+
+  * The log is initialized earlier in startup so all messages go through the library.
+
+  * Added a new option to timestamp log messages, which is useful for
+    debugging delays in application and driver startup.
+
+  * Syslog option change. If *--syslog* is specified, then messages
+    will go to syslog; if not specified then messages will only be displayed
+    on stderr. This option is now supported on FreeBSD (but not on Windows).
+
+  * If the application is a systemd service and the log output is being
+    sent of standard error then DPDK will switch to journal native protocol.
+
+  * Log messages can be timestamped with *--log-timestamp* option.
+
+  * Log messages can be colorized with the *--log-color* option.
+
+
 ABI Changes
 -----------
 
Signature · 1 line
2.45.2
#417 lore raw

v29 cover Logging subsystem enhancements

In reply to Stephen Hemminger

Improvements and unification of logging library.
This version works on all platforms: Linux, Windows and FreeBSD.

This is update to rework patch set. It adds several new features to the console log output.

* Putting a timestamp on console output which is useful for analyzing performance of startup codes. Timestamp is optional and must be enabled on command line.

* Displaying console output with colors.
It uses the standard conventions used by many other Linux commands for colorized display. The default is to enable color if the console output is going to a terminal. But it can be always on or disabled by command line flag. This default was chosen based on what dmesg(1) command does.

Color is used by many tools (vi, iproute2, git) because it is helpful; DPDK drivers and libraries print lots of not very useful messages. And having error messages highlighted in bold face helps. This might also get users to pay more attention to error messages. Many bug reports have earlier messages that are lost because there are so many info messages.

* Add support for automatic detection of systemd journal protocol. If running as systemd service will get enhanced logging.

* Use of syslog is optional and the meaning of the --syslog flag has changed. The default is *not* to use unless requested.

Add myself as maintainer for log because by now have added more than previous authors.

v29 - address review feedback and change wording of release note
If a log stream is set with rte_open_log_stream() then none of the other stuff happens (syslog, journal, timestamp, or color)

Stephen Hemminger (13):
maintainers: add for log library
windows: make getopt functions have const properties
windows: update os shim
eal: make eal_log_level_parse common
eal: do not duplicate rte_init_alert() messages
eal: change rte_exit() output to match rte_log()
log: rework syslog handling
eal: initialize log before everything else
log: add hook for printing log messages
log: add timestamp option
log: add support for systemd journal
log: colorize log output
doc: add release note about log library

 MAINTAINERS                                   |   1 +
 app/test/test_eal_flags.c                     |  66 ++++-
 .../freebsd_gsg/freebsd_eal_parameters.rst    |  27 ++
 .../prog_guide/env_abstraction_layer.rst      |   6 +-
 doc/guides/prog_guide/log_lib.rst             |  57 ++++-
 doc/guides/rel_notes/release_24_11.rst        |  20 ++
 lib/eal/common/eal_common_debug.c             |   6 +-
 lib/eal/common/eal_common_options.c           | 122 +++++----
 lib/eal/common/eal_internal_cfg.h             |   1 -
 lib/eal/common/eal_options.h                  |   5 +
 lib/eal/freebsd/eal.c                         |  65 ++---
 lib/eal/linux/eal.c                           |  68 +----
 lib/eal/windows/eal.c                         |  50 +---
 lib/eal/windows/getopt.c                      |  23 +-
 lib/eal/windows/include/getopt.h              |   8 +-
 lib/eal/windows/include/rte_os_shim.h         |  10 +
 lib/log/log.c                                 |  83 ++++--
 lib/log/log_color.c                           | 214 ++++++++++++++++
 lib/log/log_freebsd.c                         |  12 -
 lib/log/log_internal.h                        |  22 +-
 lib/log/log_journal.c                         | 152 +++++++++++
 lib/log/log_linux.c                           |  61 -----
 lib/log/log_private.h                         |  53 ++++
 lib/log/log_syslog.c                          | 108 ++++++++
 lib/log/log_timestamp.c                       | 240 ++++++++++++++++++
 lib/log/log_windows.c                         |  18 --
 lib/log/meson.build                           |  12 +-
 lib/log/version.map                           |   5 +-
 28 files changed, 1163 insertions(+), 352 deletions(-)
 create mode 100644 lib/log/log_color.c
 delete mode 100644 lib/log/log_freebsd.c
 create mode 100644 lib/log/log_journal.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 create mode 100644 lib/log/log_timestamp.c
 delete mode 100644 lib/log/log_windows.c
Signature · 1 line
2.45.2
#418 lore raw

PATCH v29 1/13 maintainers: add for log library

"You touch it you own it"
Add myself as maintainer for log library.

---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)
MAINTAINERS +1 -0
index cd78bc7db1..a504b8fc54 100644
@@ -186,6 +186,7 @@ F: app/test/test_threads.c
 F: app/test/test_version.c
 
 Logging
+M: Stephen Hemminger <[email protected]>
 F: lib/log/
 F: doc/guides/prog_guide/log_lib.rst
 F: app/test/test_logs.c
Signature · 1 line
2.45.2
#419 lore raw

PATCH v29 2/13 windows: make getopt functions have const properties

In reply to Stephen Hemminger

Having different prototypes on different platforms can lead to lots of unnecessary workarounds. Looks like the version of getopt used from windows was based on an older out of date version from FreeBSD.

This patch changes getopt, getopt_long, etc to have the same const attributes as Linux and FreeBSD. The changes are derived from the current FreeBSD version of getopt_long.

---
 lib/eal/windows/getopt.c         | 23 ++++++++++++-----------
 lib/eal/windows/include/getopt.h |  8 ++++----
 2 files changed, 16 insertions(+), 15 deletions(-)
lib/eal/windows/getopt.c +12 -11
index a1f51c6c23..50ff71b930 100644
@@ -20,7 +20,7 @@
 #include <string.h>
 #include <stdlib.h>
 
-const char    *optarg;		/* argument associated with option */
+char    *optarg;		/* argument associated with option */
 int	opterr = 1;		/* if error message should be printed */
 int	optind = 1;		/* index into parent argv vector */
 int	optopt = '?';		/* character checked for validity */
@@ -39,9 +39,9 @@ static void pass(const char *a) {(void) a; }
 #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
 #define	INORDER		1
 
-#define	EMSG		""
+static char EMSG[] = "";
 
-static const char *place = EMSG; /* option letter processing */
+static char *place = EMSG; /* option letter processing */
 
 /* XXX: set optreset to 1 rather than these two */
 static int nonopt_start = -1; /* first non option argument (for permute) */
@@ -80,7 +80,7 @@ gcd(int a, int b)
  */
 static void
 permute_args(int panonopt_start, int panonopt_end, int opt_end,
-	char **nargv)
+	char * const *nargv)
 {
 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
 	char *swap;
@@ -101,11 +101,12 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
 				pos -= nnonopts;
 			else
 				pos += nopts;
+
 			swap = nargv[pos];
 			/* LINTED const cast */
-			((char **) nargv)[pos] = nargv[cstart];
+			((char **)(uintptr_t)nargv)[pos] = nargv[cstart];
 			/* LINTED const cast */
-			((char **)nargv)[cstart] = swap;
+			((char **)(uintptr_t)nargv)[cstart] = swap;
 		}
 	}
 }
@@ -116,7 +117,7 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
  * Returns -1 if short_too is set and the option does not match long_options.
  */
 static int
-parse_long_options(char **nargv, const char *options,
+parse_long_options(char * const *nargv, const char *options,
 	const struct option *long_options, int *idx, int short_too)
 {
 	const char *current_argv;
@@ -236,7 +237,7 @@ parse_long_options(char **nargv, const char *options,
  *	Parse argc/argv argument vector.  Called by user level routines.
  */
 static int
-getopt_internal(int nargc, char **nargv, const char *options,
+getopt_internal(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx, int flags)
 {
 	char *oli;				/* option letter list index */
@@ -434,7 +435,7 @@ getopt_internal(int nargc, char **nargv, const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt(int nargc, char *nargv[], const char *options)
+getopt(int nargc, char *const nargv[], const char *options)
 {
 	return getopt_internal(nargc, nargv, options, NULL, NULL,
 			       FLAG_PERMUTE);
@@ -445,7 +446,7 @@ getopt(int nargc, char *nargv[], const char *options)
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long(int nargc, char *nargv[], const char *options,
+getopt_long(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
@@ -458,7 +459,7 @@ getopt_long(int nargc, char *nargv[], const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long_only(int nargc, char *nargv[], const char *options,
+getopt_long_only(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
lib/eal/windows/include/getopt.h +4 -4
index 6f57af454b..e4cf6873cb 100644
@@ -44,7 +44,7 @@
 
 
 /** argument to current option, or NULL if it has none */
-extern const char *optarg;
+extern char *optarg;
 /** Current position in arg string.  Starts from 1.
  * Setting to 0 resets state.
  */
@@ -80,14 +80,14 @@ struct option {
 };
 
 /** Compat: getopt */
-int getopt(int argc, char *argv[], const char *options);
+int getopt(int argc, char *const argv[], const char *options);
 
 /** Compat: getopt_long */
-int getopt_long(int argc, char *argv[], const char *options,
+int getopt_long(int argc, char *const argv[], const char *options,
 		const struct option *longopts, int *longindex);
 
 /** Compat: getopt_long_only */
-int getopt_long_only(int nargc, char *argv[], const char *options,
+int getopt_long_only(int nargc, char *const argv[], const char *options,
 		     const struct option *long_options, int *idx);
 
 
Signature · 1 line
2.45.2
#420 lore raw

PATCH v29 3/13 windows: update os shim

In reply to Stephen Hemminger

Windows does not have localtime_r but it does have a similar function that can be used instead.

Use rte_os_shim.h in lib/log instead of redefine of strdup.

---
 lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++
 lib/log/log.c                         |  7 +++----
 2 files changed, 13 insertions(+), 4 deletions(-)
lib/eal/windows/include/rte_os_shim.h +10 -0
index eda8113662..665c9ac93b 100644
@@ -110,4 +110,14 @@ rte_clock_gettime(clockid_t clock_id, struct timespec *tp)
 }
 #define clock_gettime(clock_id, tp) rte_clock_gettime(clock_id, tp)
 
+static inline struct tm *
+rte_localtime_r(const time_t *timep, struct tm *result)
+{
+	if (localtime_s(result, timep) == 0)
+		return result;
+	else
+		return NULL;
+}
+#define localtime_r(timep, result) rte_localtime_r(timep, result)
+
 #endif /* _RTE_OS_SHIM_ */
lib/log/log.c +3 -4
index 255f757d94..7416c82b34 100644
@@ -14,13 +14,12 @@
 
 #include <rte_log.h>
 #include <rte_per_lcore.h>
-
-#include "log_internal.h"
-
 #ifdef RTE_EXEC_ENV_WINDOWS
-#define strdup _strdup
+#include <rte_os_shim.h>
 #endif
 
+#include "log_internal.h"
+
 struct rte_log_dynamic_type {
 	const char *name;
 	uint32_t loglevel;
Signature · 1 line
2.45.2
#421 lore raw

PATCH v29 4/13 eal: make eal_log_level_parse common

In reply to Stephen Hemminger

The code to parse for log-level option should be same on all OS variants.

---
 lib/eal/common/eal_common_options.c | 40 +++++++++++++++++++++++++++
 lib/eal/common/eal_options.h        |  1 +
 lib/eal/freebsd/eal.c               | 42 -----------------------------
 lib/eal/linux/eal.c                 | 39 ---------------------------
 lib/eal/windows/eal.c               | 35 ------------------------
 5 files changed, 41 insertions(+), 116 deletions(-)
lib/eal/common/eal_common_options.c +40 -0
index f1a5e329a5..eb079a65a9 100644
@@ -1640,6 +1640,46 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
 	return -1;
 }
 
+/* Parse the all arguments looking for log related ones */
+int
+eal_log_level_parse(int argc, char * const argv[])
+{
+	struct internal_config *internal_conf = eal_get_internal_configuration();
+	int option_index, opt;
+	const int old_optind = optind;
+	const int old_optopt = optopt;
+	const int old_opterr = opterr;
+	char *old_optarg = optarg;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	const int old_optreset = optreset;
+	optreset = 1;
+#endif
+
+	optind = 1;
+	opterr = 0;
+
+	while ((opt = getopt_long(argc, argv, eal_short_options,
+				  eal_long_options, &option_index)) != EOF) {
+
+		switch (opt) {
+		case OPT_LOG_LEVEL_NUM:
+			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+				return -1;
+			break;
+		}
+	}
+
+	/* restore getopt lib */
+	optind = old_optind;
+	optopt = old_optopt;
+	optarg = old_optarg;
+	opterr = old_opterr;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	optreset = old_optreset;
+#endif
+	return 0;
+}
+
 int
 eal_parse_common_option(int opt, const char *optarg,
 			struct internal_config *conf)
lib/eal/common/eal_options.h +1 -0
index 3cc9cb6412..f3f2e104f6 100644
@@ -96,6 +96,7 @@ enum {
 extern const char eal_short_options[];
 extern const struct option eal_long_options[];
 
+int eal_log_level_parse(int argc, char * const argv[]);
 int eal_parse_common_option(int opt, const char *argv,
 			    struct internal_config *conf);
 int eal_option_device_parse(void);
lib/eal/freebsd/eal.c +0 -42

48 lines not on this page · raw message

lib/eal/linux/eal.c +0 -39
index 54577b7718..40d750ed0d 100644
@@ -546,45 +546,6 @@ eal_parse_vfio_vf_token(const char *vf_token)
 	return -1;
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	const int old_optind = optind;
-	const int old_optopt = optopt;
-	char * const old_optarg = optarg;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-	optind = 1;
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-				  eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg, internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	/* restore getopt lib */
-	optind = old_optind;
-	optopt = old_optopt;
-	optarg = old_optarg;
-}
-
 static int
 eal_parse_huge_worker_stack(const char *arg)
 {
lib/eal/windows/eal.c +0 -35
index 28b78a95a6..a77e590a72 100644
@@ -96,41 +96,6 @@ eal_usage(const char *prgname)
 	}
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-
-	eal_reset_internal_config(internal_conf);
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-		eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg,
-				internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	optind = 0; /* reset getopt lib */
-}
-
 /* Parse the argument given in the command line of the application */
 static int
 eal_parse_args(int argc, char **argv)
Signature · 1 line
2.45.2
#422 lore raw

PATCH v29 5/13 eal: do not duplicate rte_init_alert() messages

In reply to Stephen Hemminger

The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name.

---
 lib/eal/freebsd/eal.c | 3 +--
 lib/eal/linux/eal.c   | 3 +--
 lib/eal/windows/eal.c | 1 -
 3 files changed, 2 insertions(+), 5 deletions(-)
lib/eal/freebsd/eal.c +1 -2
index d3b40e81d8..7b974608e4 100644
@@ -529,8 +529,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /* Launch threads, called at application init(). */
lib/eal/linux/eal.c +1 -2
index 40d750ed0d..c53a051405 100644
@@ -830,8 +830,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /*
lib/eal/windows/eal.c +0 -1
index a77e590a72..93f099a968 100644
@@ -181,7 +181,6 @@ sync_func(void *arg __rte_unused)
 static void
 rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
 	EAL_LOG(ERR, "%s", msg);
 }
 
Signature · 1 line
2.45.2
#423 lore raw

PATCH v29 6/13 eal: change rte_exit() output to match rte_log()

In reply to Stephen Hemminger

The rte_exit() output format confuses the timestamp and coloring options. Change it to use be a single line with proper prefix.

Before:

[     0.006481] EAL: Error - exiting with code: 1
  Cause: [     0.006489] Cannot init EAL: Permission denied

After:

[     0.006238] EAL: Error - exiting with code: 1
[     0.006250] EAL: Cannot init EAL: Permission denied
---
 lib/eal/common/eal_common_debug.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
lib/eal/common/eal_common_debug.c +2 -4
index 3e77995896..bcfcd6df6f 100644
@@ -36,15 +36,13 @@ rte_exit(int exit_code, const char *format, ...)
 	va_list ap;
 
 	if (exit_code != 0)
-		RTE_LOG(CRIT, EAL, "Error - exiting with code: %d\n"
-				"  Cause: ", exit_code);
+		EAL_LOG(CRIT, "Error - exiting with code: %d", exit_code);
 
 	va_start(ap, format);
 	rte_vlog(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, format, ap);
 	va_end(ap);
 
 	if (rte_eal_cleanup() != 0 && rte_errno != EALREADY)
-		EAL_LOG(CRIT,
-			"EAL could not release all resources");
+		EAL_LOG(CRIT, "EAL could not release all resources");
 	exit(exit_code);
 }
Signature · 1 line
2.45.2
#424 lore raw

PATCH v29 7/13 log: rework syslog handling

In reply to Stephen Hemminger

Refactor how syslog is handled, make it common to Linux and FreeBSD The syslog facility property is better handled in lib/log rather than in eal. This also add syslog support to FreeBSD.

Log to syslog only if option is specified.
If no --syslog is given then use console only.

---
 app/test/test_eal_flags.c                     | 16 +--
 .../freebsd_gsg/freebsd_eal_parameters.rst    | 27 +++++
 .../prog_guide/env_abstraction_layer.rst      |  6 +-
 doc/guides/prog_guide/log_lib.rst             |  5 +-
 lib/eal/common/eal_common_options.c           | 57 ++---------
 lib/eal/common/eal_internal_cfg.h             |  1 -
 lib/eal/freebsd/eal.c                         |  5 +-
 lib/eal/linux/eal.c                           | 12 +--
 lib/eal/windows/eal.c                         |  6 +-
 lib/log/log.c                                 | 44 ++++-----
 lib/log/log_freebsd.c                         | 12 ---
 lib/log/log_internal.h                        | 11 +--
 lib/log/log_linux.c                           | 61 ------------
 lib/log/log_private.h                         | 25 +++++
 lib/log/log_syslog.c                          | 99 +++++++++++++++++++
 lib/log/log_windows.c                         | 18 ----
 lib/log/meson.build                           |  6 +-
 lib/log/version.map                           |  2 +-
 18 files changed, 209 insertions(+), 204 deletions(-)
 delete mode 100644 lib/log/log_freebsd.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 delete mode 100644 lib/log/log_windows.c
app/test/test_eal_flags.c +8 -8
index 71d8dba731..9fcf0d56e6 100644
@@ -985,12 +985,12 @@ test_misc_flags(void)
 	/* With -v */
 	const char *argv2[] = {prgname, prefix, mp_flag, "-v"};
 	/* With valid --syslog */
-	const char *argv3[] = {prgname, prefix, mp_flag,
-			"--syslog", "syslog"};
-	/* With empty --syslog (should fail) */
+	const char *argv3[] = {prgname, prefix, mp_flag, "--syslog=user"};
+	/* With empty --syslog (now defaults) */
 	const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"};
 	/* 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};
@@ -1080,15 +1080,15 @@ test_misc_flags(void)
 #endif
 
 	if (launch_proc(argv3) != 0) {
-		printf("Error - process did not run ok with --syslog flag\n");
+		printf("Error - process did not run ok with --syslog=user flag\n");
 		goto fail;
 	}
-	if (launch_proc(argv4) == 0) {
-		printf("Error - process run ok with empty --syslog flag\n");
+	if (launch_proc(argv4) != 0) {
+		printf("Error - process did not run ok with --syslog flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv5) == 0) {
-		printf("Error - process run ok with invalid --syslog flag\n");
+		printf("Error - process run ok with --syslog=invalid flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv7) != 0) {
doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +27 -0
index fba467a2ce..9270d9fa3b 100644
@@ -18,3 +18,30 @@ FreeBSD-specific EAL parameters
 -------------------------------
 
 There are currently no FreeBSD-specific EAL command-line parameters available.
+
+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
doc/guides/prog_guide/env_abstraction_layer.rst +3 -3
index b9fac1839d..9bafa30a0e 100644
@@ -851,9 +851,9 @@ Signal Safety
   Other functions are not signal safe because they use one or more
   library routines that are not themselves signal safe.
   For example, calling ``rte_panic()`` is not safe in a signal handler
-  because it uses ``rte_log()`` and ``rte_log()`` calls the
-  ``syslog()`` library function which is in the list of
-  signal safe functions in
+  because it uses ``rte_log()`` and ``rte_log()`` may call ``vfprintf()`` or
+  ``syslog()`` library functions which are not in the list of
+  signal safe functions
   `Signal-Safety manual page <https://man7.org/linux/man-pages/man7/signal-safety.7.html>`_.
 
   The set of functions that are expected to be async-signal-safe in DPDK
doc/guides/prog_guide/log_lib.rst +2 -3
index ff9d1b54a2..c87830ac00 100644
@@ -5,9 +5,7 @@ Log Library
 ===========
 
 The DPDK Log library provides the logging functionality for other DPDK libraries and drivers.
-By default, in a Linux application, logs are sent to syslog and also to the console.
-On FreeBSD and Windows applications, logs are sent only to the console.
-However, the log function can be overridden by the user to use a different logging mechanism.
+The messages can be sent to one or more sources controlled by the EAL command line options.
 
 Log Levels
 ----------
@@ -59,6 +57,7 @@ For example::
 
 Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.
 
+
 Using Logging APIs to Generate Log Messages
 -------------------------------------------
 
lib/eal/common/eal_common_options.c +6 -51

99 lines not on this page · raw message

lib/eal/common/eal_internal_cfg.h +0 -1
index 167ec501fa..f53ab8b4aa 100644
@@ -84,7 +84,6 @@ struct internal_config {
 	/**< true if storing all pages within single files (per-page-size,
 	 * per-node) non-legacy mode only.
 	 */
-	volatile int syslog_facility;	  /**< facility passed to openlog() */
 	/** default interrupt mode for VFIO */
 	volatile enum rte_intr_mode vfio_intr_mode;
 	/** the shared VF token for VFIO-PCI bound PF and VFs devices */
lib/eal/freebsd/eal.c +2 -3
index 7b974608e4..a609d40ee0 100644
@@ -11,7 +11,6 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <pthread.h>
-#include <syslog.h>
 #include <getopt.h>
 #include <sys/file.h>
 #include <stddef.h>
@@ -392,8 +391,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_log_level_parse() already handled these */
+		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_LOG_SYSLOG_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/eal/linux/eal.c +3 -9
index c53a051405..0c44d0b6e3 100644
@@ -610,8 +610,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_log_level_parse() already handled these options */
+		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -1103,13 +1103,7 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	if (eal_log_init(program_invocation_short_name,
-			 internal_conf->syslog_facility) < 0) {
-		rte_eal_init_alert("Cannot init logging.");
-		rte_errno = ENOMEM;
-		rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
-		return -1;
-	}
+	eal_log_init(program_invocation_short_name);
 
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
lib/eal/windows/eal.c +3 -3
index 93f099a968..cd8420a82c 100644
@@ -120,8 +120,8 @@ eal_parse_args(int argc, char **argv)
 			return -1;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_log_level_parse() already handled these options */
+		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -249,7 +249,7 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL, 0);
+	eal_log_init(NULL);
 
 	eal_log_level_parse(argc, argv);
 
lib/log/log.c +21 -23

94 lines not on this page · raw message

lib/log/log_freebsd.c deleted +0 -12
deleted file mode 100644
index 698d3c5423..0000000000
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2023 Intel Corporation
- */
-
-#include <rte_common.h>
-#include "log_internal.h"
-
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	return 0;
-}
lib/log/log_internal.h +4 -7
index 451629f1c1..3c46328e7b 100644
@@ -14,13 +14,7 @@
  * Initialize the default log stream.
  */
 __rte_internal
-int eal_log_init(const char *id, int facility);
-
-/*
- * Determine where log data is written when no call to rte_openlog_stream.
- */
-__rte_internal
-void eal_log_set_default(FILE *default_log);
+void eal_log_init(const char *id);
 
 /*
  * Save a log option for later.
@@ -30,6 +24,9 @@ int eal_log_save_regexp(const char *regexp, uint32_t level);
 __rte_internal
 int eal_log_save_pattern(const char *pattern, uint32_t level);
 
+__rte_internal
+int eal_log_syslog(const char *name);
+
 /*
  * Convert log level to string.
  */
lib/log/log_linux.c deleted +0 -61

61 lines not on this page · raw message

lib/log/log_private.h new file +25 -0
new file mode 100644
index 0000000000..bf87b43f7e
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#ifndef LOG_PRIVATE_H
+#define LOG_PRIVATE_H
+
+/* Defined in limits.h on Linux */
+#ifndef LINE_MAX
+#define LINE_MAX	2048 /* _POSIX2_LINE_MAX */
+#endif
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+static inline bool log_syslog_enabled(void)
+{
+	return false;
+}
+static inline FILE *log_syslog_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#else
+bool log_syslog_enabled(void);
+FILE *log_syslog_open(const char *id);
+#endif
+
+#endif /* LOG_PRIVATE_H */
lib/log/log_syslog.c new file +99 -0

99 lines not on this page · raw message

lib/log/log_windows.c deleted +0 -18
deleted file mode 100644
index a6a0889550..0000000000
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2017-2018 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_log.h>
-#include "log_internal.h"
-
-/* set the log to default function, called during eal init process. */
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	rte_openlog_stream(stderr);
-
-	eal_log_set_default(stderr);
-
-	return 0;
-}
lib/log/meson.build +5 -1
index 0d4319b36f..160cf34f50 100644
@@ -4,6 +4,10 @@
 includes += global_inc
 sources = files(
         'log.c',
-        'log_' + exec_env + '.c',
 )
+
+if not is_windows
+    sources += files('log_syslog.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -1
index 19d7f9cdb6..1637fba3b9 100644
@@ -29,6 +29,6 @@ INTERNAL {
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
-	eal_log_set_default;
+	eal_log_syslog; # WINDOWS_NO_EXPORT
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.45.2
#425 lore raw

PATCH v29 8/13 eal: initialize log before everything else

In reply to Stephen Hemminger

In order for all log messages (including CPU mismatch) to come out through the logging library, it must be initialized as early in rte_eal_init() as possible on all platforms.

Where it was done before was likely historical based on the support of non-OS isolated CPU's which required a shared memory buffer; that support was dropped before DPDK was publicly released.

---
 lib/eal/freebsd/eal.c  | 13 ++++++++++---
 lib/eal/linux/eal.c    | 14 +++++++++-----
 lib/eal/windows/eal.c  |  8 ++++++--
 lib/log/log_internal.h |  6 ++++++
 4 files changed, 31 insertions(+), 10 deletions(-)
lib/eal/freebsd/eal.c +10 -3
index a609d40ee0..8631a20eae 100644
@@ -52,6 +52,7 @@
 #include "eal_options.h"
 #include "eal_memcfg.h"
 #include "eal_trace.h"
+#include "log_internal.h"
 
 #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
 
@@ -546,6 +547,15 @@ rte_eal_init(int argc, char **argv)
 	bool has_phys_addr;
 	enum rte_iova_mode iova_mode;
 
+	/* setup log as early as possible */
+	if (eal_log_level_parse(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(getprogname());
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -572,9 +582,6 @@ rte_eal_init(int argc, char **argv)
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
-
 	if (rte_eal_cpu_init() < 0) {
 		rte_eal_init_alert("Cannot detect lcores.");
 		rte_errno = ENOTSUP;
lib/eal/linux/eal.c +9 -5
index 0c44d0b6e3..62d3d281c4 100644
@@ -926,6 +926,15 @@ rte_eal_init(int argc, char **argv)
 	struct internal_config *internal_conf =
 		eal_get_internal_configuration();
 
+	/* setup log as early as possible */
+	if (eal_log_level_parse(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(program_invocation_short_name);
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -949,9 +958,6 @@ rte_eal_init(int argc, char **argv)
 
 	eal_reset_internal_config(internal_conf);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
-
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
@@ -1103,8 +1109,6 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	eal_log_init(program_invocation_short_name);
-
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
 		rte_eal_init_alert("Cannot init VFIO");
lib/eal/windows/eal.c +6 -2
index cd8420a82c..33f044d7cc 100644
@@ -249,9 +249,13 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL);
+	if (eal_log_level_parse(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
 
-	eal_log_level_parse(argc, argv);
+	eal_log_init(NULL);
 
 	if (eal_create_cpu_map() < 0) {
 		rte_eal_init_alert("Cannot discover CPU and NUMA.");
lib/log/log_internal.h +6 -0
index 3c46328e7b..d5fabd7ef7 100644
@@ -16,6 +16,12 @@
 __rte_internal
 void eal_log_init(const char *id);
 
+/*
+ * Determine where log data is written when no call to rte_openlog_stream.
+ */
+__rte_internal
+void eal_log_set_default(FILE *default_log);
+
 /*
  * Save a log option for later.
  */
Signature · 1 line
2.45.2
#426 lore raw

PATCH v29 9/13 log: add hook for printing log messages

In reply to Stephen Hemminger

This is useful for when decorating log output for console or journal. Provide basic version in this patch.

---
 lib/log/log.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
lib/log/log.c +7 -1
index 511ab3b30b..cc0c61cb22 100644
@@ -29,16 +29,21 @@ struct rte_log_dynamic_type {
 	uint32_t loglevel;
 };
 
+/* Note: same as vfprintf() */
+typedef int (*log_print_t)(FILE *f, const char *fmt, 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. */
+	log_print_t print_func;
 	size_t dynamic_types_len;
 	struct rte_log_dynamic_type *dynamic_types;
 } rte_logs = {
 	.type = UINT32_MAX,
 	.level = RTE_LOG_DEBUG,
+	.print_func = vfprintf,
 };
 
 struct rte_eal_opt_loglevel {
@@ -75,6 +80,7 @@ int
 rte_openlog_stream(FILE *f)
 {
 	rte_logs.file = f;
+	rte_logs.print_func = vfprintf;
 	return 0;
 }
 
@@ -471,7 +477,7 @@ rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap)
 	RTE_PER_LCORE(log_cur_msg).loglevel = level;
 	RTE_PER_LCORE(log_cur_msg).logtype = logtype;
 
-	ret = vfprintf(f, format, ap);
+	ret = (*rte_logs.print_func)(f, format, ap);
 	fflush(f);
 	return ret;
 }
Signature · 1 line
2.45.2
#427 lore raw

PATCH v29 10/13 log: add timestamp option

In reply to Stephen Hemminger

When debugging driver or startup issues, it is useful to have a timestamp on each message printed. The messages in syslog already have a timestamp, but often syslog is not available during testing.

There are multiple timestamp formats similar to Linux dmesg. The default is time relative since startup (when first step of logging initialization is done by constructor). Other alternative formats are delta, ctime, reltime and iso formats.

Example:

$ dpdk-testpmd --log-timestamp -- -i
[     0.008610] EAL: Detected CPU lcores: 8
[     0.008634] EAL: Detected NUMA nodes: 1
[     0.008792] EAL: Detected static linkage of DPDK
[     0.010620] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
[     0.012618] EAL: Selected IOVA mode 'VA'
[     0.016675] testpmd: No probed ethernet devices
Interactive-mode selected
---
 app/test/test_eal_flags.c           |  26 +++
 doc/guides/prog_guide/log_lib.rst   |  30 +++-
 lib/eal/common/eal_common_options.c |  14 +-
 lib/eal/common/eal_options.h        |   2 +
 lib/eal/freebsd/eal.c               |   6 +-
 lib/eal/linux/eal.c                 |   4 +-
 lib/eal/windows/eal.c               |   4 +-
 lib/log/log.c                       |   5 +
 lib/log/log_internal.h              |   9 ++
 lib/log/log_private.h               |   6 +
 lib/log/log_timestamp.c             | 240 ++++++++++++++++++++++++++++
 lib/log/meson.build                 |   1 +
 lib/log/version.map                 |   1 +
 13 files changed, 341 insertions(+), 7 deletions(-)
 create mode 100644 lib/log/log_timestamp.c
app/test/test_eal_flags.c +26 -0
index 9fcf0d56e6..e24630edde 100644
@@ -1055,6 +1055,19 @@ test_misc_flags(void)
 	const char * const argv22[] = {prgname, prefix, mp_flag,
 				       "--huge-worker-stack=512"};
 
+	/* Try running with --log-timestamp */
+	const char * const argv23[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp" };
+
+	/* Try running with --log-timestamp=iso */
+	const char * const argv24[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=iso" };
+
+	/* Try running with invalid timestamp */
+	const char * const argv25[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=invalid" };
+
+
 	/* run all tests also applicable to FreeBSD first */
 
 	if (launch_proc(argv0) == 0) {
@@ -1162,6 +1175,19 @@ test_misc_flags(void)
 		printf("Error - process did not run ok with --huge-worker-stack=size parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv23) != 0) {
+		printf("Error - process did not run ok with --log-timestamp parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv24) != 0) {
+		printf("Error - process did not run ok with --log-timestamp=iso parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv25) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
+
 
 	rmdir(hugepath_dir3);
 	rmdir(hugepath_dir2);
doc/guides/prog_guide/log_lib.rst +29 -1
index c87830ac00..82d3b7be2b 100644
@@ -57,7 +57,6 @@ For example::
 
 Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.
 
-
 Using Logging APIs to Generate Log Messages
 -------------------------------------------
 
@@ -109,3 +108,32 @@ Throughout the cfgfile library, all logging calls are therefore of the form:
 
 	CFG_LOG(ERR, "invalid comment characters %c",
 	       params->comment_character);
+
+Log timestamp
+~~~~~~~~~~~~~
+
+An optional timestamp can be added before each message
+by adding the ``--log-timestamp`` option.
+For example::
+
+	/path/to/app --log-level=lib.*:debug --log-timestamp
+
+Multiple timestamp alternative timestamp formats are available:
+
+.. csv-table:: Log time stamp format
+   :header: "Format", "Description", "Example"
+   :widths: 6, 30, 32
+
+   "ctime", "Unix ctime", "``[Wed Mar 20 07:26:12 2024]``"
+   "delta", "Offset since last", "``[<    3.162373>]``"
+   "reltime", "Seconds since last or time if minute changed", "``[  +3.001791]`` or ``[Mar20 07:26:12]``"
+   "iso", "ISO-8601", "``[2024-03-20T07:26:12−07:00]``"
+
+To prefix all console messages with ISO format time the syntax is::
+
+	/path/to/app --log-timestamp=iso
+
+.. note::
+
+   Timestamp option has no effect if using syslog because the ``syslog()``
+   service already does timestamping internally.
lib/eal/common/eal_common_options.c +12 -2
index ca7b702e03..a70d63479a 100644
@@ -74,6 +74,7 @@ eal_long_options[] = {
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
+	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
 	{OPT_TRACE_DIR,         1, NULL, OPT_TRACE_DIR_NUM        },
 	{OPT_TRACE_BUF_SIZE,    1, NULL, OPT_TRACE_BUF_SIZE_NUM   },
@@ -1618,6 +1619,7 @@ eal_log_level_parse(int argc, char * const argv[])
 		switch (opt) {
 		case OPT_LOG_LEVEL_NUM:
 		case OPT_SYSLOG_NUM:
+		case OPT_LOG_TIMESTAMP_NUM:
 			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
 				return -1;
 			break;
@@ -1840,7 +1842,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		break;
 #endif
 
-	case OPT_LOG_LEVEL_NUM: {
+	case OPT_LOG_LEVEL_NUM:
 		if (eal_parse_log_level(optarg) < 0) {
 			EAL_LOG(ERR,
 				"invalid parameters for --"
@@ -1848,7 +1850,14 @@ eal_parse_common_option(int opt, const char *optarg,
 			return -1;
 		}
 		break;
-	}
+
+	case OPT_LOG_TIMESTAMP_NUM:
+		if (eal_log_timestamp(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_TIMESTAMP);
+			return -1;
+		}
+		break;
 
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
@@ -2215,6 +2224,7 @@ eal_common_usage(void)
 	       "  --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
+	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index f3f2e104f6..e24c9eca53 100644
@@ -35,6 +35,8 @@ enum {
 	OPT_LCORES_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
+#define OPT_LOG_TIMESTAMP     "log-timestamp"
+	OPT_LOG_TIMESTAMP_NUM,
 #define OPT_TRACE             "trace"
 	OPT_TRACE_NUM,
 #define OPT_TRACE_DIR         "trace-dir"
lib/eal/freebsd/eal.c +4 -2
index 8631a20eae..456f91522c 100644
@@ -392,8 +392,10 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled these */
-		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_LOG_SYSLOG_NUM)
+		/* eal_log_level_parse() already handled these options */
+		if (opt == OPT_LOG_LEVEL_NUM ||
+		    opt == OPT_SYSLOG_NUM ||
+		    opt == OPT_LOG_TIMESTAMP_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/eal/linux/eal.c +3 -1
index 62d3d281c4..cf2f0fcab9 100644
@@ -611,7 +611,9 @@ eal_parse_args(int argc, char **argv)
 		}
 
 		/* eal_log_level_parse() already handled these options */
-		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
+		if (opt == OPT_LOG_LEVEL_NUM ||
+		    opt == OPT_SYSLOG_NUM ||
+		    opt == OPT_LOG_TIMESTAMP_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/eal/windows/eal.c +3 -1
index 33f044d7cc..b1c59945fb 100644
@@ -121,7 +121,9 @@ eal_parse_args(int argc, char **argv)
 		}
 
 		/* eal_log_level_parse() already handled these options */
-		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
+		if (opt == OPT_LOG_LEVEL_NUM ||
+		    opt == OPT_SYSLOG_NUM ||
+		    opt == OPT_LOG_TIMESTAMP_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/log/log.c +5 -0
index cc0c61cb22..854d77887b 100644
@@ -513,6 +513,11 @@ eal_log_init(const char *id)
 	if (logf)
 		rte_openlog_stream(logf);
 
+	if (log_timestamp_enabled())
+		rte_logs.print_func = log_print_with_timestamp;
+	else
+		rte_logs.print_func = vfprintf;
+
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
 		"Debug dataplane logs available - lower performance\n");
lib/log/log_internal.h +9 -0
index d5fabd7ef7..8ef195a6ec 100644
@@ -5,8 +5,10 @@
 #ifndef LOG_INTERNAL_H
 #define LOG_INTERNAL_H
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <time.h>
 
 #include <rte_compat.h>
 
@@ -45,4 +47,11 @@ const char *eal_log_level2str(uint32_t level);
 __rte_internal
 void rte_eal_log_cleanup(void);
 
+/*
+ * Add timestamp to console logs
+ */
+__rte_internal
+int eal_log_timestamp(const char *fmt);
+
+
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +6 -0
index bf87b43f7e..86eaf3f910 100644
@@ -22,4 +22,10 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+bool log_timestamp_enabled(void);
+ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
+
+__rte_format_printf(2, 0)
+int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/log_timestamp.c new file +240 -0

240 lines not on this page · raw message

lib/log/meson.build +1 -0
index 160cf34f50..4ac232786e 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_timestamp.c',
 )
 
 if not is_windows
lib/log/version.map +1 -0
index 1637fba3b9..8be6907840 100644
@@ -30,5 +30,6 @@ INTERNAL {
 	eal_log_save_pattern;
 	eal_log_save_regexp;
 	eal_log_syslog; # WINDOWS_NO_EXPORT
+	eal_log_timestamp;
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.45.2
#428 lore raw

PATCH v29 11/13 log: add support for systemd journal

In reply to Stephen Hemminger

If DPDK application is being run as a systemd service, then it can use the journal protocol which allows putting more information in the log such as priority and other information.

The use of journal protocol is automatically detected and handled. Rather than having a dependency on libsystemd, just use the protocol directly as defined in:
https://systemd.io/JOURNAL_NATIVE_PROTOCOL/

---
 lib/log/log.c          |  32 +++++----
 lib/log/log_internal.h |   3 +
 lib/log/log_journal.c  | 152 +++++++++++++++++++++++++++++++++++++++++
 lib/log/log_private.h  |  14 ++++
 lib/log/log_syslog.c   |   9 +++
 lib/log/meson.build    |   4 ++
 lib/log/version.map    |   1 +
 7 files changed, 203 insertions(+), 12 deletions(-)
 create mode 100644 lib/log/log_journal.c
lib/log/log.c +20 -12
index 854d77887b..db18690055 100644
@@ -505,18 +505,26 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...)
 void
 eal_log_init(const char *id)
 {
-	FILE *logf = NULL;
-
-	if (log_syslog_enabled())
-		logf = log_syslog_open(id);
-
-	if (logf)
-		rte_openlog_stream(logf);
-
-	if (log_timestamp_enabled())
-		rte_logs.print_func = log_print_with_timestamp;
-	else
-		rte_logs.print_func = vfprintf;
+	/* If user has already set a log stream, then use it. */
+	if (rte_logs.file == NULL) {
+		FILE *logf = NULL;
+
+		/* if stderr is assocated with systemd environment */
+		if (log_journal_enabled())
+			logf = log_journal_open(id);
+		/* If --syslog option was passed */
+		else if (log_syslog_enabled())
+			logf = log_syslog_open(id);
+
+		/* if either syslog or journal is used, then no special handling */
+		if (logf)
+			rte_openlog_stream(logf);
+
+		else if (log_timestamp_enabled())
+			rte_logs.print_func = log_print_with_timestamp;
+		else
+			rte_logs.print_func = vfprintf;
+	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
lib/log/log_internal.h +3 -0
index 8ef195a6ec..731c099984 100644
@@ -35,6 +35,9 @@ int eal_log_save_pattern(const char *pattern, uint32_t level);
 __rte_internal
 int eal_log_syslog(const char *name);
 
+__rte_internal
+int eal_log_journal(const char *opt);
+
 /*
  * Convert log level to string.
  */
lib/log/log_journal.c new file +152 -0

152 lines not on this page · raw message

lib/log/log_private.h +14 -0
index 86eaf3f910..37895949f6 100644
@@ -22,6 +22,20 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+#ifdef RTE_EXEC_ENV_LINUX
+bool log_journal_enabled(void);
+FILE *log_journal_open(const char *id);
+#else
+static inline bool log_journal_enabled(void)
+{
+	return false;
+}
+static inline FILE *log_journal_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#endif /* !RTE_EXEC_ENV_LINUX */
+
 bool log_timestamp_enabled(void);
 ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 
lib/log/log_syslog.c +9 -0
index bc9b996fd6..15c1f835c8 100644
@@ -17,6 +17,10 @@
 
 static int log_facility;
 
+/*
+ * Usable list of facilities
+ * Skip kern, mark, and security
+ */
 static const struct {
 	const char *name;
 	int value;
@@ -47,6 +51,11 @@ eal_log_syslog(const char *name)
 {
 	unsigned int i;
 
+	if (name == NULL) {
+		log_facility = LOG_DAEMON;
+		return 0;
+	}
+
 	for (i = 0; i < RTE_DIM(facilitys); i++) {
 		if (!strcmp(name, facilitys[i].name)) {
 			log_facility = facilitys[i].value;
lib/log/meson.build +4 -0
index 4ac232786e..86e4452b19 100644
@@ -11,4 +11,8 @@ if not is_windows
     sources += files('log_syslog.c')
 endif
 
+if is_linux
+    sources += files('log_journal.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -0
index 8be6907840..800d3943bc 100644
@@ -26,6 +26,7 @@ INTERNAL {
 	global:
 
 	eal_log_init;
+	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
Signature · 1 line
2.45.2
#429 lore raw

PATCH v29 12/13 log: colorize log output

In reply to Stephen Hemminger

Like dmesg, colorize the log output (unless redirected to file). Timestamp is green, the subsystem is in yellow and the message is red if urgent, boldface if an error, and normal for info and debug messages.

The default is to not use color since it may disturb automatic tests and other embedded usage.

---
 app/test/test_eal_flags.c           |  24 ++++
 doc/guides/prog_guide/log_lib.rst   |  24 ++++
 lib/eal/common/eal_common_options.c |  11 ++
 lib/eal/common/eal_options.h        |   2 +
 lib/log/log.c                       |  21 ++-
 lib/log/log_color.c                 | 214 ++++++++++++++++++++++++++++
 lib/log/log_internal.h              |   5 +
 lib/log/log_private.h               |   8 ++
 lib/log/meson.build                 |   1 +
 lib/log/version.map                 |   1 +
 10 files changed, 307 insertions(+), 4 deletions(-)
 create mode 100644 lib/log/log_color.c
app/test/test_eal_flags.c +24 -0
index e24630edde..061ddaf97f 100644
@@ -1067,6 +1067,18 @@ test_misc_flags(void)
 	const char * const argv25[] = {prgname, prefix, mp_flag,
 				       "--log-timestamp=invalid" };
 
+	/* Try running with --log-color */
+	const char * const argv26[] = {prgname, prefix, mp_flag,
+				       "--log-color" };
+
+	/* Try running with --log-color=never */
+	const char * const argv27[] = {prgname, prefix, mp_flag,
+				       "--log-color=never" };
+
+	/* Try running with --log-color=invalid */
+	const char * const argv28[] = {prgname, prefix, mp_flag,
+				       "--log-color=invalid" };
+
 
 	/* run all tests also applicable to FreeBSD first */
 
@@ -1187,6 +1199,18 @@ test_misc_flags(void)
 		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv26) != 0) {
+		printf("Error - process did not run ok with --log-color parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv27) != 0) {
+		printf("Error - process did not run ok with --log-color=never parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv28) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
 
 
 	rmdir(hugepath_dir3);
doc/guides/prog_guide/log_lib.rst +24 -0
index 82d3b7be2b..a4f880037b 100644
@@ -57,6 +57,7 @@ For example::
 
 Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.
 
+
 Using Logging APIs to Generate Log Messages
 -------------------------------------------
 
@@ -137,3 +138,26 @@ To prefix all console messages with ISO format time the syntax is::
 
    Timestamp option has no effect if using syslog because the ``syslog()``
    service already does timestamping internally.
+
+
+Color output
+~~~~~~~~~~~~
+
+The log library will highlight important messages.
+This is controlled by the ``--log-color`` option.
+The optional argument describes when color is enabled:
+
+:never: Do not enable color. This is the default behavior.
+
+:auto: Enable color only when printing to a terminal.
+       This is the same as ``--log-color`` with no argument
+
+:always: Always print color
+
+For example to enable color in logs if using terminal::
+
+	/path/to/app --log-color
+
+.. note::
+
+   Color output is never used for syslog or systemd journal logging.
lib/eal/common/eal_common_options.c +11 -0
index a70d63479a..6965666a7c 100644
@@ -73,6 +73,7 @@ eal_long_options[] = {
 	{OPT_HUGE_UNLINK,       2, NULL, OPT_HUGE_UNLINK_NUM      },
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
+	{OPT_LOG_COLOR,		2, NULL, OPT_LOG_COLOR_NUM	  },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
 	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
@@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[])
 		case OPT_LOG_LEVEL_NUM:
 		case OPT_SYSLOG_NUM:
 		case OPT_LOG_TIMESTAMP_NUM:
+		case OPT_LOG_COLOR_NUM:
 			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
 				return -1;
 			break;
@@ -1859,6 +1861,14 @@ eal_parse_common_option(int opt, const char *optarg,
 		}
 		break;
 
+	case OPT_LOG_COLOR_NUM:
+		if (eal_log_color(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_COLOR);
+			return -1;
+		}
+		break;
+
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
 		if (eal_trace_args_save(optarg) < 0) {
@@ -2225,6 +2235,7 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
 	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
+	       "  --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index e24c9eca53..87c3c32f86 100644
@@ -33,6 +33,8 @@ enum {
 	OPT_HUGE_UNLINK_NUM,
 #define OPT_LCORES            "lcores"
 	OPT_LCORES_NUM,
+#define OPT_LOG_COLOR	      "log-color"
+	OPT_LOG_COLOR_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
 #define OPT_LOG_TIMESTAMP     "log-timestamp"
lib/log/log.c +17 -4
index db18690055..cd9261e55d 100644
@@ -12,6 +12,7 @@
 #include <regex.h>
 #include <fnmatch.h>
 #include <sys/queue.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -520,10 +521,22 @@ eal_log_init(const char *id)
 		if (logf)
 			rte_openlog_stream(logf);
 
-		else if (log_timestamp_enabled())
-			rte_logs.print_func = log_print_with_timestamp;
-		else
-			rte_logs.print_func = vfprintf;
+		else {
+			bool is_terminal = isatty(fileno(stderr));
+			bool use_color = log_color_enabled(is_terminal);
+
+			if (log_timestamp_enabled()) {
+				if (use_color)
+					rte_logs.print_func = color_print_with_timestamp;
+				else
+					rte_logs.print_func = log_print_with_timestamp;
+			} else {
+				if (use_color)
+					rte_logs.print_func = color_print;
+				else
+					rte_logs.print_func = vfprintf;
+			}
+		}
 	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
lib/log/log_color.c new file +214 -0

214 lines not on this page · raw message

lib/log/log_internal.h +5 -0
index 731c099984..00dde59211 100644
@@ -56,5 +56,10 @@ void rte_eal_log_cleanup(void);
 __rte_internal
 int eal_log_timestamp(const char *fmt);
 
+/*
+ * Enable or disable color in log messages
+ */
+__rte_internal
+int eal_log_color(const char *mode);
 
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +8 -0
index 37895949f6..5755cbf71f 100644
@@ -42,4 +42,12 @@ ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 __rte_format_printf(2, 0)
 int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
 
+bool log_color_enabled(bool is_tty);
+
+__rte_format_printf(2, 0)
+int color_print(FILE *f, const char *format, va_list ap);
+
+__rte_format_printf(2, 0)
+int color_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/meson.build +1 -0
index 86e4452b19..b3de57b9c7 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_color.c',
         'log_timestamp.c',
 )
 
lib/log/version.map +1 -0
index 800d3943bc..09d8a4289b 100644
@@ -25,6 +25,7 @@ DPDK_25 {
 INTERNAL {
 	global:
 
+	eal_log_color;
 	eal_log_init;
 	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
Signature · 1 line
2.45.2
#430 lore raw

PATCH v29 13/13 doc: add release note about log library

In reply to Stephen Hemminger

Significant enough to warrant a release note.

---
 doc/guides/rel_notes/release_24_11.rst | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
doc/guides/rel_notes/release_24_11.rst +20 -0
index fa4822d928..1d2e60231b 100644
@@ -349,6 +349,26 @@ API Changes
   and replaced it with a new shared devarg ``llq_policy`` that keeps the same logic.
 
 
+* **Logging library changes**
+
+  * The log is initialized earlier in startup so all messages go through the library.
+
+  * Added a new option to timestamp log messages, which is useful for
+    debugging delays in application and driver startup.
+
+  * If the application is a systemd service and the log output is being
+    sent to standard error then DPDK will switch to journal native protocol.
+    This allows the more data such as severity to be sent.
+
+  * The syslog option has changed. By default, messages are no longer sent
+    to syslog unless the *--syslog* option is specified.
+    Syslog is also now now supported on FreeBSD (but not on Windows).
+
+  * Log messages can be timestamped with *--log-timestamp* option.
+
+  * Log messages can be colorized with the *--log-color* option.
+
+
 ABI Changes
 -----------
 
Signature · 1 line
2.45.2
#431 lore raw

v30 cover Log library enhancements

In reply to Stephen Hemminger

Improvements and unification of logging library.
This version works on all platforms: Linux, Windows and FreeBSD.

This is update to rework patch set. It adds several new features to the console log output.

* Putting a timestamp on console output which is useful for analyzing performance of startup codes. Timestamp is optional and must be enabled on command line.

* Displaying console output with colors.
It uses the standard conventions used by many other Linux commands for colorized display. The default is to enable color if the console output is going to a terminal. But it can be always on or disabled by command line flag. This default was chosen based on what dmesg(1) command does.

Color is used by many tools (vi, iproute2, git) because it is helpful; DPDK drivers and libraries print lots of not very useful messages. And having error messages highlighted in bold face helps. This might also get users to pay more attention to error messages. Many bug reports have earlier messages that are lost because there are so many info messages.

* Add support for automatic detection of systemd journal protocol. If running as systemd service will get enhanced logging.

* Use of syslog is optional and the meaning of the --syslog flag has changed. The default is *not* to use unless requested.

Add myself as maintainer for log because by now have added more than previous authors.

v30 - add isatty() to windows os shim
fix wording in release note etc.

Stephen Hemminger (13):
maintainers: add for log library
windows: make getopt functions have const properties
windows: update os shim
eal: make eal_log_level_parse common
eal: do not duplicate rte_init_alert() messages
eal: change rte_exit() output to match rte_log()
log: rework syslog handling
eal: initialize log before everything else
log: add hook for printing log messages
log: add timestamp option
log: add support for systemd journal
log: colorize log output
doc: add release note about log library

 MAINTAINERS                                   |   1 +
 app/test/test_eal_flags.c                     |  66 ++++-
 .../freebsd_gsg/freebsd_eal_parameters.rst    |  27 ++
 .../prog_guide/env_abstraction_layer.rst      |   6 +-
 doc/guides/prog_guide/log_lib.rst             |  60 ++++-
 doc/guides/rel_notes/release_24_11.rst        |  20 ++
 lib/eal/common/eal_common_debug.c             |   6 +-
 lib/eal/common/eal_common_options.c           | 122 +++++----
 lib/eal/common/eal_internal_cfg.h             |   1 -
 lib/eal/common/eal_options.h                  |   5 +
 lib/eal/freebsd/eal.c                         |  65 ++---
 lib/eal/linux/eal.c                           |  68 +----
 lib/eal/windows/eal.c                         |  50 +---
 lib/eal/windows/getopt.c                      |  23 +-
 lib/eal/windows/include/getopt.h              |   8 +-
 lib/eal/windows/include/rte_os_shim.h         |  12 +
 lib/log/log.c                                 |  83 ++++--
 lib/log/log_color.c                           | 214 ++++++++++++++++
 lib/log/log_freebsd.c                         |  12 -
 lib/log/log_internal.h                        |  22 +-
 lib/log/log_journal.c                         | 152 +++++++++++
 lib/log/log_linux.c                           |  61 -----
 lib/log/log_private.h                         |  53 ++++
 lib/log/log_syslog.c                          | 108 ++++++++
 lib/log/log_timestamp.c                       | 240 ++++++++++++++++++
 lib/log/log_windows.c                         |  18 --
 lib/log/meson.build                           |  12 +-
 lib/log/version.map                           |   5 +-
 28 files changed, 1168 insertions(+), 352 deletions(-)
 create mode 100644 lib/log/log_color.c
 delete mode 100644 lib/log/log_freebsd.c
 create mode 100644 lib/log/log_journal.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 create mode 100644 lib/log/log_timestamp.c
 delete mode 100644 lib/log/log_windows.c
Signature · 1 line
2.45.2
#432 lore raw

PATCH v30 1/13 maintainers: add for log library

"You touch it you own it"
Add myself as maintainer for log library.

---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)
MAINTAINERS +1 -0
index e25e9465b5..411b948649 100644
@@ -187,6 +187,7 @@ F: app/test/test_threads.c
 F: app/test/test_version.c
 
 Logging
+M: Stephen Hemminger <[email protected]>
 F: lib/log/
 F: doc/guides/prog_guide/log_lib.rst
 F: app/test/test_logs.c
Signature · 1 line
2.45.2
#433 lore raw

PATCH v30 2/13 windows: make getopt functions have const properties

In reply to Stephen Hemminger

Having different prototypes on different platforms can lead to lots of unnecessary workarounds. Looks like the version of getopt used from windows was based on an older out of date version from FreeBSD.

This patch changes getopt, getopt_long, etc to have the same const attributes as Linux and FreeBSD. The changes are derived from the current FreeBSD version of getopt_long.

---
 lib/eal/windows/getopt.c         | 23 ++++++++++++-----------
 lib/eal/windows/include/getopt.h |  8 ++++----
 2 files changed, 16 insertions(+), 15 deletions(-)
lib/eal/windows/getopt.c +12 -11
index a1f51c6c23..50ff71b930 100644
@@ -20,7 +20,7 @@
 #include <string.h>
 #include <stdlib.h>
 
-const char    *optarg;		/* argument associated with option */
+char    *optarg;		/* argument associated with option */
 int	opterr = 1;		/* if error message should be printed */
 int	optind = 1;		/* index into parent argv vector */
 int	optopt = '?';		/* character checked for validity */
@@ -39,9 +39,9 @@ static void pass(const char *a) {(void) a; }
 #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
 #define	INORDER		1
 
-#define	EMSG		""
+static char EMSG[] = "";
 
-static const char *place = EMSG; /* option letter processing */
+static char *place = EMSG; /* option letter processing */
 
 /* XXX: set optreset to 1 rather than these two */
 static int nonopt_start = -1; /* first non option argument (for permute) */
@@ -80,7 +80,7 @@ gcd(int a, int b)
  */
 static void
 permute_args(int panonopt_start, int panonopt_end, int opt_end,
-	char **nargv)
+	char * const *nargv)
 {
 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
 	char *swap;
@@ -101,11 +101,12 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
 				pos -= nnonopts;
 			else
 				pos += nopts;
+
 			swap = nargv[pos];
 			/* LINTED const cast */
-			((char **) nargv)[pos] = nargv[cstart];
+			((char **)(uintptr_t)nargv)[pos] = nargv[cstart];
 			/* LINTED const cast */
-			((char **)nargv)[cstart] = swap;
+			((char **)(uintptr_t)nargv)[cstart] = swap;
 		}
 	}
 }
@@ -116,7 +117,7 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
  * Returns -1 if short_too is set and the option does not match long_options.
  */
 static int
-parse_long_options(char **nargv, const char *options,
+parse_long_options(char * const *nargv, const char *options,
 	const struct option *long_options, int *idx, int short_too)
 {
 	const char *current_argv;
@@ -236,7 +237,7 @@ parse_long_options(char **nargv, const char *options,
  *	Parse argc/argv argument vector.  Called by user level routines.
  */
 static int
-getopt_internal(int nargc, char **nargv, const char *options,
+getopt_internal(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx, int flags)
 {
 	char *oli;				/* option letter list index */
@@ -434,7 +435,7 @@ getopt_internal(int nargc, char **nargv, const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt(int nargc, char *nargv[], const char *options)
+getopt(int nargc, char *const nargv[], const char *options)
 {
 	return getopt_internal(nargc, nargv, options, NULL, NULL,
 			       FLAG_PERMUTE);
@@ -445,7 +446,7 @@ getopt(int nargc, char *nargv[], const char *options)
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long(int nargc, char *nargv[], const char *options,
+getopt_long(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
@@ -458,7 +459,7 @@ getopt_long(int nargc, char *nargv[], const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long_only(int nargc, char *nargv[], const char *options,
+getopt_long_only(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
lib/eal/windows/include/getopt.h +4 -4
index 6f57af454b..e4cf6873cb 100644
@@ -44,7 +44,7 @@
 
 
 /** argument to current option, or NULL if it has none */
-extern const char *optarg;
+extern char *optarg;
 /** Current position in arg string.  Starts from 1.
  * Setting to 0 resets state.
  */
@@ -80,14 +80,14 @@ struct option {
 };
 
 /** Compat: getopt */
-int getopt(int argc, char *argv[], const char *options);
+int getopt(int argc, char *const argv[], const char *options);
 
 /** Compat: getopt_long */
-int getopt_long(int argc, char *argv[], const char *options,
+int getopt_long(int argc, char *const argv[], const char *options,
 		const struct option *longopts, int *longindex);
 
 /** Compat: getopt_long_only */
-int getopt_long_only(int nargc, char *argv[], const char *options,
+int getopt_long_only(int nargc, char *const argv[], const char *options,
 		     const struct option *long_options, int *idx);
 
 
Signature · 1 line
2.45.2
#434 lore raw

PATCH v30 3/13 windows: update os shim

In reply to Stephen Hemminger

Windows does not have localtime_r but it does have a similar function that can be used instead.

Use rte_os_shim.h in lib/log instead of redefine of strdup.

Add fileno() and isatty() to the wrapper.

---
 lib/eal/windows/include/rte_os_shim.h | 12 ++++++++++++
 lib/log/log.c                         |  7 +++----
 2 files changed, 15 insertions(+), 4 deletions(-)
lib/eal/windows/include/rte_os_shim.h +12 -0
index eda8113662..0e74eb19c7 100644
@@ -30,6 +30,8 @@
 #define write(fd, buf, n) _write(fd, buf, n)
 #define close(fd) _close(fd)
 #define unlink(path) _unlink(path)
+#define fileno(f) _fileno(f)
+#define isatty(fd) _isatty(fd)
 
 #define IPVERSION	4
 
@@ -110,4 +112,14 @@ rte_clock_gettime(clockid_t clock_id, struct timespec *tp)
 }
 #define clock_gettime(clock_id, tp) rte_clock_gettime(clock_id, tp)
 
+static inline struct tm *
+rte_localtime_r(const time_t *timep, struct tm *result)
+{
+	if (localtime_s(result, timep) == 0)
+		return result;
+	else
+		return NULL;
+}
+#define localtime_r(timep, result) rte_localtime_r(timep, result)
+
 #endif /* _RTE_OS_SHIM_ */
lib/log/log.c +3 -4
index 255f757d94..7416c82b34 100644
@@ -14,13 +14,12 @@
 
 #include <rte_log.h>
 #include <rte_per_lcore.h>
-
-#include "log_internal.h"
-
 #ifdef RTE_EXEC_ENV_WINDOWS
-#define strdup _strdup
+#include <rte_os_shim.h>
 #endif
 
+#include "log_internal.h"
+
 struct rte_log_dynamic_type {
 	const char *name;
 	uint32_t loglevel;
Signature · 1 line
2.45.2
#435 lore raw

PATCH v30 4/13 eal: make eal_log_level_parse common

In reply to Stephen Hemminger

The code to parse for log-level option should be same on all OS variants.

---
 lib/eal/common/eal_common_options.c | 40 +++++++++++++++++++++++++++
 lib/eal/common/eal_options.h        |  1 +
 lib/eal/freebsd/eal.c               | 42 -----------------------------
 lib/eal/linux/eal.c                 | 39 ---------------------------
 lib/eal/windows/eal.c               | 35 ------------------------
 5 files changed, 41 insertions(+), 116 deletions(-)
lib/eal/common/eal_common_options.c +40 -0
index f1a5e329a5..eb079a65a9 100644
@@ -1640,6 +1640,46 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
 	return -1;
 }
 
+/* Parse the all arguments looking for log related ones */
+int
+eal_log_level_parse(int argc, char * const argv[])
+{
+	struct internal_config *internal_conf = eal_get_internal_configuration();
+	int option_index, opt;
+	const int old_optind = optind;
+	const int old_optopt = optopt;
+	const int old_opterr = opterr;
+	char *old_optarg = optarg;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	const int old_optreset = optreset;
+	optreset = 1;
+#endif
+
+	optind = 1;
+	opterr = 0;
+
+	while ((opt = getopt_long(argc, argv, eal_short_options,
+				  eal_long_options, &option_index)) != EOF) {
+
+		switch (opt) {
+		case OPT_LOG_LEVEL_NUM:
+			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+				return -1;
+			break;
+		}
+	}
+
+	/* restore getopt lib */
+	optind = old_optind;
+	optopt = old_optopt;
+	optarg = old_optarg;
+	opterr = old_opterr;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	optreset = old_optreset;
+#endif
+	return 0;
+}
+
 int
 eal_parse_common_option(int opt, const char *optarg,
 			struct internal_config *conf)
lib/eal/common/eal_options.h +1 -0
index 3cc9cb6412..f3f2e104f6 100644
@@ -96,6 +96,7 @@ enum {
 extern const char eal_short_options[];
 extern const struct option eal_long_options[];
 
+int eal_log_level_parse(int argc, char * const argv[]);
 int eal_parse_common_option(int opt, const char *argv,
 			    struct internal_config *conf);
 int eal_option_device_parse(void);
lib/eal/freebsd/eal.c +0 -42

48 lines not on this page · raw message

lib/eal/linux/eal.c +0 -39
index 54577b7718..40d750ed0d 100644
@@ -546,45 +546,6 @@ eal_parse_vfio_vf_token(const char *vf_token)
 	return -1;
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	const int old_optind = optind;
-	const int old_optopt = optopt;
-	char * const old_optarg = optarg;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-	optind = 1;
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-				  eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg, internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	/* restore getopt lib */
-	optind = old_optind;
-	optopt = old_optopt;
-	optarg = old_optarg;
-}
-
 static int
 eal_parse_huge_worker_stack(const char *arg)
 {
lib/eal/windows/eal.c +0 -35
index 28b78a95a6..a77e590a72 100644
@@ -96,41 +96,6 @@ eal_usage(const char *prgname)
 	}
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-
-	eal_reset_internal_config(internal_conf);
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-		eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg,
-				internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	optind = 0; /* reset getopt lib */
-}
-
 /* Parse the argument given in the command line of the application */
 static int
 eal_parse_args(int argc, char **argv)
Signature · 1 line
2.45.2
#436 lore raw

PATCH v30 5/13 eal: do not duplicate rte_init_alert() messages

In reply to Stephen Hemminger

The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name.

---
 lib/eal/freebsd/eal.c | 3 +--
 lib/eal/linux/eal.c   | 3 +--
 lib/eal/windows/eal.c | 1 -
 3 files changed, 2 insertions(+), 5 deletions(-)
lib/eal/freebsd/eal.c +1 -2
index d3b40e81d8..7b974608e4 100644
@@ -529,8 +529,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /* Launch threads, called at application init(). */
lib/eal/linux/eal.c +1 -2
index 40d750ed0d..c53a051405 100644
@@ -830,8 +830,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /*
lib/eal/windows/eal.c +0 -1
index a77e590a72..93f099a968 100644
@@ -181,7 +181,6 @@ sync_func(void *arg __rte_unused)
 static void
 rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
 	EAL_LOG(ERR, "%s", msg);
 }
 
Signature · 1 line
2.45.2
#437 lore raw

PATCH v30 6/13 eal: change rte_exit() output to match rte_log()

In reply to Stephen Hemminger

The rte_exit() output format confuses the timestamp and coloring options. Change it to use be a single line with proper prefix.

Before:

[     0.006481] EAL: Error - exiting with code: 1
  Cause: [     0.006489] Cannot init EAL: Permission denied

After:

[     0.006238] EAL: Error - exiting with code: 1
[     0.006250] EAL: Cannot init EAL: Permission denied
---
 lib/eal/common/eal_common_debug.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
lib/eal/common/eal_common_debug.c +2 -4
index 3e77995896..bcfcd6df6f 100644
@@ -36,15 +36,13 @@ rte_exit(int exit_code, const char *format, ...)
 	va_list ap;
 
 	if (exit_code != 0)
-		RTE_LOG(CRIT, EAL, "Error - exiting with code: %d\n"
-				"  Cause: ", exit_code);
+		EAL_LOG(CRIT, "Error - exiting with code: %d", exit_code);
 
 	va_start(ap, format);
 	rte_vlog(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, format, ap);
 	va_end(ap);
 
 	if (rte_eal_cleanup() != 0 && rte_errno != EALREADY)
-		EAL_LOG(CRIT,
-			"EAL could not release all resources");
+		EAL_LOG(CRIT, "EAL could not release all resources");
 	exit(exit_code);
 }
Signature · 1 line
2.45.2
#438 lore raw

PATCH v30 7/13 log: rework syslog handling

In reply to Stephen Hemminger

Refactor how syslog is handled, make it common to Linux and FreeBSD The syslog facility property is better handled in lib/log rather than in eal. This also add syslog support to FreeBSD.

Log to syslog only if option is specified.
If no --syslog is given then use only standard error.

---
 app/test/test_eal_flags.c                     | 16 +--
 .../freebsd_gsg/freebsd_eal_parameters.rst    | 27 +++++
 .../prog_guide/env_abstraction_layer.rst      |  6 +-
 doc/guides/prog_guide/log_lib.rst             |  7 +-
 lib/eal/common/eal_common_options.c           | 57 ++---------
 lib/eal/common/eal_internal_cfg.h             |  1 -
 lib/eal/freebsd/eal.c                         |  5 +-
 lib/eal/linux/eal.c                           | 12 +--
 lib/eal/windows/eal.c                         |  6 +-
 lib/log/log.c                                 | 44 ++++-----
 lib/log/log_freebsd.c                         | 12 ---
 lib/log/log_internal.h                        | 11 +--
 lib/log/log_linux.c                           | 61 ------------
 lib/log/log_private.h                         | 25 +++++
 lib/log/log_syslog.c                          | 99 +++++++++++++++++++
 lib/log/log_windows.c                         | 18 ----
 lib/log/meson.build                           |  6 +-
 lib/log/version.map                           |  2 +-
 18 files changed, 211 insertions(+), 204 deletions(-)
 delete mode 100644 lib/log/log_freebsd.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 delete mode 100644 lib/log/log_windows.c
app/test/test_eal_flags.c +8 -8
index 71d8dba731..9fcf0d56e6 100644
@@ -985,12 +985,12 @@ test_misc_flags(void)
 	/* With -v */
 	const char *argv2[] = {prgname, prefix, mp_flag, "-v"};
 	/* With valid --syslog */
-	const char *argv3[] = {prgname, prefix, mp_flag,
-			"--syslog", "syslog"};
-	/* With empty --syslog (should fail) */
+	const char *argv3[] = {prgname, prefix, mp_flag, "--syslog=user"};
+	/* With empty --syslog (now defaults) */
 	const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"};
 	/* 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};
@@ -1080,15 +1080,15 @@ test_misc_flags(void)
 #endif
 
 	if (launch_proc(argv3) != 0) {
-		printf("Error - process did not run ok with --syslog flag\n");
+		printf("Error - process did not run ok with --syslog=user flag\n");
 		goto fail;
 	}
-	if (launch_proc(argv4) == 0) {
-		printf("Error - process run ok with empty --syslog flag\n");
+	if (launch_proc(argv4) != 0) {
+		printf("Error - process did not run ok with --syslog flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv5) == 0) {
-		printf("Error - process run ok with invalid --syslog flag\n");
+		printf("Error - process run ok with --syslog=invalid flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv7) != 0) {
doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +27 -0
index fba467a2ce..9270d9fa3b 100644
@@ -18,3 +18,30 @@ FreeBSD-specific EAL parameters
 -------------------------------
 
 There are currently no FreeBSD-specific EAL command-line parameters available.
+
+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
doc/guides/prog_guide/env_abstraction_layer.rst +3 -3
index b9fac1839d..9bafa30a0e 100644
@@ -851,9 +851,9 @@ Signal Safety
   Other functions are not signal safe because they use one or more
   library routines that are not themselves signal safe.
   For example, calling ``rte_panic()`` is not safe in a signal handler
-  because it uses ``rte_log()`` and ``rte_log()`` calls the
-  ``syslog()`` library function which is in the list of
-  signal safe functions in
+  because it uses ``rte_log()`` and ``rte_log()`` may call ``vfprintf()`` or
+  ``syslog()`` library functions which are not in the list of
+  signal safe functions
   `Signal-Safety manual page <https://man7.org/linux/man-pages/man7/signal-safety.7.html>`_.
 
   The set of functions that are expected to be async-signal-safe in DPDK
doc/guides/prog_guide/log_lib.rst +4 -3
index ff9d1b54a2..a77ba939a9 100644
@@ -5,9 +5,10 @@ Log Library
 ===========
 
 The DPDK Log library provides the logging functionality for other DPDK libraries and drivers.
-By default, in a Linux application, logs are sent to syslog and also to the console.
-On FreeBSD and Windows applications, logs are sent only to the console.
-However, the log function can be overridden by the user to use a different logging mechanism.
+By default, logs are sent only to standard error output of the process.
+The syslog EAL option can be used to redirect to the stystem logger
+on Linux and FreeBSD.
+In addition, the log can be redirected to a different stdio file stream.
 
 Log Levels
 ----------
lib/eal/common/eal_common_options.c +6 -51

99 lines not on this page · raw message

lib/eal/common/eal_internal_cfg.h +0 -1
index 167ec501fa..f53ab8b4aa 100644
@@ -84,7 +84,6 @@ struct internal_config {
 	/**< true if storing all pages within single files (per-page-size,
 	 * per-node) non-legacy mode only.
 	 */
-	volatile int syslog_facility;	  /**< facility passed to openlog() */
 	/** default interrupt mode for VFIO */
 	volatile enum rte_intr_mode vfio_intr_mode;
 	/** the shared VF token for VFIO-PCI bound PF and VFs devices */
lib/eal/freebsd/eal.c +2 -3
index 7b974608e4..a609d40ee0 100644
@@ -11,7 +11,6 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <pthread.h>
-#include <syslog.h>
 #include <getopt.h>
 #include <sys/file.h>
 #include <stddef.h>
@@ -392,8 +391,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_log_level_parse() already handled these */
+		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_LOG_SYSLOG_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/eal/linux/eal.c +3 -9
index c53a051405..0c44d0b6e3 100644
@@ -610,8 +610,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_log_level_parse() already handled these options */
+		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -1103,13 +1103,7 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	if (eal_log_init(program_invocation_short_name,
-			 internal_conf->syslog_facility) < 0) {
-		rte_eal_init_alert("Cannot init logging.");
-		rte_errno = ENOMEM;
-		rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
-		return -1;
-	}
+	eal_log_init(program_invocation_short_name);
 
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
lib/eal/windows/eal.c +3 -3
index 93f099a968..cd8420a82c 100644
@@ -120,8 +120,8 @@ eal_parse_args(int argc, char **argv)
 			return -1;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_log_level_parse() already handled these options */
+		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -249,7 +249,7 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL, 0);
+	eal_log_init(NULL);
 
 	eal_log_level_parse(argc, argv);
 
lib/log/log.c +21 -23

94 lines not on this page · raw message

lib/log/log_freebsd.c deleted +0 -12
deleted file mode 100644
index 698d3c5423..0000000000
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2023 Intel Corporation
- */
-
-#include <rte_common.h>
-#include "log_internal.h"
-
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	return 0;
-}
lib/log/log_internal.h +4 -7
index 451629f1c1..3c46328e7b 100644
@@ -14,13 +14,7 @@
  * Initialize the default log stream.
  */
 __rte_internal
-int eal_log_init(const char *id, int facility);
-
-/*
- * Determine where log data is written when no call to rte_openlog_stream.
- */
-__rte_internal
-void eal_log_set_default(FILE *default_log);
+void eal_log_init(const char *id);
 
 /*
  * Save a log option for later.
@@ -30,6 +24,9 @@ int eal_log_save_regexp(const char *regexp, uint32_t level);
 __rte_internal
 int eal_log_save_pattern(const char *pattern, uint32_t level);
 
+__rte_internal
+int eal_log_syslog(const char *name);
+
 /*
  * Convert log level to string.
  */
lib/log/log_linux.c deleted +0 -61

61 lines not on this page · raw message

lib/log/log_private.h new file +25 -0
new file mode 100644
index 0000000000..bf87b43f7e
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#ifndef LOG_PRIVATE_H
+#define LOG_PRIVATE_H
+
+/* Defined in limits.h on Linux */
+#ifndef LINE_MAX
+#define LINE_MAX	2048 /* _POSIX2_LINE_MAX */
+#endif
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+static inline bool log_syslog_enabled(void)
+{
+	return false;
+}
+static inline FILE *log_syslog_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#else
+bool log_syslog_enabled(void);
+FILE *log_syslog_open(const char *id);
+#endif
+
+#endif /* LOG_PRIVATE_H */
lib/log/log_syslog.c new file +99 -0

99 lines not on this page · raw message

lib/log/log_windows.c deleted +0 -18
deleted file mode 100644
index a6a0889550..0000000000
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2017-2018 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_log.h>
-#include "log_internal.h"
-
-/* set the log to default function, called during eal init process. */
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	rte_openlog_stream(stderr);
-
-	eal_log_set_default(stderr);
-
-	return 0;
-}
lib/log/meson.build +5 -1
index 0d4319b36f..160cf34f50 100644
@@ -4,6 +4,10 @@
 includes += global_inc
 sources = files(
         'log.c',
-        'log_' + exec_env + '.c',
 )
+
+if not is_windows
+    sources += files('log_syslog.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -1
index 19d7f9cdb6..1637fba3b9 100644
@@ -29,6 +29,6 @@ INTERNAL {
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
-	eal_log_set_default;
+	eal_log_syslog; # WINDOWS_NO_EXPORT
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.45.2
#439 lore raw

PATCH v30 8/13 eal: initialize log before everything else

In reply to Stephen Hemminger

In order for all log messages (including CPU mismatch) to come out through the logging library, it must be initialized as early in rte_eal_init() as possible on all platforms.

Where it was done before was likely historical based on the support of non-OS isolated CPU's which required a shared memory buffer; that support was dropped before DPDK was publicly released.

---
 lib/eal/freebsd/eal.c  | 13 ++++++++++---
 lib/eal/linux/eal.c    | 14 +++++++++-----
 lib/eal/windows/eal.c  |  8 ++++++--
 lib/log/log_internal.h |  6 ++++++
 4 files changed, 31 insertions(+), 10 deletions(-)
lib/eal/freebsd/eal.c +10 -3
index a609d40ee0..8631a20eae 100644
@@ -52,6 +52,7 @@
 #include "eal_options.h"
 #include "eal_memcfg.h"
 #include "eal_trace.h"
+#include "log_internal.h"
 
 #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
 
@@ -546,6 +547,15 @@ rte_eal_init(int argc, char **argv)
 	bool has_phys_addr;
 	enum rte_iova_mode iova_mode;
 
+	/* setup log as early as possible */
+	if (eal_log_level_parse(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(getprogname());
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -572,9 +582,6 @@ rte_eal_init(int argc, char **argv)
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
-
 	if (rte_eal_cpu_init() < 0) {
 		rte_eal_init_alert("Cannot detect lcores.");
 		rte_errno = ENOTSUP;
lib/eal/linux/eal.c +9 -5
index 0c44d0b6e3..62d3d281c4 100644
@@ -926,6 +926,15 @@ rte_eal_init(int argc, char **argv)
 	struct internal_config *internal_conf =
 		eal_get_internal_configuration();
 
+	/* setup log as early as possible */
+	if (eal_log_level_parse(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(program_invocation_short_name);
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -949,9 +958,6 @@ rte_eal_init(int argc, char **argv)
 
 	eal_reset_internal_config(internal_conf);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
-
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
@@ -1103,8 +1109,6 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	eal_log_init(program_invocation_short_name);
-
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
 		rte_eal_init_alert("Cannot init VFIO");
lib/eal/windows/eal.c +6 -2
index cd8420a82c..33f044d7cc 100644
@@ -249,9 +249,13 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL);
+	if (eal_log_level_parse(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
 
-	eal_log_level_parse(argc, argv);
+	eal_log_init(NULL);
 
 	if (eal_create_cpu_map() < 0) {
 		rte_eal_init_alert("Cannot discover CPU and NUMA.");
lib/log/log_internal.h +6 -0
index 3c46328e7b..d5fabd7ef7 100644
@@ -16,6 +16,12 @@
 __rte_internal
 void eal_log_init(const char *id);
 
+/*
+ * Determine where log data is written when no call to rte_openlog_stream.
+ */
+__rte_internal
+void eal_log_set_default(FILE *default_log);
+
 /*
  * Save a log option for later.
  */
Signature · 1 line
2.45.2
#440 lore raw

PATCH v30 9/13 log: add hook for printing log messages

In reply to Stephen Hemminger

This is useful for when decorating log output for console or journal. Provide basic version in this patch.

---
 lib/log/log.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
lib/log/log.c +7 -1
index 511ab3b30b..cc0c61cb22 100644
@@ -29,16 +29,21 @@ struct rte_log_dynamic_type {
 	uint32_t loglevel;
 };
 
+/* Note: same as vfprintf() */
+typedef int (*log_print_t)(FILE *f, const char *fmt, 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. */
+	log_print_t print_func;
 	size_t dynamic_types_len;
 	struct rte_log_dynamic_type *dynamic_types;
 } rte_logs = {
 	.type = UINT32_MAX,
 	.level = RTE_LOG_DEBUG,
+	.print_func = vfprintf,
 };
 
 struct rte_eal_opt_loglevel {
@@ -75,6 +80,7 @@ int
 rte_openlog_stream(FILE *f)
 {
 	rte_logs.file = f;
+	rte_logs.print_func = vfprintf;
 	return 0;
 }
 
@@ -471,7 +477,7 @@ rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap)
 	RTE_PER_LCORE(log_cur_msg).loglevel = level;
 	RTE_PER_LCORE(log_cur_msg).logtype = logtype;
 
-	ret = vfprintf(f, format, ap);
+	ret = (*rte_logs.print_func)(f, format, ap);
 	fflush(f);
 	return ret;
 }
Signature · 1 line
2.45.2
#441 lore raw

PATCH v30 10/13 log: add timestamp option

In reply to Stephen Hemminger

When debugging driver or startup issues, it is useful to have a timestamp on each message printed. The messages in syslog already have a timestamp, but often syslog is not available during testing.

There are multiple timestamp formats similar to Linux dmesg. The default is time relative since startup (when first step of logging initialization is done by constructor). Other alternative formats are delta, ctime, reltime and iso formats.

Example:

$ dpdk-testpmd --log-timestamp -- -i
[     0.008610] EAL: Detected CPU lcores: 8
[     0.008634] EAL: Detected NUMA nodes: 1
[     0.008792] EAL: Detected static linkage of DPDK
[     0.010620] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
[     0.012618] EAL: Selected IOVA mode 'VA'
[     0.016675] testpmd: No probed ethernet devices
Interactive-mode selected
---
 app/test/test_eal_flags.c           |  26 +++
 doc/guides/prog_guide/log_lib.rst   |  29 ++++
 lib/eal/common/eal_common_options.c |  14 +-
 lib/eal/common/eal_options.h        |   2 +
 lib/eal/freebsd/eal.c               |   6 +-
 lib/eal/linux/eal.c                 |   4 +-
 lib/eal/windows/eal.c               |   4 +-
 lib/log/log.c                       |   5 +
 lib/log/log_internal.h              |   9 ++
 lib/log/log_private.h               |   6 +
 lib/log/log_timestamp.c             | 240 ++++++++++++++++++++++++++++
 lib/log/meson.build                 |   1 +
 lib/log/version.map                 |   1 +
 13 files changed, 341 insertions(+), 6 deletions(-)
 create mode 100644 lib/log/log_timestamp.c
app/test/test_eal_flags.c +26 -0
index 9fcf0d56e6..e24630edde 100644
@@ -1055,6 +1055,19 @@ test_misc_flags(void)
 	const char * const argv22[] = {prgname, prefix, mp_flag,
 				       "--huge-worker-stack=512"};
 
+	/* Try running with --log-timestamp */
+	const char * const argv23[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp" };
+
+	/* Try running with --log-timestamp=iso */
+	const char * const argv24[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=iso" };
+
+	/* Try running with invalid timestamp */
+	const char * const argv25[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=invalid" };
+
+
 	/* run all tests also applicable to FreeBSD first */
 
 	if (launch_proc(argv0) == 0) {
@@ -1162,6 +1175,19 @@ test_misc_flags(void)
 		printf("Error - process did not run ok with --huge-worker-stack=size parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv23) != 0) {
+		printf("Error - process did not run ok with --log-timestamp parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv24) != 0) {
+		printf("Error - process did not run ok with --log-timestamp=iso parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv25) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
+
 
 	rmdir(hugepath_dir3);
 	rmdir(hugepath_dir2);
doc/guides/prog_guide/log_lib.rst +29 -0
index a77ba939a9..3843b70016 100644
@@ -111,3 +111,32 @@ Throughout the cfgfile library, all logging calls are therefore of the form:
 
 	CFG_LOG(ERR, "invalid comment characters %c",
 	       params->comment_character);
+
+Log timestamp
+~~~~~~~~~~~~~
+
+An optional timestamp can be added before each message
+by adding the ``--log-timestamp`` option.
+For example::
+
+	/path/to/app --log-level=lib.*:debug --log-timestamp
+
+Multiple timestamp alternative timestamp formats are available:
+
+.. csv-table:: Log time stamp format
+   :header: "Format", "Description", "Example"
+   :widths: 6, 30, 32
+
+   "ctime", "Unix ctime", "``[Wed Mar 20 07:26:12 2024]``"
+   "delta", "Offset since last", "``[<    3.162373>]``"
+   "reltime", "Seconds since last or time if minute changed", "``[  +3.001791]`` or ``[Mar20 07:26:12]``"
+   "iso", "ISO-8601", "``[2024-03-20T07:26:12−07:00]``"
+
+To prefix all console messages with ISO format time the syntax is::
+
+	/path/to/app --log-timestamp=iso
+
+.. note::
+
+   Timestamp option has no effect if using syslog because the ``syslog()``
+   service already does timestamping internally.
lib/eal/common/eal_common_options.c +12 -2
index ca7b702e03..a70d63479a 100644
@@ -74,6 +74,7 @@ eal_long_options[] = {
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
+	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
 	{OPT_TRACE_DIR,         1, NULL, OPT_TRACE_DIR_NUM        },
 	{OPT_TRACE_BUF_SIZE,    1, NULL, OPT_TRACE_BUF_SIZE_NUM   },
@@ -1618,6 +1619,7 @@ eal_log_level_parse(int argc, char * const argv[])
 		switch (opt) {
 		case OPT_LOG_LEVEL_NUM:
 		case OPT_SYSLOG_NUM:
+		case OPT_LOG_TIMESTAMP_NUM:
 			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
 				return -1;
 			break;
@@ -1840,7 +1842,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		break;
 #endif
 
-	case OPT_LOG_LEVEL_NUM: {
+	case OPT_LOG_LEVEL_NUM:
 		if (eal_parse_log_level(optarg) < 0) {
 			EAL_LOG(ERR,
 				"invalid parameters for --"
@@ -1848,7 +1850,14 @@ eal_parse_common_option(int opt, const char *optarg,
 			return -1;
 		}
 		break;
-	}
+
+	case OPT_LOG_TIMESTAMP_NUM:
+		if (eal_log_timestamp(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_TIMESTAMP);
+			return -1;
+		}
+		break;
 
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
@@ -2215,6 +2224,7 @@ eal_common_usage(void)
 	       "  --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
+	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index f3f2e104f6..e24c9eca53 100644
@@ -35,6 +35,8 @@ enum {
 	OPT_LCORES_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
+#define OPT_LOG_TIMESTAMP     "log-timestamp"
+	OPT_LOG_TIMESTAMP_NUM,
 #define OPT_TRACE             "trace"
 	OPT_TRACE_NUM,
 #define OPT_TRACE_DIR         "trace-dir"
lib/eal/freebsd/eal.c +4 -2
index 8631a20eae..456f91522c 100644
@@ -392,8 +392,10 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled these */
-		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_LOG_SYSLOG_NUM)
+		/* eal_log_level_parse() already handled these options */
+		if (opt == OPT_LOG_LEVEL_NUM ||
+		    opt == OPT_SYSLOG_NUM ||
+		    opt == OPT_LOG_TIMESTAMP_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/eal/linux/eal.c +3 -1
index 62d3d281c4..cf2f0fcab9 100644
@@ -611,7 +611,9 @@ eal_parse_args(int argc, char **argv)
 		}
 
 		/* eal_log_level_parse() already handled these options */
-		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
+		if (opt == OPT_LOG_LEVEL_NUM ||
+		    opt == OPT_SYSLOG_NUM ||
+		    opt == OPT_LOG_TIMESTAMP_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/eal/windows/eal.c +3 -1
index 33f044d7cc..b1c59945fb 100644
@@ -121,7 +121,9 @@ eal_parse_args(int argc, char **argv)
 		}
 
 		/* eal_log_level_parse() already handled these options */
-		if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM)
+		if (opt == OPT_LOG_LEVEL_NUM ||
+		    opt == OPT_SYSLOG_NUM ||
+		    opt == OPT_LOG_TIMESTAMP_NUM)
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
lib/log/log.c +5 -0
index cc0c61cb22..854d77887b 100644
@@ -513,6 +513,11 @@ eal_log_init(const char *id)
 	if (logf)
 		rte_openlog_stream(logf);
 
+	if (log_timestamp_enabled())
+		rte_logs.print_func = log_print_with_timestamp;
+	else
+		rte_logs.print_func = vfprintf;
+
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
 		"Debug dataplane logs available - lower performance\n");
lib/log/log_internal.h +9 -0
index d5fabd7ef7..8ef195a6ec 100644
@@ -5,8 +5,10 @@
 #ifndef LOG_INTERNAL_H
 #define LOG_INTERNAL_H
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <time.h>
 
 #include <rte_compat.h>
 
@@ -45,4 +47,11 @@ const char *eal_log_level2str(uint32_t level);
 __rte_internal
 void rte_eal_log_cleanup(void);
 
+/*
+ * Add timestamp to console logs
+ */
+__rte_internal
+int eal_log_timestamp(const char *fmt);
+
+
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +6 -0
index bf87b43f7e..86eaf3f910 100644
@@ -22,4 +22,10 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+bool log_timestamp_enabled(void);
+ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
+
+__rte_format_printf(2, 0)
+int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/log_timestamp.c new file +240 -0

240 lines not on this page · raw message

lib/log/meson.build +1 -0
index 160cf34f50..4ac232786e 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_timestamp.c',
 )
 
 if not is_windows
lib/log/version.map +1 -0
index 1637fba3b9..8be6907840 100644
@@ -30,5 +30,6 @@ INTERNAL {
 	eal_log_save_pattern;
 	eal_log_save_regexp;
 	eal_log_syslog; # WINDOWS_NO_EXPORT
+	eal_log_timestamp;
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.45.2
#442 lore raw

PATCH v30 11/13 log: add support for systemd journal

In reply to Stephen Hemminger

If DPDK application is being run as a systemd service, then it can use the journal protocol which allows putting more information in the log such as priority and other information.

The use of journal protocol is automatically detected and handled. Rather than having a dependency on libsystemd, just use the protocol directly as defined in:
https://systemd.io/JOURNAL_NATIVE_PROTOCOL/

---
 lib/log/log.c          |  32 +++++----
 lib/log/log_internal.h |   3 +
 lib/log/log_journal.c  | 152 +++++++++++++++++++++++++++++++++++++++++
 lib/log/log_private.h  |  14 ++++
 lib/log/log_syslog.c   |   9 +++
 lib/log/meson.build    |   4 ++
 lib/log/version.map    |   1 +
 7 files changed, 203 insertions(+), 12 deletions(-)
 create mode 100644 lib/log/log_journal.c
lib/log/log.c +20 -12
index 854d77887b..db18690055 100644
@@ -505,18 +505,26 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...)
 void
 eal_log_init(const char *id)
 {
-	FILE *logf = NULL;
-
-	if (log_syslog_enabled())
-		logf = log_syslog_open(id);
-
-	if (logf)
-		rte_openlog_stream(logf);
-
-	if (log_timestamp_enabled())
-		rte_logs.print_func = log_print_with_timestamp;
-	else
-		rte_logs.print_func = vfprintf;
+	/* If user has already set a log stream, then use it. */
+	if (rte_logs.file == NULL) {
+		FILE *logf = NULL;
+
+		/* if stderr is assocated with systemd environment */
+		if (log_journal_enabled())
+			logf = log_journal_open(id);
+		/* If --syslog option was passed */
+		else if (log_syslog_enabled())
+			logf = log_syslog_open(id);
+
+		/* if either syslog or journal is used, then no special handling */
+		if (logf)
+			rte_openlog_stream(logf);
+
+		else if (log_timestamp_enabled())
+			rte_logs.print_func = log_print_with_timestamp;
+		else
+			rte_logs.print_func = vfprintf;
+	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
lib/log/log_internal.h +3 -0
index 8ef195a6ec..731c099984 100644
@@ -35,6 +35,9 @@ int eal_log_save_pattern(const char *pattern, uint32_t level);
 __rte_internal
 int eal_log_syslog(const char *name);
 
+__rte_internal
+int eal_log_journal(const char *opt);
+
 /*
  * Convert log level to string.
  */
lib/log/log_journal.c new file +152 -0

152 lines not on this page · raw message

lib/log/log_private.h +14 -0
index 86eaf3f910..37895949f6 100644
@@ -22,6 +22,20 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+#ifdef RTE_EXEC_ENV_LINUX
+bool log_journal_enabled(void);
+FILE *log_journal_open(const char *id);
+#else
+static inline bool log_journal_enabled(void)
+{
+	return false;
+}
+static inline FILE *log_journal_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#endif /* !RTE_EXEC_ENV_LINUX */
+
 bool log_timestamp_enabled(void);
 ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 
lib/log/log_syslog.c +9 -0
index bc9b996fd6..15c1f835c8 100644
@@ -17,6 +17,10 @@
 
 static int log_facility;
 
+/*
+ * Usable list of facilities
+ * Skip kern, mark, and security
+ */
 static const struct {
 	const char *name;
 	int value;
@@ -47,6 +51,11 @@ eal_log_syslog(const char *name)
 {
 	unsigned int i;
 
+	if (name == NULL) {
+		log_facility = LOG_DAEMON;
+		return 0;
+	}
+
 	for (i = 0; i < RTE_DIM(facilitys); i++) {
 		if (!strcmp(name, facilitys[i].name)) {
 			log_facility = facilitys[i].value;
lib/log/meson.build +4 -0
index 4ac232786e..86e4452b19 100644
@@ -11,4 +11,8 @@ if not is_windows
     sources += files('log_syslog.c')
 endif
 
+if is_linux
+    sources += files('log_journal.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -0
index 8be6907840..800d3943bc 100644
@@ -26,6 +26,7 @@ INTERNAL {
 	global:
 
 	eal_log_init;
+	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
Signature · 1 line
2.45.2
#443 lore raw

PATCH v30 12/13 log: colorize log output

In reply to Stephen Hemminger

Like dmesg, colorize the log output (unless redirected to file). Timestamp is green, the subsystem is in yellow and the message is red if urgent, boldface if an error, and normal for info and debug messages.

The default is to not use color since it may disturb automatic tests and other embedded usage.

---
 app/test/test_eal_flags.c           |  24 ++++
 doc/guides/prog_guide/log_lib.rst   |  24 ++++
 lib/eal/common/eal_common_options.c |  11 ++
 lib/eal/common/eal_options.h        |   2 +
 lib/log/log.c                       |  21 ++-
 lib/log/log_color.c                 | 214 ++++++++++++++++++++++++++++
 lib/log/log_internal.h              |   5 +
 lib/log/log_private.h               |   8 ++
 lib/log/meson.build                 |   1 +
 lib/log/version.map                 |   1 +
 10 files changed, 307 insertions(+), 4 deletions(-)
 create mode 100644 lib/log/log_color.c
app/test/test_eal_flags.c +24 -0
index e24630edde..061ddaf97f 100644
@@ -1067,6 +1067,18 @@ test_misc_flags(void)
 	const char * const argv25[] = {prgname, prefix, mp_flag,
 				       "--log-timestamp=invalid" };
 
+	/* Try running with --log-color */
+	const char * const argv26[] = {prgname, prefix, mp_flag,
+				       "--log-color" };
+
+	/* Try running with --log-color=never */
+	const char * const argv27[] = {prgname, prefix, mp_flag,
+				       "--log-color=never" };
+
+	/* Try running with --log-color=invalid */
+	const char * const argv28[] = {prgname, prefix, mp_flag,
+				       "--log-color=invalid" };
+
 
 	/* run all tests also applicable to FreeBSD first */
 
@@ -1187,6 +1199,18 @@ test_misc_flags(void)
 		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv26) != 0) {
+		printf("Error - process did not run ok with --log-color parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv27) != 0) {
+		printf("Error - process did not run ok with --log-color=never parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv28) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
 
 
 	rmdir(hugepath_dir3);
doc/guides/prog_guide/log_lib.rst +24 -0
index 3843b70016..748d3836dc 100644
@@ -60,6 +60,7 @@ For example::
 
 Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.
 
+
 Using Logging APIs to Generate Log Messages
 -------------------------------------------
 
@@ -140,3 +141,26 @@ To prefix all console messages with ISO format time the syntax is::
 
    Timestamp option has no effect if using syslog because the ``syslog()``
    service already does timestamping internally.
+
+
+Color output
+~~~~~~~~~~~~
+
+The log library will highlight important messages.
+This is controlled by the ``--log-color`` option.
+The optional argument describes when color is enabled:
+
+:never: Do not enable color. This is the default behavior.
+
+:auto: Enable color only when printing to a terminal.
+       This is the same as ``--log-color`` with no argument
+
+:always: Always print color
+
+For example to enable color in logs if using terminal::
+
+	/path/to/app --log-color
+
+.. note::
+
+   Color output is never used for syslog or systemd journal logging.
lib/eal/common/eal_common_options.c +11 -0
index a70d63479a..6965666a7c 100644
@@ -73,6 +73,7 @@ eal_long_options[] = {
 	{OPT_HUGE_UNLINK,       2, NULL, OPT_HUGE_UNLINK_NUM      },
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
+	{OPT_LOG_COLOR,		2, NULL, OPT_LOG_COLOR_NUM	  },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
 	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
@@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[])
 		case OPT_LOG_LEVEL_NUM:
 		case OPT_SYSLOG_NUM:
 		case OPT_LOG_TIMESTAMP_NUM:
+		case OPT_LOG_COLOR_NUM:
 			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
 				return -1;
 			break;
@@ -1859,6 +1861,14 @@ eal_parse_common_option(int opt, const char *optarg,
 		}
 		break;
 
+	case OPT_LOG_COLOR_NUM:
+		if (eal_log_color(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_COLOR);
+			return -1;
+		}
+		break;
+
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
 		if (eal_trace_args_save(optarg) < 0) {
@@ -2225,6 +2235,7 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
 	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
+	       "  --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index e24c9eca53..87c3c32f86 100644
@@ -33,6 +33,8 @@ enum {
 	OPT_HUGE_UNLINK_NUM,
 #define OPT_LCORES            "lcores"
 	OPT_LCORES_NUM,
+#define OPT_LOG_COLOR	      "log-color"
+	OPT_LOG_COLOR_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
 #define OPT_LOG_TIMESTAMP     "log-timestamp"
lib/log/log.c +17 -4
index db18690055..cd9261e55d 100644
@@ -12,6 +12,7 @@
 #include <regex.h>
 #include <fnmatch.h>
 #include <sys/queue.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -520,10 +521,22 @@ eal_log_init(const char *id)
 		if (logf)
 			rte_openlog_stream(logf);
 
-		else if (log_timestamp_enabled())
-			rte_logs.print_func = log_print_with_timestamp;
-		else
-			rte_logs.print_func = vfprintf;
+		else {
+			bool is_terminal = isatty(fileno(stderr));
+			bool use_color = log_color_enabled(is_terminal);
+
+			if (log_timestamp_enabled()) {
+				if (use_color)
+					rte_logs.print_func = color_print_with_timestamp;
+				else
+					rte_logs.print_func = log_print_with_timestamp;
+			} else {
+				if (use_color)
+					rte_logs.print_func = color_print;
+				else
+					rte_logs.print_func = vfprintf;
+			}
+		}
 	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
lib/log/log_color.c new file +214 -0

214 lines not on this page · raw message

lib/log/log_internal.h +5 -0
index 731c099984..00dde59211 100644
@@ -56,5 +56,10 @@ void rte_eal_log_cleanup(void);
 __rte_internal
 int eal_log_timestamp(const char *fmt);
 
+/*
+ * Enable or disable color in log messages
+ */
+__rte_internal
+int eal_log_color(const char *mode);
 
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +8 -0
index 37895949f6..5755cbf71f 100644
@@ -42,4 +42,12 @@ ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 __rte_format_printf(2, 0)
 int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
 
+bool log_color_enabled(bool is_tty);
+
+__rte_format_printf(2, 0)
+int color_print(FILE *f, const char *format, va_list ap);
+
+__rte_format_printf(2, 0)
+int color_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/meson.build +1 -0
index 86e4452b19..b3de57b9c7 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_color.c',
         'log_timestamp.c',
 )
 
lib/log/version.map +1 -0
index 800d3943bc..09d8a4289b 100644
@@ -25,6 +25,7 @@ DPDK_25 {
 INTERNAL {
 	global:
 
+	eal_log_color;
 	eal_log_init;
 	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
Signature · 1 line
2.45.2
#444 lore raw

PATCH v30 13/13 doc: add release note about log library

In reply to Stephen Hemminger

Significant enough to warrant a release note.

---
 doc/guides/rel_notes/release_24_11.rst | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
doc/guides/rel_notes/release_24_11.rst +20 -0
index 53a5ffebe5..b96042ea14 100644
@@ -353,6 +353,26 @@ API Changes
   and replaced it with a new shared devarg ``llq_policy`` that keeps the same logic.
 
 
+* **Logging library changes**
+
+  * The log is initialized earlier in startup so all messages go through the library.
+
+  * Added a new option to timestamp log messages, which is useful for
+    debugging delays in application and driver startup.
+
+  * If the application is a systemd service and the log output is being
+    sent to standard error then DPDK will switch to journal native protocol.
+    This allows the more data such as severity to be sent.
+
+  * The syslog option has changed. By default, messages are no longer sent
+    to syslog unless the *--syslog* option is specified.
+    Syslog is also supported on FreeBSD (but not on Windows).
+
+  * Log messages can be timestamped with *--log-timestamp* option.
+
+  * Log messages can be colorized with the *--log-color* option.
+
+
 ABI Changes
 -----------
 
Signature · 1 line
2.45.2
#445 lore raw

v31 cover Log library enhancements

In reply to Stephen Hemminger

Improvements and unification of logging library.
This version works on all platforms: Linux, Windows and FreeBSD.

This is update to rework patch set. It adds several new features to the console log output.

* Putting a timestamp on console output which is useful for analyzing performance of startup codes. Timestamp is optional and must be enabled on command line.

* Displaying console output with colors.
It uses the standard conventions used by many other Linux commands for colorized display. The default is to enable color if the console output is going to a terminal. But it can be always on or disabled by command line flag. This default was chosen based on what dmesg(1) command does.

Color is used by many tools (vi, iproute2, git) because it is helpful; DPDK drivers and libraries print lots of not very useful messages. And having error messages highlighted in bold face helps. This might also get users to pay more attention to error messages. Many bug reports have earlier messages that are lost because there are so many info messages.

* Add support for automatic detection of systemd journal protocol. If running as systemd service will get enhanced logging.

* Use of syslog is optional and the meaning of the --syslog flag has changed. The default is *not* to use unless requested.

Add Stephen as maintainer for log because by now have added more than previous authors.

Resending for CI after some small/cosmetic changes:

Changes since v30:
- added a little helper that identifies log options (this fixed a little bug with the color option being parsed twice) and
renamed eal_log_level_parse() as eal_parse_log_options(),
- adjusted log level to ALERT for EAL error on Windows,
- split RN updates in relevant patches and fixed style,
- fixed --syslog usage string,
- split and squashed Windows shim update in relevant patches,
- fixed typos,
- cleaned duplicate inclusion of headers,
- moved syslog facility code update in relevant patch,
- removed dead reference to eal_log_set_default,

Signature · 58 lines
David Marchand

David Marchand (1):
  eal: introduce log options parser

Stephen Hemminger (11):
  eal/windows: align getopt to FreeBSD
  eal: factorize parser for log level
  eal: do not log init failure twice
  eal: improve exit output log
  log: rework syslog handling
  eal: initialize log before everything else
  log: add hook for printing log messages
  log: add timestamp option
  log: support systemd journal
  log: colorize log output
  maintainers: update for log library

 MAINTAINERS                                   |   1 +
 app/test/test_eal_flags.c                     |  64 ++++-
 .../freebsd_gsg/freebsd_eal_parameters.rst    |  27 ++
 .../prog_guide/env_abstraction_layer.rst      |   6 +-
 doc/guides/prog_guide/log_lib.rst             |  58 ++++-
 doc/guides/rel_notes/release_24_11.rst        |  16 ++
 lib/eal/common/eal_common_debug.c             |   6 +-
 lib/eal/common/eal_common_options.c           | 132 ++++++----
 lib/eal/common/eal_internal_cfg.h             |   1 -
 lib/eal/common/eal_options.h                  |   6 +
 lib/eal/freebsd/eal.c                         |  63 +----
 lib/eal/linux/eal.c                           |  66 +----
 lib/eal/windows/eal.c                         |  51 +---
 lib/eal/windows/getopt.c                      |  23 +-
 lib/eal/windows/include/getopt.h              |   8 +-
 lib/eal/windows/include/rte_os_shim.h         |  12 +
 lib/log/log.c                                 |  82 ++++--
 lib/log/log_color.c                           | 214 ++++++++++++++++
 lib/log/log_freebsd.c                         |  12 -
 lib/log/log_internal.h                        |  28 +-
 lib/log/log_journal.c                         | 153 +++++++++++
 lib/log/log_linux.c                           |  61 -----
 lib/log/log_private.h                         |  57 +++++
 lib/log/log_syslog.c                          | 108 ++++++++
 lib/log/log_timestamp.c                       | 240 ++++++++++++++++++
 lib/log/log_windows.c                         |  18 --
 lib/log/meson.build                           |  12 +-
 lib/log/version.map                           |   5 +-
 28 files changed, 1171 insertions(+), 359 deletions(-)
 create mode 100644 lib/log/log_color.c
 delete mode 100644 lib/log/log_freebsd.c
 create mode 100644 lib/log/log_journal.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 create mode 100644 lib/log/log_timestamp.c
 delete mode 100644 lib/log/log_windows.c

-- 
2.47.0
#446 lore raw

PATCH v31 1/12 eal/windows: align getopt to FreeBSD

From: Stephen Hemminger <[email protected]>

Having different prototypes on different platforms can lead to lots of unnecessary workarounds. It looks like the version of getopt used from windows was based on an older out of date version from FreeBSD.

This patch changes getopt, getopt_long, etc to have the same const attributes as Linux and FreeBSD. The changes are derived from the current FreeBSD version of getopt_long.

---
 lib/eal/windows/getopt.c         | 23 ++++++++++++-----------
 lib/eal/windows/include/getopt.h |  8 ++++----
 2 files changed, 16 insertions(+), 15 deletions(-)
lib/eal/windows/getopt.c +12 -11
index a1f51c6c23..50ff71b930 100644
@@ -20,7 +20,7 @@
 #include <string.h>
 #include <stdlib.h>
 
-const char    *optarg;		/* argument associated with option */
+char    *optarg;		/* argument associated with option */
 int	opterr = 1;		/* if error message should be printed */
 int	optind = 1;		/* index into parent argv vector */
 int	optopt = '?';		/* character checked for validity */
@@ -39,9 +39,9 @@ static void pass(const char *a) {(void) a; }
 #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
 #define	INORDER		1
 
-#define	EMSG		""
+static char EMSG[] = "";
 
-static const char *place = EMSG; /* option letter processing */
+static char *place = EMSG; /* option letter processing */
 
 /* XXX: set optreset to 1 rather than these two */
 static int nonopt_start = -1; /* first non option argument (for permute) */
@@ -80,7 +80,7 @@ gcd(int a, int b)
  */
 static void
 permute_args(int panonopt_start, int panonopt_end, int opt_end,
-	char **nargv)
+	char * const *nargv)
 {
 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
 	char *swap;
@@ -101,11 +101,12 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
 				pos -= nnonopts;
 			else
 				pos += nopts;
+
 			swap = nargv[pos];
 			/* LINTED const cast */
-			((char **) nargv)[pos] = nargv[cstart];
+			((char **)(uintptr_t)nargv)[pos] = nargv[cstart];
 			/* LINTED const cast */
-			((char **)nargv)[cstart] = swap;
+			((char **)(uintptr_t)nargv)[cstart] = swap;
 		}
 	}
 }
@@ -116,7 +117,7 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
  * Returns -1 if short_too is set and the option does not match long_options.
  */
 static int
-parse_long_options(char **nargv, const char *options,
+parse_long_options(char * const *nargv, const char *options,
 	const struct option *long_options, int *idx, int short_too)
 {
 	const char *current_argv;
@@ -236,7 +237,7 @@ parse_long_options(char **nargv, const char *options,
  *	Parse argc/argv argument vector.  Called by user level routines.
  */
 static int
-getopt_internal(int nargc, char **nargv, const char *options,
+getopt_internal(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx, int flags)
 {
 	char *oli;				/* option letter list index */
@@ -434,7 +435,7 @@ getopt_internal(int nargc, char **nargv, const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt(int nargc, char *nargv[], const char *options)
+getopt(int nargc, char *const nargv[], const char *options)
 {
 	return getopt_internal(nargc, nargv, options, NULL, NULL,
 			       FLAG_PERMUTE);
@@ -445,7 +446,7 @@ getopt(int nargc, char *nargv[], const char *options)
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long(int nargc, char *nargv[], const char *options,
+getopt_long(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
@@ -458,7 +459,7 @@ getopt_long(int nargc, char *nargv[], const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long_only(int nargc, char *nargv[], const char *options,
+getopt_long_only(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
lib/eal/windows/include/getopt.h +4 -4
index 6f57af454b..e4cf6873cb 100644
@@ -44,7 +44,7 @@
 
 
 /** argument to current option, or NULL if it has none */
-extern const char *optarg;
+extern char *optarg;
 /** Current position in arg string.  Starts from 1.
  * Setting to 0 resets state.
  */
@@ -80,14 +80,14 @@ struct option {
 };
 
 /** Compat: getopt */
-int getopt(int argc, char *argv[], const char *options);
+int getopt(int argc, char *const argv[], const char *options);
 
 /** Compat: getopt_long */
-int getopt_long(int argc, char *argv[], const char *options,
+int getopt_long(int argc, char *const argv[], const char *options,
 		const struct option *longopts, int *longindex);
 
 /** Compat: getopt_long_only */
-int getopt_long_only(int nargc, char *argv[], const char *options,
+int getopt_long_only(int nargc, char *const argv[], const char *options,
 		     const struct option *long_options, int *idx);
 
 
Signature · 1 line
2.47.0
#447 lore raw

PATCH v31 2/12 eal: factorize parser for log level

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

The code to parse for log-level option should be same on all OS variants.

---
 lib/eal/common/eal_common_options.c | 40 +++++++++++++++++++++++++++
 lib/eal/common/eal_options.h        |  1 +
 lib/eal/freebsd/eal.c               | 42 -----------------------------
 lib/eal/linux/eal.c                 | 39 ---------------------------
 lib/eal/windows/eal.c               | 35 ------------------------
 5 files changed, 41 insertions(+), 116 deletions(-)
lib/eal/common/eal_common_options.c +40 -0
index f1a5e329a5..17c378f0c7 100644
@@ -1640,6 +1640,46 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
 	return -1;
 }
 
+/* Parse the arguments for --log-level only */
+int
+eal_log_level_parse(int argc, char * const argv[])
+{
+	struct internal_config *internal_conf = eal_get_internal_configuration();
+	int option_index, opt;
+	const int old_optind = optind;
+	const int old_optopt = optopt;
+	const int old_opterr = opterr;
+	char *old_optarg = optarg;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	const int old_optreset = optreset;
+	optreset = 1;
+#endif
+
+	optind = 1;
+	opterr = 0;
+
+	while ((opt = getopt_long(argc, argv, eal_short_options,
+				  eal_long_options, &option_index)) != EOF) {
+
+		switch (opt) {
+		case OPT_LOG_LEVEL_NUM:
+			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+				return -1;
+			break;
+		}
+	}
+
+	/* restore getopt lib */
+	optind = old_optind;
+	optopt = old_optopt;
+	optarg = old_optarg;
+	opterr = old_opterr;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	optreset = old_optreset;
+#endif
+	return 0;
+}
+
 int
 eal_parse_common_option(int opt, const char *optarg,
 			struct internal_config *conf)
lib/eal/common/eal_options.h +1 -0
index 3cc9cb6412..f3f2e104f6 100644
@@ -96,6 +96,7 @@ enum {
 extern const char eal_short_options[];
 extern const struct option eal_long_options[];
 
+int eal_log_level_parse(int argc, char * const argv[]);
 int eal_parse_common_option(int opt, const char *argv,
 			    struct internal_config *conf);
 int eal_option_device_parse(void);
lib/eal/freebsd/eal.c +0 -42

48 lines not on this page · raw message

lib/eal/linux/eal.c +0 -39
index 54577b7718..40d750ed0d 100644
@@ -546,45 +546,6 @@ eal_parse_vfio_vf_token(const char *vf_token)
 	return -1;
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	const int old_optind = optind;
-	const int old_optopt = optopt;
-	char * const old_optarg = optarg;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-	optind = 1;
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-				  eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg, internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	/* restore getopt lib */
-	optind = old_optind;
-	optopt = old_optopt;
-	optarg = old_optarg;
-}
-
 static int
 eal_parse_huge_worker_stack(const char *arg)
 {
lib/eal/windows/eal.c +0 -35
index 28b78a95a6..a77e590a72 100644
@@ -96,41 +96,6 @@ eal_usage(const char *prgname)
 	}
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-
-	eal_reset_internal_config(internal_conf);
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-		eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg,
-				internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	optind = 0; /* reset getopt lib */
-}
-
 /* Parse the argument given in the command line of the application */
 static int
 eal_parse_args(int argc, char **argv)
Signature · 1 line
2.47.0
#448 lore raw

PATCH v31 3/12 eal: introduce log options parser

In reply to David Marchand

Rename existing log level option parser and add a little helper tracking all options related to logs.
This will make it easier to add more log options in the next commits.

---
 lib/eal/common/eal_common_options.c | 26 ++++++++++++++++++--------
 lib/eal/common/eal_options.h        |  3 ++-
 lib/eal/freebsd/eal.c               |  8 ++++----
 lib/eal/linux/eal.c                 |  8 ++++----
 lib/eal/windows/eal.c               |  7 ++++---
 5 files changed, 32 insertions(+), 20 deletions(-)
lib/eal/common/eal_common_options.c +18 -8
index 17c378f0c7..ab6cf8bebf 100644
@@ -1640,9 +1640,20 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
 	return -1;
 }
 
-/* Parse the arguments for --log-level only */
+bool
+eal_option_is_log(int opt)
+{
+	switch (opt) {
+	case OPT_LOG_LEVEL_NUM:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* Parse all arguments looking for log related ones */
 int
-eal_log_level_parse(int argc, char * const argv[])
+eal_parse_log_options(int argc, char * const argv[])
 {
 	struct internal_config *internal_conf = eal_get_internal_configuration();
 	int option_index, opt;
@@ -1661,12 +1672,11 @@ eal_log_level_parse(int argc, char * const argv[])
 	while ((opt = getopt_long(argc, argv, eal_short_options,
 				  eal_long_options, &option_index)) != EOF) {
 
-		switch (opt) {
-		case OPT_LOG_LEVEL_NUM:
-			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
-				return -1;
-			break;
-		}
+		if (!eal_option_is_log(opt))
+			continue;
+
+		if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+			return -1;
 	}
 
 	/* restore getopt lib */
lib/eal/common/eal_options.h +2 -1
index f3f2e104f6..06ba023c5a 100644
@@ -96,7 +96,8 @@ enum {
 extern const char eal_short_options[];
 extern const struct option eal_long_options[];
 
-int eal_log_level_parse(int argc, char * const argv[]);
+bool eal_option_is_log(int opt);
+int eal_parse_log_options(int argc, char * const argv[]);
 int eal_parse_common_option(int opt, const char *argv,
 			    struct internal_config *conf);
 int eal_option_device_parse(void);
lib/eal/freebsd/eal.c +4 -4
index d3b40e81d8..8563ef1156 100644
@@ -392,8 +392,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_parse_log_options() already handled this option */
+		if (eal_option_is_log(opt))
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -574,8 +574,8 @@ rte_eal_init(int argc, char **argv)
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
+	/* parse log options as early as possible */
+	eal_parse_log_options(argc, argv);
 
 	if (rte_eal_cpu_init() < 0) {
 		rte_eal_init_alert("Cannot detect lcores.");
lib/eal/linux/eal.c +4 -4
index 40d750ed0d..9ac52ea500 100644
@@ -610,8 +610,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_parse_log_options() already handled this option */
+		if (eal_option_is_log(opt))
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -950,8 +950,8 @@ rte_eal_init(int argc, char **argv)
 
 	eal_reset_internal_config(internal_conf);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
+	/* parse log options as early as possible */
+	eal_parse_log_options(argc, argv);
 
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
lib/eal/windows/eal.c +4 -3
index a77e590a72..69d367fb8e 100644
@@ -120,8 +120,8 @@ eal_parse_args(int argc, char **argv)
 			return -1;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_parse_log_options() already handled this option */
+		if (eal_option_is_log(opt))
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -252,7 +252,8 @@ rte_eal_init(int argc, char **argv)
 
 	eal_log_init(NULL, 0);
 
-	eal_log_level_parse(argc, argv);
+	/* parse log options as early as possible */
+	eal_parse_log_options(argc, argv);
 
 	if (eal_create_cpu_map() < 0) {
 		rte_eal_init_alert("Cannot discover CPU and NUMA.");
Signature · 1 line
2.47.0
#449 lore raw

PATCH v31 4/12 eal: do not log init failure twice

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

The message already goes through logging, and does not need to be printed on stderr.
Message level should be ALERT to match function name.

---
 lib/eal/freebsd/eal.c | 3 +--
 lib/eal/linux/eal.c   | 3 +--
 lib/eal/windows/eal.c | 3 +--
 3 files changed, 3 insertions(+), 6 deletions(-)
lib/eal/freebsd/eal.c +1 -2
index 8563ef1156..11b305dc08 100644
@@ -529,8 +529,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /* Launch threads, called at application init(). */
lib/eal/linux/eal.c +1 -2
index 9ac52ea500..a6ca679cba 100644
@@ -830,8 +830,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /*
lib/eal/windows/eal.c +1 -2
index 69d367fb8e..ad02f6a6d1 100644
@@ -181,8 +181,7 @@ sync_func(void *arg __rte_unused)
 static void
 rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /* Stubs to enable EAL trace point compilation
Signature · 1 line
2.47.0
#450 lore raw

PATCH v31 5/12 eal: improve exit output log

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

The rte_exit() output format confuses the timestamp and coloring options. Change it to use be a single line with proper prefix.

Before:

[     0.006481] EAL: Error - exiting with code: 1
  Cause: [     0.006489] Cannot init EAL: Permission denied

After:

[     0.006238] EAL: Error - exiting with code: 1
[     0.006250] EAL: Cannot init EAL: Permission denied
---
 lib/eal/common/eal_common_debug.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
lib/eal/common/eal_common_debug.c +2 -4
index 3e77995896..bcfcd6df6f 100644
@@ -36,15 +36,13 @@ rte_exit(int exit_code, const char *format, ...)
 	va_list ap;
 
 	if (exit_code != 0)
-		RTE_LOG(CRIT, EAL, "Error - exiting with code: %d\n"
-				"  Cause: ", exit_code);
+		EAL_LOG(CRIT, "Error - exiting with code: %d", exit_code);
 
 	va_start(ap, format);
 	rte_vlog(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, format, ap);
 	va_end(ap);
 
 	if (rte_eal_cleanup() != 0 && rte_errno != EALREADY)
-		EAL_LOG(CRIT,
-			"EAL could not release all resources");
+		EAL_LOG(CRIT, "EAL could not release all resources");
 	exit(exit_code);
 }
Signature · 1 line
2.47.0
#451 lore raw

PATCH v31 6/12 log: rework syslog handling

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

Refactor how syslog is handled, make it common to Linux and FreeBSD The syslog facility property is better handled in lib/log rather than in eal.
This also adds syslog support to FreeBSD.

Log to syslog only if option is specified.
If no --syslog is given then use only standard error.

---
 app/test/test_eal_flags.c                     |  16 +--
 .../freebsd_gsg/freebsd_eal_parameters.rst    |  27 +++++
 .../prog_guide/env_abstraction_layer.rst      |   6 +-
 doc/guides/prog_guide/log_lib.rst             |   6 +-
 doc/guides/rel_notes/release_24_11.rst        |   6 +
 lib/eal/common/eal_common_options.c           |  57 +--------
 lib/eal/common/eal_internal_cfg.h             |   1 -
 lib/eal/freebsd/eal.c                         |   1 -
 lib/eal/linux/eal.c                           |   8 +-
 lib/eal/windows/eal.c                         |   2 +-
 lib/log/log.c                                 |  43 ++++---
 lib/log/log_freebsd.c                         |  12 --
 lib/log/log_internal.h                        |  11 +-
 lib/log/log_linux.c                           |  61 ----------
 lib/log/log_private.h                         |  27 +++++
 lib/log/log_syslog.c                          | 108 ++++++++++++++++++
 lib/log/log_windows.c                         |  18 ---
 lib/log/meson.build                           |   6 +-
 lib/log/version.map                           |   2 +-
 19 files changed, 220 insertions(+), 198 deletions(-)
 delete mode 100644 lib/log/log_freebsd.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 delete mode 100644 lib/log/log_windows.c
app/test/test_eal_flags.c +8 -8
index 71d8dba731..9fcf0d56e6 100644
@@ -985,12 +985,12 @@ test_misc_flags(void)
 	/* With -v */
 	const char *argv2[] = {prgname, prefix, mp_flag, "-v"};
 	/* With valid --syslog */
-	const char *argv3[] = {prgname, prefix, mp_flag,
-			"--syslog", "syslog"};
-	/* With empty --syslog (should fail) */
+	const char *argv3[] = {prgname, prefix, mp_flag, "--syslog=user"};
+	/* With empty --syslog (now defaults) */
 	const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"};
 	/* 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};
@@ -1080,15 +1080,15 @@ test_misc_flags(void)
 #endif
 
 	if (launch_proc(argv3) != 0) {
-		printf("Error - process did not run ok with --syslog flag\n");
+		printf("Error - process did not run ok with --syslog=user flag\n");
 		goto fail;
 	}
-	if (launch_proc(argv4) == 0) {
-		printf("Error - process run ok with empty --syslog flag\n");
+	if (launch_proc(argv4) != 0) {
+		printf("Error - process did not run ok with --syslog flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv5) == 0) {
-		printf("Error - process run ok with invalid --syslog flag\n");
+		printf("Error - process run ok with --syslog=invalid flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv7) != 0) {
doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +27 -0
index fba467a2ce..9270d9fa3b 100644
@@ -18,3 +18,30 @@ FreeBSD-specific EAL parameters
 -------------------------------
 
 There are currently no FreeBSD-specific EAL command-line parameters available.
+
+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
doc/guides/prog_guide/env_abstraction_layer.rst +3 -3
index b9fac1839d..9bafa30a0e 100644
@@ -851,9 +851,9 @@ Signal Safety
   Other functions are not signal safe because they use one or more
   library routines that are not themselves signal safe.
   For example, calling ``rte_panic()`` is not safe in a signal handler
-  because it uses ``rte_log()`` and ``rte_log()`` calls the
-  ``syslog()`` library function which is in the list of
-  signal safe functions in
+  because it uses ``rte_log()`` and ``rte_log()`` may call ``vfprintf()`` or
+  ``syslog()`` library functions which are not in the list of
+  signal safe functions
   `Signal-Safety manual page <https://man7.org/linux/man-pages/man7/signal-safety.7.html>`_.
 
   The set of functions that are expected to be async-signal-safe in DPDK
doc/guides/prog_guide/log_lib.rst +3 -3
index ff9d1b54a2..9cee75b88c 100644
@@ -5,9 +5,9 @@ Log Library
 ===========
 
 The DPDK Log library provides the logging functionality for other DPDK libraries and drivers.
-By default, in a Linux application, logs are sent to syslog and also to the console.
-On FreeBSD and Windows applications, logs are sent only to the console.
-However, the log function can be overridden by the user to use a different logging mechanism.
+By default, logs are sent only to standard error output of the process.
+The syslog EAL option can be used to redirect to the stystem logger on Linux and FreeBSD.
+In addition, the log can be redirected to a different stdio file stream.
 
 Log Levels
 ----------
doc/guides/rel_notes/release_24_11.rst +6 -0
index 9dc739c4cb..2a78396b79 100644
@@ -100,6 +100,12 @@ New Features
   (and vice versa); freeing the same pointer twice in the same routine;
   freeing an object that was not created by allocation; etc.
 
+* **Updated logging library**
+
+  * The syslog option has changed.
+    By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
+    Syslog is also supported on FreeBSD (but not on Windows).
+
 * **Updated Marvell cnxk mempool driver.**
 
   * Added mempool driver support for CN20K SoC.
lib/eal/common/eal_common_options.c +6 -51

99 lines not on this page · raw message

lib/eal/common/eal_internal_cfg.h +0 -1
index 167ec501fa..f53ab8b4aa 100644
@@ -84,7 +84,6 @@ struct internal_config {
 	/**< true if storing all pages within single files (per-page-size,
 	 * per-node) non-legacy mode only.
 	 */
-	volatile int syslog_facility;	  /**< facility passed to openlog() */
 	/** default interrupt mode for VFIO */
 	volatile enum rte_intr_mode vfio_intr_mode;
 	/** the shared VF token for VFIO-PCI bound PF and VFs devices */
lib/eal/freebsd/eal.c +0 -1
index 11b305dc08..a9f3efd0f0 100644
@@ -11,7 +11,6 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <pthread.h>
-#include <syslog.h>
 #include <getopt.h>
 #include <sys/file.h>
 #include <stddef.h>
lib/eal/linux/eal.c +1 -7
index a6ca679cba..2248881307 100644
@@ -1103,13 +1103,7 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	if (eal_log_init(program_invocation_short_name,
-			 internal_conf->syslog_facility) < 0) {
-		rte_eal_init_alert("Cannot init logging.");
-		rte_errno = ENOMEM;
-		rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
-		return -1;
-	}
+	eal_log_init(program_invocation_short_name);
 
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
lib/eal/windows/eal.c +1 -1
index ad02f6a6d1..9bd0ab5fad 100644
@@ -249,7 +249,7 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL, 0);
+	eal_log_init(NULL);
 
 	/* parse log options as early as possible */
 	eal_parse_log_options(argc, argv);
lib/log/log.c +20 -23

90 lines not on this page · raw message

lib/log/log_freebsd.c deleted +0 -12
deleted file mode 100644
index 698d3c5423..0000000000
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2023 Intel Corporation
- */
-
-#include <rte_common.h>
-#include "log_internal.h"
-
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	return 0;
-}
lib/log/log_internal.h +4 -7
index 451629f1c1..3c46328e7b 100644
@@ -14,13 +14,7 @@
  * Initialize the default log stream.
  */
 __rte_internal
-int eal_log_init(const char *id, int facility);
-
-/*
- * Determine where log data is written when no call to rte_openlog_stream.
- */
-__rte_internal
-void eal_log_set_default(FILE *default_log);
+void eal_log_init(const char *id);
 
 /*
  * Save a log option for later.
@@ -30,6 +24,9 @@ int eal_log_save_regexp(const char *regexp, uint32_t level);
 __rte_internal
 int eal_log_save_pattern(const char *pattern, uint32_t level);
 
+__rte_internal
+int eal_log_syslog(const char *name);
+
 /*
  * Convert log level to string.
  */
lib/log/log_linux.c deleted +0 -61

61 lines not on this page · raw message

lib/log/log_private.h new file +27 -0
new file mode 100644
index 0000000000..d5a8bf271a
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#ifndef LOG_PRIVATE_H
+#define LOG_PRIVATE_H
+
+/* Defined in limits.h on Linux */
+#ifndef LINE_MAX
+#define LINE_MAX	2048 /* _POSIX2_LINE_MAX */
+#endif
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+static inline bool
+log_syslog_enabled(void)
+{
+	return false;
+}
+static inline FILE *
+log_syslog_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#else
+bool log_syslog_enabled(void);
+FILE *log_syslog_open(const char *id);
+#endif
+
+#endif /* LOG_PRIVATE_H */
lib/log/log_syslog.c new file +108 -0

108 lines not on this page · raw message

lib/log/log_windows.c deleted +0 -18
deleted file mode 100644
index a6a0889550..0000000000
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2017-2018 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_log.h>
-#include "log_internal.h"
-
-/* set the log to default function, called during eal init process. */
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	rte_openlog_stream(stderr);
-
-	eal_log_set_default(stderr);
-
-	return 0;
-}
lib/log/meson.build +5 -1
index 0d4319b36f..160cf34f50 100644
@@ -4,6 +4,10 @@
 includes += global_inc
 sources = files(
         'log.c',
-        'log_' + exec_env + '.c',
 )
+
+if not is_windows
+    sources += files('log_syslog.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -1
index 19d7f9cdb6..1637fba3b9 100644
@@ -29,6 +29,6 @@ INTERNAL {
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
-	eal_log_set_default;
+	eal_log_syslog; # WINDOWS_NO_EXPORT
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.47.0
#452 lore raw

PATCH v31 7/12 eal: initialize log before everything else

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

In order for all log messages (including CPU mismatch) to come out through the logging library, it must be initialized as early in rte_eal_init() as possible on all platforms.

Where it was done before was likely historical, based on the support of non-OS isolated CPU's which required a shared memory buffer. That support was dropped before DPDK was publicly released.

---
 doc/guides/rel_notes/release_24_11.rst |  2 ++
 lib/eal/freebsd/eal.c                  | 13 ++++++++++---
 lib/eal/linux/eal.c                    | 14 +++++++++-----
 lib/eal/windows/eal.c                  | 10 +++++++---
 4 files changed, 28 insertions(+), 11 deletions(-)
doc/guides/rel_notes/release_24_11.rst +2 -0
index 2a78396b79..7da3c99dec 100644
@@ -102,6 +102,8 @@ New Features
 
 * **Updated logging library**
 
+  * The log subsystem is initialized earlier in startup so all messages go through the library.
+
   * The syslog option has changed.
     By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
     Syslog is also supported on FreeBSD (but not on Windows).
lib/eal/freebsd/eal.c +10 -3
index a9f3efd0f0..c31a3858dd 100644
@@ -52,6 +52,7 @@
 #include "eal_options.h"
 #include "eal_memcfg.h"
 #include "eal_trace.h"
+#include "log_internal.h"
 
 #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
 
@@ -546,6 +547,15 @@ rte_eal_init(int argc, char **argv)
 	bool has_phys_addr;
 	enum rte_iova_mode iova_mode;
 
+	/* setup log as early as possible */
+	if (eal_parse_log_options(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(getprogname());
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -572,9 +582,6 @@ rte_eal_init(int argc, char **argv)
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
-	/* parse log options as early as possible */
-	eal_parse_log_options(argc, argv);
-
 	if (rte_eal_cpu_init() < 0) {
 		rte_eal_init_alert("Cannot detect lcores.");
 		rte_errno = ENOTSUP;
lib/eal/linux/eal.c +9 -5
index 2248881307..b3aae7393d 100644
@@ -926,6 +926,15 @@ rte_eal_init(int argc, char **argv)
 	struct internal_config *internal_conf =
 		eal_get_internal_configuration();
 
+	/* setup log as early as possible */
+	if (eal_parse_log_options(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(program_invocation_short_name);
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -949,9 +958,6 @@ rte_eal_init(int argc, char **argv)
 
 	eal_reset_internal_config(internal_conf);
 
-	/* parse log options as early as possible */
-	eal_parse_log_options(argc, argv);
-
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
@@ -1103,8 +1109,6 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	eal_log_init(program_invocation_short_name);
-
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
 		rte_eal_init_alert("Cannot init VFIO");
lib/eal/windows/eal.c +7 -3
index 9bd0ab5fad..1892290f89 100644
@@ -249,10 +249,14 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL);
+	/* setup log as early as possible */
+	if (eal_parse_log_options(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
 
-	/* parse log options as early as possible */
-	eal_parse_log_options(argc, argv);
+	eal_log_init(NULL);
 
 	if (eal_create_cpu_map() < 0) {
 		rte_eal_init_alert("Cannot discover CPU and NUMA.");
Signature · 1 line
2.47.0
#453 lore raw

PATCH v31 8/12 log: add hook for printing log messages

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

This is useful for when decorating log output for console or journal. Provide basic version in this patch.

---
 lib/log/log.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
lib/log/log.c +7 -1
index a5cae1f950..dbff223108 100644
@@ -29,16 +29,21 @@ struct rte_log_dynamic_type {
 	uint32_t loglevel;
 };
 
+/* Note: same as vfprintf() */
+typedef int (*log_print_t)(FILE *f, const char *fmt, 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. */
+	log_print_t print_func;
 	size_t dynamic_types_len;
 	struct rte_log_dynamic_type *dynamic_types;
 } rte_logs = {
 	.type = UINT32_MAX,
 	.level = RTE_LOG_DEBUG,
+	.print_func = vfprintf,
 };
 
 struct rte_eal_opt_loglevel {
@@ -75,6 +80,7 @@ int
 rte_openlog_stream(FILE *f)
 {
 	rte_logs.file = f;
+	rte_logs.print_func = vfprintf;
 	return 0;
 }
 
@@ -471,7 +477,7 @@ rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap)
 	RTE_PER_LCORE(log_cur_msg).loglevel = level;
 	RTE_PER_LCORE(log_cur_msg).logtype = logtype;
 
-	ret = vfprintf(f, format, ap);
+	ret = (*rte_logs.print_func)(f, format, ap);
 	fflush(f);
 	return ret;
 }
Signature · 1 line
2.47.0
#454 lore raw

PATCH v31 9/12 log: add timestamp option

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

When debugging driver or startup issues, it is useful to have a timestamp on each message printed.
The messages in syslog already have a timestamp, but often syslog is not available during testing.

There are multiple timestamp formats similar to Linux dmesg. The default is time relative since startup (when first step of logging initialization is done by constructor).
Other alternative formats are delta, ctime, reltime and iso formats.

Example:

$ dpdk-testpmd --log-timestamp -- -i
[     0.008610] EAL: Detected CPU lcores: 8
[     0.008634] EAL: Detected NUMA nodes: 1
[     0.008792] EAL: Detected static linkage of DPDK
[     0.010620] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
[     0.012618] EAL: Selected IOVA mode 'VA'
[     0.016675] testpmd: No probed ethernet devices
Interactive-mode selected

Note: Windows does not have localtime_r but it does have a similar function that can be used instead. Add it to rte_os_shim.h.

---
 app/test/test_eal_flags.c              |  24 +++
 doc/guides/prog_guide/log_lib.rst      |  28 +++
 doc/guides/rel_notes/release_24_11.rst |   2 +
 lib/eal/common/eal_common_options.c    |  14 +-
 lib/eal/common/eal_options.h           |   2 +
 lib/eal/windows/include/rte_os_shim.h  |  10 ++
 lib/log/log.c                          |  13 +-
 lib/log/log_internal.h                 |   9 +
 lib/log/log_private.h                  |   6 +
 lib/log/log_timestamp.c                | 240 +++++++++++++++++++++++++
 lib/log/meson.build                    |   1 +
 lib/log/version.map                    |   1 +
 12 files changed, 344 insertions(+), 6 deletions(-)
 create mode 100644 lib/log/log_timestamp.c
app/test/test_eal_flags.c +24 -0
index 9fcf0d56e6..1a062fe0e8 100644
@@ -1055,6 +1055,18 @@ test_misc_flags(void)
 	const char * const argv22[] = {prgname, prefix, mp_flag,
 				       "--huge-worker-stack=512"};
 
+	/* Try running with --log-timestamp */
+	const char * const argv23[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp" };
+
+	/* Try running with --log-timestamp=iso */
+	const char * const argv24[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=iso" };
+
+	/* Try running with invalid timestamp */
+	const char * const argv25[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=invalid" };
+
 	/* run all tests also applicable to FreeBSD first */
 
 	if (launch_proc(argv0) == 0) {
@@ -1162,6 +1174,18 @@ test_misc_flags(void)
 		printf("Error - process did not run ok with --huge-worker-stack=size parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv23) != 0) {
+		printf("Error - process did not run ok with --log-timestamp parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv24) != 0) {
+		printf("Error - process did not run ok with --log-timestamp=iso parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv25) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
 
 	rmdir(hugepath_dir3);
 	rmdir(hugepath_dir2);
doc/guides/prog_guide/log_lib.rst +28 -0
index 9cee75b88c..a2e95317f5 100644
@@ -110,3 +110,31 @@ Throughout the cfgfile library, all logging calls are therefore of the form:
 
 	CFG_LOG(ERR, "invalid comment characters %c",
 	       params->comment_character);
+
+Log timestamp
+~~~~~~~~~~~~~
+
+An optional timestamp can be added before each message by adding the ``--log-timestamp`` option.
+For example::
+
+	/path/to/app --log-level=lib.*:debug --log-timestamp
+
+Multiple alternative timestamp formats are available:
+
+.. csv-table:: Log time stamp format
+   :header: "Format", "Description", "Example"
+   :widths: 6, 30, 32
+
+   "ctime", "Unix ctime", "``[Wed Mar 20 07:26:12 2024]``"
+   "delta", "Offset since last", "``[<    3.162373>]``"
+   "reltime", "Seconds since last or time if minute changed", "``[  +3.001791]`` or ``[Mar20 07:26:12]``"
+   "iso", "ISO-8601", "``[2024-03-20T07:26:12−07:00]``"
+
+To prefix all console messages with ISO format time the syntax is::
+
+	/path/to/app --log-timestamp=iso
+
+.. note::
+
+   Timestamp option has no effect if using syslog
+   because the ``syslog()`` service already does timestamping internally.
doc/guides/rel_notes/release_24_11.rst +2 -0
index 7da3c99dec..c7504c4ecd 100644
@@ -108,6 +108,8 @@ New Features
     By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
     Syslog is also supported on FreeBSD (but not on Windows).
 
+  * Log messages can be timestamped with ``--log-timestamp`` option.
+
 * **Updated Marvell cnxk mempool driver.**
 
   * Added mempool driver support for CN20K SoC.
lib/eal/common/eal_common_options.c +12 -2
index 9f4feb2611..7de6a25e62 100644
@@ -74,6 +74,7 @@ eal_long_options[] = {
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
+	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
 	{OPT_TRACE_DIR,         1, NULL, OPT_TRACE_DIR_NUM        },
 	{OPT_TRACE_BUF_SIZE,    1, NULL, OPT_TRACE_BUF_SIZE_NUM   },
@@ -1599,6 +1600,7 @@ eal_option_is_log(int opt)
 {
 	switch (opt) {
 	case OPT_LOG_LEVEL_NUM:
+	case OPT_LOG_TIMESTAMP_NUM:
 	case OPT_SYSLOG_NUM:
 		return true;
 	default:
@@ -1850,7 +1852,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		break;
 #endif
 
-	case OPT_LOG_LEVEL_NUM: {
+	case OPT_LOG_LEVEL_NUM:
 		if (eal_parse_log_level(optarg) < 0) {
 			EAL_LOG(ERR,
 				"invalid parameters for --"
@@ -1858,7 +1860,14 @@ eal_parse_common_option(int opt, const char *optarg,
 			return -1;
 		}
 		break;
-	}
+
+	case OPT_LOG_TIMESTAMP_NUM:
+		if (eal_log_timestamp(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_TIMESTAMP);
+			return -1;
+		}
+		break;
 
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
@@ -2225,6 +2234,7 @@ eal_common_usage(void)
 	       "  --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
+	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index 06ba023c5a..a1b52ae694 100644
@@ -35,6 +35,8 @@ enum {
 	OPT_LCORES_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
+#define OPT_LOG_TIMESTAMP     "log-timestamp"
+	OPT_LOG_TIMESTAMP_NUM,
 #define OPT_TRACE             "trace"
 	OPT_TRACE_NUM,
 #define OPT_TRACE_DIR         "trace-dir"
lib/eal/windows/include/rte_os_shim.h +10 -0
index eda8113662..665c9ac93b 100644
@@ -110,4 +110,14 @@ rte_clock_gettime(clockid_t clock_id, struct timespec *tp)
 }
 #define clock_gettime(clock_id, tp) rte_clock_gettime(clock_id, tp)
 
+static inline struct tm *
+rte_localtime_r(const time_t *timep, struct tm *result)
+{
+	if (localtime_s(result, timep) == 0)
+		return result;
+	else
+		return NULL;
+}
+#define localtime_r(timep, result) rte_localtime_r(timep, result)
+
 #endif /* _RTE_OS_SHIM_ */
lib/log/log.c +9 -4
index dbff223108..854d77887b 100644
@@ -17,13 +17,13 @@
 #include <rte_log.h>
 #include <rte_per_lcore.h>
 
-#include "log_internal.h"
-#include "log_private.h"
-
 #ifdef RTE_EXEC_ENV_WINDOWS
-#define strdup _strdup
+#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;
@@ -513,6 +513,11 @@ eal_log_init(const char *id)
 	if (logf)
 		rte_openlog_stream(logf);
 
+	if (log_timestamp_enabled())
+		rte_logs.print_func = log_print_with_timestamp;
+	else
+		rte_logs.print_func = vfprintf;
+
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
 		"Debug dataplane logs available - lower performance\n");
lib/log/log_internal.h +9 -0
index 3c46328e7b..7c7d44eed2 100644
@@ -5,8 +5,10 @@
 #ifndef LOG_INTERNAL_H
 #define LOG_INTERNAL_H
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <time.h>
 
 #include <rte_compat.h>
 
@@ -39,4 +41,11 @@ const char *eal_log_level2str(uint32_t level);
 __rte_internal
 void rte_eal_log_cleanup(void);
 
+/*
+ * Add timestamp to console logs
+ */
+__rte_internal
+int eal_log_timestamp(const char *fmt);
+
+
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +6 -0
index d5a8bf271a..5da9c9b438 100644
@@ -24,4 +24,10 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+bool log_timestamp_enabled(void);
+ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
+
+__rte_format_printf(2, 0)
+int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/log_timestamp.c new file +240 -0

240 lines not on this page · raw message

lib/log/meson.build +1 -0
index 160cf34f50..4ac232786e 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_timestamp.c',
 )
 
 if not is_windows
lib/log/version.map +1 -0
index 1637fba3b9..8be6907840 100644
@@ -30,5 +30,6 @@ INTERNAL {
 	eal_log_save_pattern;
 	eal_log_save_regexp;
 	eal_log_syslog; # WINDOWS_NO_EXPORT
+	eal_log_timestamp;
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.47.0
#455 lore raw

PATCH v31 10/12 log: support systemd journal

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

If DPDK application is being run as a systemd service, then it can use the journal protocol which allows putting more information in the log such as priority and other information.

The use of journal protocol is automatically detected and handled. Rather than having a dependency on libsystemd, just use the protocol directly as defined in:
https://systemd.io/JOURNAL_NATIVE_PROTOCOL/

---
 doc/guides/rel_notes/release_24_11.rst |   4 +
 lib/log/log.c                          |  31 +++--
 lib/log/log_internal.h                 |   3 +
 lib/log/log_journal.c                  | 153 +++++++++++++++++++++++++
 lib/log/log_private.h                  |  16 +++
 lib/log/meson.build                    |   4 +
 lib/log/version.map                    |   1 +
 7 files changed, 200 insertions(+), 12 deletions(-)
 create mode 100644 lib/log/log_journal.c
doc/guides/rel_notes/release_24_11.rst +4 -0
index c7504c4ecd..a9ca444ee8 100644
@@ -104,6 +104,10 @@ New Features
 
   * The log subsystem is initialized earlier in startup so all messages go through the library.
 
+  * If the application is a systemd service and the log output is being sent to standard error
+    then DPDK will switch to journal native protocol.
+    This allows the more data such as severity to be sent.
+
   * The syslog option has changed.
     By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
     Syslog is also supported on FreeBSD (but not on Windows).
lib/log/log.c +19 -12
index 854d77887b..0974adc81f 100644
@@ -505,18 +505,25 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...)
 void
 eal_log_init(const char *id)
 {
-	FILE *logf = NULL;
-
-	if (log_syslog_enabled())
-		logf = log_syslog_open(id);
-
-	if (logf)
-		rte_openlog_stream(logf);
-
-	if (log_timestamp_enabled())
-		rte_logs.print_func = log_print_with_timestamp;
-	else
-		rte_logs.print_func = vfprintf;
+	/* If user has already set a log stream, then use it. */
+	if (rte_logs.file == NULL) {
+		FILE *logf = NULL;
+
+		/* if stderr is associated with systemd environment */
+		if (log_journal_enabled())
+			logf = log_journal_open(id);
+		/* If --syslog option was passed */
+		else if (log_syslog_enabled())
+			logf = log_syslog_open(id);
+
+		/* if either syslog or journal is used, then no special handling */
+		if (logf)
+			rte_openlog_stream(logf);
+		else if (log_timestamp_enabled())
+			rte_logs.print_func = log_print_with_timestamp;
+		else
+			rte_logs.print_func = vfprintf;
+	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
lib/log/log_internal.h +3 -0
index 7c7d44eed2..82fdc21ac2 100644
@@ -29,6 +29,9 @@ int eal_log_save_pattern(const char *pattern, uint32_t level);
 __rte_internal
 int eal_log_syslog(const char *name);
 
+__rte_internal
+int eal_log_journal(const char *opt);
+
 /*
  * Convert log level to string.
  */
lib/log/log_journal.c new file +153 -0

153 lines not on this page · raw message

lib/log/log_private.h +16 -0
index 5da9c9b438..1b66057fd6 100644
@@ -24,6 +24,22 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+#ifdef RTE_EXEC_ENV_LINUX
+bool log_journal_enabled(void);
+FILE *log_journal_open(const char *id);
+#else
+static inline bool
+log_journal_enabled(void)
+{
+	return false;
+}
+static inline FILE *
+log_journal_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#endif /* !RTE_EXEC_ENV_LINUX */
+
 bool log_timestamp_enabled(void);
 ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 
lib/log/meson.build +4 -0
index 4ac232786e..86e4452b19 100644
@@ -11,4 +11,8 @@ if not is_windows
     sources += files('log_syslog.c')
 endif
 
+if is_linux
+    sources += files('log_journal.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -0
index 8be6907840..800d3943bc 100644
@@ -26,6 +26,7 @@ INTERNAL {
 	global:
 
 	eal_log_init;
+	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
Signature · 1 line
2.47.0
#456 lore raw

PATCH v31 11/12 log: colorize log output

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

Like dmesg, colorize the log output (unless redirected to file). Timestamp is green, the subsystem is in yellow and the message is red if urgent, boldface if an error, and normal for info and debug messages.

The default is to not use color since it may disturb automatic tests and other embedded usage.

Note: add fileno() and isatty() to the Windows wrapper.

---
 app/test/test_eal_flags.c              |  24 +++
 doc/guides/prog_guide/log_lib.rst      |  24 +++
 doc/guides/rel_notes/release_24_11.rst |   2 +
 lib/eal/common/eal_common_options.c    |  11 ++
 lib/eal/common/eal_options.h           |   2 +
 lib/eal/windows/include/rte_os_shim.h  |   2 +
 lib/log/log.c                          |  23 ++-
 lib/log/log_color.c                    | 214 +++++++++++++++++++++++++
 lib/log/log_internal.h                 |   5 +
 lib/log/log_private.h                  |   8 +
 lib/log/meson.build                    |   1 +
 lib/log/version.map                    |   1 +
 12 files changed, 312 insertions(+), 5 deletions(-)
 create mode 100644 lib/log/log_color.c
app/test/test_eal_flags.c +24 -0
index 1a062fe0e8..d37d6b8627 100644
@@ -1067,6 +1067,18 @@ test_misc_flags(void)
 	const char * const argv25[] = {prgname, prefix, mp_flag,
 				       "--log-timestamp=invalid" };
 
+	/* Try running with --log-color */
+	const char * const argv26[] = {prgname, prefix, mp_flag,
+				       "--log-color" };
+
+	/* Try running with --log-color=never */
+	const char * const argv27[] = {prgname, prefix, mp_flag,
+				       "--log-color=never" };
+
+	/* Try running with --log-color=invalid */
+	const char * const argv28[] = {prgname, prefix, mp_flag,
+				       "--log-color=invalid" };
+
 	/* run all tests also applicable to FreeBSD first */
 
 	if (launch_proc(argv0) == 0) {
@@ -1186,6 +1198,18 @@ test_misc_flags(void)
 		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv26) != 0) {
+		printf("Error - process did not run ok with --log-color parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv27) != 0) {
+		printf("Error - process did not run ok with --log-color=never parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv28) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
 
 	rmdir(hugepath_dir3);
 	rmdir(hugepath_dir2);
doc/guides/prog_guide/log_lib.rst +24 -0
index a2e95317f5..3e888b8965 100644
@@ -59,6 +59,7 @@ For example::
 
 Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.
 
+
 Using Logging APIs to Generate Log Messages
 -------------------------------------------
 
@@ -138,3 +139,26 @@ To prefix all console messages with ISO format time the syntax is::
 
    Timestamp option has no effect if using syslog
    because the ``syslog()`` service already does timestamping internally.
+
+
+Color output
+~~~~~~~~~~~~
+
+The log library will highlight important messages.
+This is controlled by the ``--log-color`` option.
+The optional argument describes when color is enabled:
+
+:never: Do not enable color. This is the default behavior.
+
+:auto: Enable color only when printing to a terminal.
+       This is the same as ``--log-color`` with no argument.
+
+:always: Always print color.
+
+For example to enable color in logs if using terminal::
+
+	/path/to/app --log-color
+
+.. note::
+
+   Color output is never used for syslog or systemd journal logging.
doc/guides/rel_notes/release_24_11.rst +2 -0
index a9ca444ee8..23eb3f574b 100644
@@ -114,6 +114,8 @@ New Features
 
   * Log messages can be timestamped with ``--log-timestamp`` option.
 
+  * Log messages can be colorized with the ``--log-color`` option.
+
 * **Updated Marvell cnxk mempool driver.**
 
   * Added mempool driver support for CN20K SoC.
lib/eal/common/eal_common_options.c +11 -0
index 7de6a25e62..79db9a47dd 100644
@@ -73,6 +73,7 @@ eal_long_options[] = {
 	{OPT_HUGE_UNLINK,       2, NULL, OPT_HUGE_UNLINK_NUM      },
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
+	{OPT_LOG_COLOR,		2, NULL, OPT_LOG_COLOR_NUM	  },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
 	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
@@ -1599,6 +1600,7 @@ bool
 eal_option_is_log(int opt)
 {
 	switch (opt) {
+	case OPT_LOG_COLOR_NUM:
 	case OPT_LOG_LEVEL_NUM:
 	case OPT_LOG_TIMESTAMP_NUM:
 	case OPT_SYSLOG_NUM:
@@ -1869,6 +1871,14 @@ eal_parse_common_option(int opt, const char *optarg,
 		}
 		break;
 
+	case OPT_LOG_COLOR_NUM:
+		if (eal_log_color(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_COLOR);
+			return -1;
+		}
+		break;
+
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
 		if (eal_trace_args_save(optarg) < 0) {
@@ -2235,6 +2245,7 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
 	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
+	       "  --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index a1b52ae694..95fb4f6108 100644
@@ -33,6 +33,8 @@ enum {
 	OPT_HUGE_UNLINK_NUM,
 #define OPT_LCORES            "lcores"
 	OPT_LCORES_NUM,
+#define OPT_LOG_COLOR	      "log-color"
+	OPT_LOG_COLOR_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
 #define OPT_LOG_TIMESTAMP     "log-timestamp"
lib/eal/windows/include/rte_os_shim.h +2 -0
index 665c9ac93b..0e74eb19c7 100644
@@ -30,6 +30,8 @@
 #define write(fd, buf, n) _write(fd, buf, n)
 #define close(fd) _close(fd)
 #define unlink(path) _unlink(path)
+#define fileno(f) _fileno(f)
+#define isatty(fd) _isatty(fd)
 
 #define IPVERSION	4
 
lib/log/log.c +18 -5
index 0974adc81f..eb087d601e 100644
@@ -12,6 +12,7 @@
 #include <regex.h>
 #include <fnmatch.h>
 #include <sys/queue.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -517,12 +518,24 @@ eal_log_init(const char *id)
 			logf = log_syslog_open(id);
 
 		/* if either syslog or journal is used, then no special handling */
-		if (logf)
+		if (logf) {
 			rte_openlog_stream(logf);
-		else if (log_timestamp_enabled())
-			rte_logs.print_func = log_print_with_timestamp;
-		else
-			rte_logs.print_func = vfprintf;
+		} else {
+			bool is_terminal = isatty(fileno(stderr));
+			bool use_color = log_color_enabled(is_terminal);
+
+			if (log_timestamp_enabled()) {
+				if (use_color)
+					rte_logs.print_func = color_print_with_timestamp;
+				else
+					rte_logs.print_func = log_print_with_timestamp;
+			} else {
+				if (use_color)
+					rte_logs.print_func = color_print;
+				else
+					rte_logs.print_func = vfprintf;
+			}
+		}
 	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
lib/log/log_color.c new file +214 -0

214 lines not on this page · raw message

lib/log/log_internal.h +5 -0
index 82fdc21ac2..bba7041ea3 100644
@@ -50,5 +50,10 @@ void rte_eal_log_cleanup(void);
 __rte_internal
 int eal_log_timestamp(const char *fmt);
 
+/*
+ * Enable or disable color in log messages
+ */
+__rte_internal
+int eal_log_color(const char *mode);
 
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +8 -0
index 1b66057fd6..f275346c7b 100644
@@ -46,4 +46,12 @@ ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 __rte_format_printf(2, 0)
 int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
 
+bool log_color_enabled(bool is_tty);
+
+__rte_format_printf(2, 0)
+int color_print(FILE *f, const char *format, va_list ap);
+
+__rte_format_printf(2, 0)
+int color_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/meson.build +1 -0
index 86e4452b19..b3de57b9c7 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_color.c',
         'log_timestamp.c',
 )
 
lib/log/version.map +1 -0
index 800d3943bc..09d8a4289b 100644
@@ -25,6 +25,7 @@ DPDK_25 {
 INTERNAL {
 	global:
 
+	eal_log_color;
 	eal_log_init;
 	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
Signature · 1 line
2.47.0
#457 lore raw

PATCH v31 12/12 maintainers: update for log library

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

"You touch it you own it".
Add myself as maintainer for log library.

---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)
MAINTAINERS +1 -0
index 8919d78919..94530c97b0 100644
@@ -193,6 +193,7 @@ F: app/test/test_threads.c
 F: app/test/test_version.c
 
 Logging
+M: Stephen Hemminger <[email protected]>
 F: lib/log/
 F: doc/guides/prog_guide/log_lib.rst
 F: app/test/test_logs.c
Signature · 1 line
2.47.0
#458 lore raw

Re: [PATCH v31 00/12] Log library enhancements

In reply to David Marchand
Quoted 39 lines · David Marchand

Improvements and unification of logging library.
This version works on all platforms: Linux, Windows and FreeBSD.

This is update to rework patch set. It adds several new features to the console log output.

* Putting a timestamp on console output which is useful for analyzing performance of startup codes. Timestamp is optional and must be enabled on command line.

* Displaying console output with colors.
It uses the standard conventions used by many other Linux commands for colorized display. The default is to enable color if the console output is going to a terminal. But it can be always on or disabled by command line flag. This default was chosen based on what dmesg(1) command does.

Color is used by many tools (vi, iproute2, git) because it is helpful; DPDK drivers and libraries print lots of not very useful messages. And having error messages highlighted in bold face helps. This might also get users to pay more attention to error messages. Many bug reports have earlier messages that are lost because there are so many info messages.

* Add support for automatic detection of systemd journal protocol. If running as systemd service will get enhanced logging.

* Use of syslog is optional and the meaning of the --syslog flag has changed. The default is *not* to use unless requested.

Add Stephen as maintainer for log because by now have added more than previous authors.

Resending for CI after some small/cosmetic changes:

Quoted 12 lines

Changes since v30:
- added a little helper that identifies log options (this fixed a little bug with the color option being parsed twice) and
renamed eal_log_level_parse() as eal_parse_log_options(),
- adjusted log level to ALERT for EAL error on Windows,
- split RN updates in relevant patches and fixed style,
- fixed --syslog usage string,
- split and squashed Windows shim update in relevant patches,
- fixed typos,
- cleaned duplicate inclusion of headers,
- moved syslog facility code update in relevant patch,
- removed dead reference to eal_log_set_default,

The escape character \e is refused with MSVC.

This had been reported as a warning starting v26 iiuc:

==== 20 line log output for Windows Server 2022 (dpdk_msvc_compile): ====
...
[ 3 5 / 9 6 ] C o m p i l i n g C o b j e c t l i b / l i b
r t e _ l o g . a . p / l o g _ l o g _ c o l o r . c . o b j
F A I L E D : l i b / l i b r t e _ l o g . a . p / l o g _ l o g
_ c o l o r . c . o b j
" c l " " - I l i b \ l i b r t e _ l o g . a . p " " - I l i b
" " - I . . \ l i b " " - I . " " - I . . " " - I c o n f i g
" " - I . . \ c o n f i g " " - I l i b \ e a l \ i n c l u d e "
" - I . . \ l i b \ e a l \ i n c l u d e " " - I l i b \ e a l \ w
i n d o w s \ i n c l u d e " " - I . . \ l i b \ e a l \ w i n d o
w s \ i n c l u d e " " - I l i b \ e a l \ x 8 6 \ i n c l u d e "
" - I . . \ l i b \ e a l \ x 8 6 \ i n c l u d e " " - I l i b \ l
o g " " - I . . \ l i b \ l o g " " - I C : \ P r o g r a m F i
l e s \ M e l l a n o x \ M L N X _ W i n O F 2 _ D e v X _ S D K \ i
n c " " / M D " " / n o l o g o " " / s h o w I n c l u d e s "
" / W 3 " " / W X " " / s t d : c 1 1 " " / O 2 " " / G w "
" / w d 4 2 4 4 " " / w d 4 2 6 7 " " / w d 4 1 4 6 " " / e x p
e r i m e n t a l : c 1 1 a t o m i c s " " / d 1 e x p e r i m e n
t a l : t y p e o f " " / e x p e r i m e n t a l : s t a t e m e n
t E x p r e s
s i o n s " " / F I " " r t e _ c o n f i g . h " " - D _ G N
U _ S O U R C E " " - D _ W I N 3 2 _ W I N N T = 0 x 0 A 0 0 " "
- D A L L O W _ E X P E R I M E N T A L _ A P I " " - D A L L O W _
I N T E R N A L _ A P I " " - D R T E _ L O G _ D E F A U L T _ L O
G T Y P E = l i b . l o g " " / F d l i b \ l i b r t e _ l o g . a
. p \ l o g _ l o g _ c o l o r . c . p d b " / F o l i b / l i b r
t e _ l o g . a . p / l o g _ l o g _ c o l o r . c . o b j " / c "
. . / l i b / l o g / l o g _ c o l o r . c
. . / l i b / l o g / l o g _ c o l o r . c ( 8 6 ) : e r r o r
C 2 2 2 0 : t h e f o l l o w i n g w a r n i n g i s t r e
a t e d a s a n e r r o r
. . / l i b / l o g / l o g _ c o l o r . c ( 8 6 ) : w a r n i n

g   C 4 1 2 9 :   ' e ' :   u n r e c o g n i z e d   c h a r a c t e
r   e s c a p e   s e q u e n c e
  . . / l i b / l o g / l o g _ c o l o r . c ( 8 6 ) :   w a r n i n
g   C 4 1 2 9 :   ' e ' :   u n r e c o g n i z e d   c h a r a c t e
r   e s c a p e   s e q u e n c e
  . . / l i b / l o g / l o g _ c o l o r . c ( 8 8 ) :   w a r n i n
g   C 4 1 2 9 :   ' e ' :   u n r e c o g n i z e d   c h a r a c t e
r   e s c a p e   s e q u e n c e

Respinning the series with \033 (that was used until v25) and we should be good.

Signature · 1 line
David Marchand
#459 lore raw

v31 cover Log library enhancements

In reply to Stephen Hemminger

Improvements and unification of logging library.
This version works on all platforms: Linux, Windows and FreeBSD.

This is update to rework patch set. It adds several new features to the console log output.

* Putting a timestamp on console output which is useful for analyzing performance of startup codes. Timestamp is optional and must be enabled on command line.

* Displaying console output with colors.
It uses the standard conventions used by many other Linux commands for colorized display. The default is to enable color if the console output is going to a terminal. But it can be always on or disabled by command line flag. This default was chosen based on what dmesg(1) command does.

Color is used by many tools (vi, iproute2, git) because it is helpful; DPDK drivers and libraries print lots of not very useful messages. And having error messages highlighted in bold face helps. This might also get users to pay more attention to error messages. Many bug reports have earlier messages that are lost because there are so many info messages.

* Add support for automatic detection of systemd journal protocol. If running as systemd service will get enhanced logging.

* Use of syslog is optional and the meaning of the --syslog flag has changed. The default is *not* to use unless requested.

Add Stephen as maintainer for log because by now have added more than previous authors.

Resending for CI:

Changes since v31:
- rebased,
- fixed build with MSVC: escape character was restored to \033 (used until v25) instead of \e,

Changes since v30:
- added a little helper that identifies log options (this fixed a little bug with the color option being parsed twice) and
renamed eal_log_level_parse() as eal_parse_log_options(),
- adjusted log level to ALERT for EAL error on Windows,
- split RN updates in relevant patches and fixed style,
- fixed --syslog usage string,
- split and squashed Windows shim update in relevant patches,
- fixed typos,
- cleaned duplicate inclusion of headers,
- moved syslog facility code update in relevant patch,
- removed dead reference to eal_log_set_default,

Signature · 58 lines
David Marchand

David Marchand (1):
  eal: introduce log options parser

Stephen Hemminger (11):
  eal/windows: align getopt to FreeBSD
  eal: factorize parser for log level
  eal: do not log init failure twice
  eal: improve exit output log
  log: rework syslog handling
  eal: initialize log before everything else
  log: add hook for printing log messages
  log: add timestamp option
  log: support systemd journal
  log: colorize log output
  maintainers: update for log library

 MAINTAINERS                                   |   1 +
 app/test/test_eal_flags.c                     |  64 ++++-
 .../freebsd_gsg/freebsd_eal_parameters.rst    |  27 ++
 .../prog_guide/env_abstraction_layer.rst      |   6 +-
 doc/guides/prog_guide/log_lib.rst             |  58 ++++-
 doc/guides/rel_notes/release_24_11.rst        |  16 ++
 lib/eal/common/eal_common_debug.c             |   6 +-
 lib/eal/common/eal_common_options.c           | 132 ++++++----
 lib/eal/common/eal_internal_cfg.h             |   1 -
 lib/eal/common/eal_options.h                  |   6 +
 lib/eal/freebsd/eal.c                         |  63 +----
 lib/eal/linux/eal.c                           |  66 +----
 lib/eal/windows/eal.c                         |  51 +---
 lib/eal/windows/getopt.c                      |  23 +-
 lib/eal/windows/include/getopt.h              |   8 +-
 lib/eal/windows/include/rte_os_shim.h         |  12 +
 lib/log/log.c                                 |  82 ++++--
 lib/log/log_color.c                           | 214 ++++++++++++++++
 lib/log/log_freebsd.c                         |  12 -
 lib/log/log_internal.h                        |  28 +-
 lib/log/log_journal.c                         | 153 +++++++++++
 lib/log/log_linux.c                           |  61 -----
 lib/log/log_private.h                         |  57 +++++
 lib/log/log_syslog.c                          | 108 ++++++++
 lib/log/log_timestamp.c                       | 240 ++++++++++++++++++
 lib/log/log_windows.c                         |  18 --
 lib/log/meson.build                           |  12 +-
 lib/log/version.map                           |   5 +-
 28 files changed, 1171 insertions(+), 359 deletions(-)
 create mode 100644 lib/log/log_color.c
 delete mode 100644 lib/log/log_freebsd.c
 create mode 100644 lib/log/log_journal.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 create mode 100644 lib/log/log_timestamp.c
 delete mode 100644 lib/log/log_windows.c

-- 
2.47.0
#460 lore raw

PATCH v32 1/12 eal/windows: align getopt to FreeBSD

From: Stephen Hemminger <[email protected]>

Having different prototypes on different platforms can lead to lots of unnecessary workarounds. It looks like the version of getopt used from windows was based on an older out of date version from FreeBSD.

This patch changes getopt, getopt_long, etc to have the same const attributes as Linux and FreeBSD. The changes are derived from the current FreeBSD version of getopt_long.

---
 lib/eal/windows/getopt.c         | 23 ++++++++++++-----------
 lib/eal/windows/include/getopt.h |  8 ++++----
 2 files changed, 16 insertions(+), 15 deletions(-)
lib/eal/windows/getopt.c +12 -11
index a1f51c6c23..50ff71b930 100644
@@ -20,7 +20,7 @@
 #include <string.h>
 #include <stdlib.h>
 
-const char    *optarg;		/* argument associated with option */
+char    *optarg;		/* argument associated with option */
 int	opterr = 1;		/* if error message should be printed */
 int	optind = 1;		/* index into parent argv vector */
 int	optopt = '?';		/* character checked for validity */
@@ -39,9 +39,9 @@ static void pass(const char *a) {(void) a; }
 #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
 #define	INORDER		1
 
-#define	EMSG		""
+static char EMSG[] = "";
 
-static const char *place = EMSG; /* option letter processing */
+static char *place = EMSG; /* option letter processing */
 
 /* XXX: set optreset to 1 rather than these two */
 static int nonopt_start = -1; /* first non option argument (for permute) */
@@ -80,7 +80,7 @@ gcd(int a, int b)
  */
 static void
 permute_args(int panonopt_start, int panonopt_end, int opt_end,
-	char **nargv)
+	char * const *nargv)
 {
 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
 	char *swap;
@@ -101,11 +101,12 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
 				pos -= nnonopts;
 			else
 				pos += nopts;
+
 			swap = nargv[pos];
 			/* LINTED const cast */
-			((char **) nargv)[pos] = nargv[cstart];
+			((char **)(uintptr_t)nargv)[pos] = nargv[cstart];
 			/* LINTED const cast */
-			((char **)nargv)[cstart] = swap;
+			((char **)(uintptr_t)nargv)[cstart] = swap;
 		}
 	}
 }
@@ -116,7 +117,7 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
  * Returns -1 if short_too is set and the option does not match long_options.
  */
 static int
-parse_long_options(char **nargv, const char *options,
+parse_long_options(char * const *nargv, const char *options,
 	const struct option *long_options, int *idx, int short_too)
 {
 	const char *current_argv;
@@ -236,7 +237,7 @@ parse_long_options(char **nargv, const char *options,
  *	Parse argc/argv argument vector.  Called by user level routines.
  */
 static int
-getopt_internal(int nargc, char **nargv, const char *options,
+getopt_internal(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx, int flags)
 {
 	char *oli;				/* option letter list index */
@@ -434,7 +435,7 @@ getopt_internal(int nargc, char **nargv, const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt(int nargc, char *nargv[], const char *options)
+getopt(int nargc, char *const nargv[], const char *options)
 {
 	return getopt_internal(nargc, nargv, options, NULL, NULL,
 			       FLAG_PERMUTE);
@@ -445,7 +446,7 @@ getopt(int nargc, char *nargv[], const char *options)
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long(int nargc, char *nargv[], const char *options,
+getopt_long(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
@@ -458,7 +459,7 @@ getopt_long(int nargc, char *nargv[], const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long_only(int nargc, char *nargv[], const char *options,
+getopt_long_only(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
lib/eal/windows/include/getopt.h +4 -4
index 6f57af454b..e4cf6873cb 100644
@@ -44,7 +44,7 @@
 
 
 /** argument to current option, or NULL if it has none */
-extern const char *optarg;
+extern char *optarg;
 /** Current position in arg string.  Starts from 1.
  * Setting to 0 resets state.
  */
@@ -80,14 +80,14 @@ struct option {
 };
 
 /** Compat: getopt */
-int getopt(int argc, char *argv[], const char *options);
+int getopt(int argc, char *const argv[], const char *options);
 
 /** Compat: getopt_long */
-int getopt_long(int argc, char *argv[], const char *options,
+int getopt_long(int argc, char *const argv[], const char *options,
 		const struct option *longopts, int *longindex);
 
 /** Compat: getopt_long_only */
-int getopt_long_only(int nargc, char *argv[], const char *options,
+int getopt_long_only(int nargc, char *const argv[], const char *options,
 		     const struct option *long_options, int *idx);
 
 
Signature · 1 line
2.47.0
#461 lore raw

PATCH v32 2/12 eal: factorize parser for log level

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

The code to parse for log-level option should be same on all OS variants.

---
 lib/eal/common/eal_common_options.c | 40 +++++++++++++++++++++++++++
 lib/eal/common/eal_options.h        |  1 +
 lib/eal/freebsd/eal.c               | 42 -----------------------------
 lib/eal/linux/eal.c                 | 39 ---------------------------
 lib/eal/windows/eal.c               | 35 ------------------------
 5 files changed, 41 insertions(+), 116 deletions(-)
lib/eal/common/eal_common_options.c +40 -0
index f1a5e329a5..17c378f0c7 100644
@@ -1640,6 +1640,46 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
 	return -1;
 }
 
+/* Parse the arguments for --log-level only */
+int
+eal_log_level_parse(int argc, char * const argv[])
+{
+	struct internal_config *internal_conf = eal_get_internal_configuration();
+	int option_index, opt;
+	const int old_optind = optind;
+	const int old_optopt = optopt;
+	const int old_opterr = opterr;
+	char *old_optarg = optarg;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	const int old_optreset = optreset;
+	optreset = 1;
+#endif
+
+	optind = 1;
+	opterr = 0;
+
+	while ((opt = getopt_long(argc, argv, eal_short_options,
+				  eal_long_options, &option_index)) != EOF) {
+
+		switch (opt) {
+		case OPT_LOG_LEVEL_NUM:
+			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+				return -1;
+			break;
+		}
+	}
+
+	/* restore getopt lib */
+	optind = old_optind;
+	optopt = old_optopt;
+	optarg = old_optarg;
+	opterr = old_opterr;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	optreset = old_optreset;
+#endif
+	return 0;
+}
+
 int
 eal_parse_common_option(int opt, const char *optarg,
 			struct internal_config *conf)
lib/eal/common/eal_options.h +1 -0
index 3cc9cb6412..f3f2e104f6 100644
@@ -96,6 +96,7 @@ enum {
 extern const char eal_short_options[];
 extern const struct option eal_long_options[];
 
+int eal_log_level_parse(int argc, char * const argv[]);
 int eal_parse_common_option(int opt, const char *argv,
 			    struct internal_config *conf);
 int eal_option_device_parse(void);
lib/eal/freebsd/eal.c +0 -42

48 lines not on this page · raw message

lib/eal/linux/eal.c +0 -39
index b568cb4481..f82a398d4b 100644
@@ -547,45 +547,6 @@ eal_parse_vfio_vf_token(const char *vf_token)
 	return -1;
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	const int old_optind = optind;
-	const int old_optopt = optopt;
-	char * const old_optarg = optarg;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-	optind = 1;
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-				  eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg, internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	/* restore getopt lib */
-	optind = old_optind;
-	optopt = old_optopt;
-	optarg = old_optarg;
-}
-
 static int
 eal_parse_huge_worker_stack(const char *arg)
 {
lib/eal/windows/eal.c +0 -35
index 620ac38677..25e69a429b 100644
@@ -97,41 +97,6 @@ eal_usage(const char *prgname)
 	}
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-
-	eal_reset_internal_config(internal_conf);
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-		eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg,
-				internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	optind = 0; /* reset getopt lib */
-}
-
 /* Parse the argument given in the command line of the application */
 static int
 eal_parse_args(int argc, char **argv)
Signature · 1 line
2.47.0
#462 lore raw

PATCH v32 3/12 eal: introduce log options parser

In reply to David Marchand

Rename existing log level option parser and add a little helper tracking all options related to logs.
This will make it easier to add more log options in the next commits.

---
 lib/eal/common/eal_common_options.c | 26 ++++++++++++++++++--------
 lib/eal/common/eal_options.h        |  3 ++-
 lib/eal/freebsd/eal.c               |  8 ++++----
 lib/eal/linux/eal.c                 |  8 ++++----
 lib/eal/windows/eal.c               |  7 ++++---
 5 files changed, 32 insertions(+), 20 deletions(-)
lib/eal/common/eal_common_options.c +18 -8
index 17c378f0c7..ab6cf8bebf 100644
@@ -1640,9 +1640,20 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
 	return -1;
 }
 
-/* Parse the arguments for --log-level only */
+bool
+eal_option_is_log(int opt)
+{
+	switch (opt) {
+	case OPT_LOG_LEVEL_NUM:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* Parse all arguments looking for log related ones */
 int
-eal_log_level_parse(int argc, char * const argv[])
+eal_parse_log_options(int argc, char * const argv[])
 {
 	struct internal_config *internal_conf = eal_get_internal_configuration();
 	int option_index, opt;
@@ -1661,12 +1672,11 @@ eal_log_level_parse(int argc, char * const argv[])
 	while ((opt = getopt_long(argc, argv, eal_short_options,
 				  eal_long_options, &option_index)) != EOF) {
 
-		switch (opt) {
-		case OPT_LOG_LEVEL_NUM:
-			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
-				return -1;
-			break;
-		}
+		if (!eal_option_is_log(opt))
+			continue;
+
+		if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+			return -1;
 	}
 
 	/* restore getopt lib */
lib/eal/common/eal_options.h +2 -1
index f3f2e104f6..06ba023c5a 100644
@@ -96,7 +96,8 @@ enum {
 extern const char eal_short_options[];
 extern const struct option eal_long_options[];
 
-int eal_log_level_parse(int argc, char * const argv[]);
+bool eal_option_is_log(int opt);
+int eal_parse_log_options(int argc, char * const argv[]);
 int eal_parse_common_option(int opt, const char *argv,
 			    struct internal_config *conf);
 int eal_option_device_parse(void);
lib/eal/freebsd/eal.c +4 -4
index 89dfc540f2..16b1c67cca 100644
@@ -393,8 +393,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_parse_log_options() already handled this option */
+		if (eal_option_is_log(opt))
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -575,8 +575,8 @@ rte_eal_init(int argc, char **argv)
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
+	/* parse log options as early as possible */
+	eal_parse_log_options(argc, argv);
 
 	if (rte_eal_cpu_init() < 0) {
 		rte_eal_init_alert("Cannot detect lcores.");
lib/eal/linux/eal.c +4 -4
index f82a398d4b..49a88cfbd5 100644
@@ -611,8 +611,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_parse_log_options() already handled this option */
+		if (eal_option_is_log(opt))
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -951,8 +951,8 @@ rte_eal_init(int argc, char **argv)
 
 	eal_reset_internal_config(internal_conf);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
+	/* parse log options as early as possible */
+	eal_parse_log_options(argc, argv);
 
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
lib/eal/windows/eal.c +4 -3
index 25e69a429b..f77053eb7e 100644
@@ -121,8 +121,8 @@ eal_parse_args(int argc, char **argv)
 			return -1;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_parse_log_options() already handled this option */
+		if (eal_option_is_log(opt))
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -254,7 +254,8 @@ rte_eal_init(int argc, char **argv)
 
 	eal_log_init(NULL, 0);
 
-	eal_log_level_parse(argc, argv);
+	/* parse log options as early as possible */
+	eal_parse_log_options(argc, argv);
 
 	if (eal_create_cpu_map() < 0) {
 		rte_eal_init_alert("Cannot discover CPU and NUMA.");
Signature · 1 line
2.47.0
#463 lore raw

PATCH v32 4/12 eal: do not log init failure twice

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

The message already goes through logging, and does not need to be printed on stderr.
Message level should be ALERT to match function name.

---
 lib/eal/freebsd/eal.c | 3 +--
 lib/eal/linux/eal.c   | 3 +--
 lib/eal/windows/eal.c | 3 +--
 3 files changed, 3 insertions(+), 6 deletions(-)
lib/eal/freebsd/eal.c +1 -2
index 16b1c67cca..c84983ac3f 100644
@@ -530,8 +530,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /* Launch threads, called at application init(). */
lib/eal/linux/eal.c +1 -2
index 49a88cfbd5..3915cdb838 100644
@@ -831,8 +831,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /*
lib/eal/windows/eal.c +1 -2
index f77053eb7e..a3eb15ce00 100644
@@ -182,8 +182,7 @@ sync_func(void *arg __rte_unused)
 static void
 rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /* Stubs to enable EAL trace point compilation
Signature · 1 line
2.47.0
#464 lore raw

PATCH v32 5/12 eal: improve exit output log

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

The rte_exit() output format confuses the timestamp and coloring options. Change it to use be a single line with proper prefix.

Before:

[     0.006481] EAL: Error - exiting with code: 1
  Cause: [     0.006489] Cannot init EAL: Permission denied

After:

[     0.006238] EAL: Error - exiting with code: 1
[     0.006250] EAL: Cannot init EAL: Permission denied
---
 lib/eal/common/eal_common_debug.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
lib/eal/common/eal_common_debug.c +2 -4
index 3e77995896..bcfcd6df6f 100644
@@ -36,15 +36,13 @@ rte_exit(int exit_code, const char *format, ...)
 	va_list ap;
 
 	if (exit_code != 0)
-		RTE_LOG(CRIT, EAL, "Error - exiting with code: %d\n"
-				"  Cause: ", exit_code);
+		EAL_LOG(CRIT, "Error - exiting with code: %d", exit_code);
 
 	va_start(ap, format);
 	rte_vlog(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, format, ap);
 	va_end(ap);
 
 	if (rte_eal_cleanup() != 0 && rte_errno != EALREADY)
-		EAL_LOG(CRIT,
-			"EAL could not release all resources");
+		EAL_LOG(CRIT, "EAL could not release all resources");
 	exit(exit_code);
 }
Signature · 1 line
2.47.0
#465 lore raw

PATCH v32 6/12 log: rework syslog handling

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

Refactor how syslog is handled, make it common to Linux and FreeBSD The syslog facility property is better handled in lib/log rather than in eal.
This also adds syslog support to FreeBSD.

Log to syslog only if option is specified.
If no --syslog is given then use only standard error.

---
 app/test/test_eal_flags.c                     |  16 +--
 .../freebsd_gsg/freebsd_eal_parameters.rst    |  27 +++++
 .../prog_guide/env_abstraction_layer.rst      |   6 +-
 doc/guides/prog_guide/log_lib.rst             |   6 +-
 doc/guides/rel_notes/release_24_11.rst        |   6 +
 lib/eal/common/eal_common_options.c           |  57 +--------
 lib/eal/common/eal_internal_cfg.h             |   1 -
 lib/eal/freebsd/eal.c                         |   1 -
 lib/eal/linux/eal.c                           |   8 +-
 lib/eal/windows/eal.c                         |   2 +-
 lib/log/log.c                                 |  43 ++++---
 lib/log/log_freebsd.c                         |  12 --
 lib/log/log_internal.h                        |  11 +-
 lib/log/log_linux.c                           |  61 ----------
 lib/log/log_private.h                         |  27 +++++
 lib/log/log_syslog.c                          | 108 ++++++++++++++++++
 lib/log/log_windows.c                         |  18 ---
 lib/log/meson.build                           |   6 +-
 lib/log/version.map                           |   2 +-
 19 files changed, 220 insertions(+), 198 deletions(-)
 delete mode 100644 lib/log/log_freebsd.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 delete mode 100644 lib/log/log_windows.c
app/test/test_eal_flags.c +8 -8
index 71d8dba731..9fcf0d56e6 100644
@@ -985,12 +985,12 @@ test_misc_flags(void)
 	/* With -v */
 	const char *argv2[] = {prgname, prefix, mp_flag, "-v"};
 	/* With valid --syslog */
-	const char *argv3[] = {prgname, prefix, mp_flag,
-			"--syslog", "syslog"};
-	/* With empty --syslog (should fail) */
+	const char *argv3[] = {prgname, prefix, mp_flag, "--syslog=user"};
+	/* With empty --syslog (now defaults) */
 	const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"};
 	/* 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};
@@ -1080,15 +1080,15 @@ test_misc_flags(void)
 #endif
 
 	if (launch_proc(argv3) != 0) {
-		printf("Error - process did not run ok with --syslog flag\n");
+		printf("Error - process did not run ok with --syslog=user flag\n");
 		goto fail;
 	}
-	if (launch_proc(argv4) == 0) {
-		printf("Error - process run ok with empty --syslog flag\n");
+	if (launch_proc(argv4) != 0) {
+		printf("Error - process did not run ok with --syslog flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv5) == 0) {
-		printf("Error - process run ok with invalid --syslog flag\n");
+		printf("Error - process run ok with --syslog=invalid flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv7) != 0) {
doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +27 -0
index fba467a2ce..9270d9fa3b 100644
@@ -18,3 +18,30 @@ FreeBSD-specific EAL parameters
 -------------------------------
 
 There are currently no FreeBSD-specific EAL command-line parameters available.
+
+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
doc/guides/prog_guide/env_abstraction_layer.rst +3 -3
index 272aeeb4ba..04214a05b2 100644
@@ -884,9 +884,9 @@ Signal Safety
   Other functions are not signal safe because they use one or more
   library routines that are not themselves signal safe.
   For example, calling ``rte_panic()`` is not safe in a signal handler
-  because it uses ``rte_log()`` and ``rte_log()`` calls the
-  ``syslog()`` library function which is in the list of
-  signal safe functions in
+  because it uses ``rte_log()`` and ``rte_log()`` may call ``vfprintf()`` or
+  ``syslog()`` library functions which are not in the list of
+  signal safe functions
   `Signal-Safety manual page <https://man7.org/linux/man-pages/man7/signal-safety.7.html>`_.
 
   The set of functions that are expected to be async-signal-safe in DPDK
doc/guides/prog_guide/log_lib.rst +3 -3
index ff9d1b54a2..9cee75b88c 100644
@@ -5,9 +5,9 @@ Log Library
 ===========
 
 The DPDK Log library provides the logging functionality for other DPDK libraries and drivers.
-By default, in a Linux application, logs are sent to syslog and also to the console.
-On FreeBSD and Windows applications, logs are sent only to the console.
-However, the log function can be overridden by the user to use a different logging mechanism.
+By default, logs are sent only to standard error output of the process.
+The syslog EAL option can be used to redirect to the stystem logger on Linux and FreeBSD.
+In addition, the log can be redirected to a different stdio file stream.
 
 Log Levels
 ----------
doc/guides/rel_notes/release_24_11.rst +6 -0
index d93343fd52..f27d283fab 100644
@@ -114,6 +114,12 @@ New Features
   (and vice versa); freeing the same pointer twice in the same routine;
   freeing an object that was not created by allocation; etc.
 
+* **Updated logging library**
+
+  * The syslog option has changed.
+    By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
+    Syslog is also supported on FreeBSD (but not on Windows).
+
 * **Updated Marvell cnxk mempool driver.**
 
   * Added mempool driver support for CN20K SoC.
lib/eal/common/eal_common_options.c +6 -51

99 lines not on this page · raw message

lib/eal/common/eal_internal_cfg.h +0 -1
index 167ec501fa..f53ab8b4aa 100644
@@ -84,7 +84,6 @@ struct internal_config {
 	/**< true if storing all pages within single files (per-page-size,
 	 * per-node) non-legacy mode only.
 	 */
-	volatile int syslog_facility;	  /**< facility passed to openlog() */
 	/** default interrupt mode for VFIO */
 	volatile enum rte_intr_mode vfio_intr_mode;
 	/** the shared VF token for VFIO-PCI bound PF and VFs devices */
lib/eal/freebsd/eal.c +0 -1
index c84983ac3f..e7fd4f141e 100644
@@ -11,7 +11,6 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <pthread.h>
-#include <syslog.h>
 #include <getopt.h>
 #include <sys/file.h>
 #include <stddef.h>
lib/eal/linux/eal.c +1 -7
index 3915cdb838..c321ea87f3 100644
@@ -1104,13 +1104,7 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	if (eal_log_init(program_invocation_short_name,
-			 internal_conf->syslog_facility) < 0) {
-		rte_eal_init_alert("Cannot init logging.");
-		rte_errno = ENOMEM;
-		rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
-		return -1;
-	}
+	eal_log_init(program_invocation_short_name);
 
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
lib/eal/windows/eal.c +1 -1
index a3eb15ce00..b948c52670 100644
@@ -251,7 +251,7 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL, 0);
+	eal_log_init(NULL);
 
 	/* parse log options as early as possible */
 	eal_parse_log_options(argc, argv);
lib/log/log.c +20 -23

90 lines not on this page · raw message

lib/log/log_freebsd.c deleted +0 -12
deleted file mode 100644
index 698d3c5423..0000000000
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2023 Intel Corporation
- */
-
-#include <rte_common.h>
-#include "log_internal.h"
-
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	return 0;
-}
lib/log/log_internal.h +4 -7
index 451629f1c1..3c46328e7b 100644
@@ -14,13 +14,7 @@
  * Initialize the default log stream.
  */
 __rte_internal
-int eal_log_init(const char *id, int facility);
-
-/*
- * Determine where log data is written when no call to rte_openlog_stream.
- */
-__rte_internal
-void eal_log_set_default(FILE *default_log);
+void eal_log_init(const char *id);
 
 /*
  * Save a log option for later.
@@ -30,6 +24,9 @@ int eal_log_save_regexp(const char *regexp, uint32_t level);
 __rte_internal
 int eal_log_save_pattern(const char *pattern, uint32_t level);
 
+__rte_internal
+int eal_log_syslog(const char *name);
+
 /*
  * Convert log level to string.
  */
lib/log/log_linux.c deleted +0 -61

61 lines not on this page · raw message

lib/log/log_private.h new file +27 -0
new file mode 100644
index 0000000000..d5a8bf271a
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#ifndef LOG_PRIVATE_H
+#define LOG_PRIVATE_H
+
+/* Defined in limits.h on Linux */
+#ifndef LINE_MAX
+#define LINE_MAX	2048 /* _POSIX2_LINE_MAX */
+#endif
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+static inline bool
+log_syslog_enabled(void)
+{
+	return false;
+}
+static inline FILE *
+log_syslog_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#else
+bool log_syslog_enabled(void);
+FILE *log_syslog_open(const char *id);
+#endif
+
+#endif /* LOG_PRIVATE_H */
lib/log/log_syslog.c new file +108 -0

108 lines not on this page · raw message

lib/log/log_windows.c deleted +0 -18
deleted file mode 100644
index a6a0889550..0000000000
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2017-2018 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_log.h>
-#include "log_internal.h"
-
-/* set the log to default function, called during eal init process. */
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	rte_openlog_stream(stderr);
-
-	eal_log_set_default(stderr);
-
-	return 0;
-}
lib/log/meson.build +5 -1
index 0d4319b36f..160cf34f50 100644
@@ -4,6 +4,10 @@
 includes += global_inc
 sources = files(
         'log.c',
-        'log_' + exec_env + '.c',
 )
+
+if not is_windows
+    sources += files('log_syslog.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -1
index 19d7f9cdb6..1637fba3b9 100644
@@ -29,6 +29,6 @@ INTERNAL {
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
-	eal_log_set_default;
+	eal_log_syslog; # WINDOWS_NO_EXPORT
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.47.0
#466 lore raw

PATCH v32 7/12 eal: initialize log before everything else

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

In order for all log messages (including CPU mismatch) to come out through the logging library, it must be initialized as early in rte_eal_init() as possible on all platforms.

Where it was done before was likely historical, based on the support of non-OS isolated CPU's which required a shared memory buffer. That support was dropped before DPDK was publicly released.

---
 doc/guides/rel_notes/release_24_11.rst |  2 ++
 lib/eal/freebsd/eal.c                  | 13 ++++++++++---
 lib/eal/linux/eal.c                    | 14 +++++++++-----
 lib/eal/windows/eal.c                  | 10 +++++++---
 4 files changed, 28 insertions(+), 11 deletions(-)
doc/guides/rel_notes/release_24_11.rst +2 -0
index f27d283fab..3853af2798 100644
@@ -116,6 +116,8 @@ New Features
 
 * **Updated logging library**
 
+  * The log subsystem is initialized earlier in startup so all messages go through the library.
+
   * The syslog option has changed.
     By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
     Syslog is also supported on FreeBSD (but not on Windows).
lib/eal/freebsd/eal.c +10 -3
index e7fd4f141e..a96bbf5836 100644
@@ -53,6 +53,7 @@
 #include "eal_options.h"
 #include "eal_memcfg.h"
 #include "eal_trace.h"
+#include "log_internal.h"
 
 #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
 
@@ -547,6 +548,15 @@ rte_eal_init(int argc, char **argv)
 	bool has_phys_addr;
 	enum rte_iova_mode iova_mode;
 
+	/* setup log as early as possible */
+	if (eal_parse_log_options(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(getprogname());
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -573,9 +583,6 @@ rte_eal_init(int argc, char **argv)
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
-	/* parse log options as early as possible */
-	eal_parse_log_options(argc, argv);
-
 	if (rte_eal_cpu_init() < 0) {
 		rte_eal_init_alert("Cannot detect lcores.");
 		rte_errno = ENOTSUP;
lib/eal/linux/eal.c +9 -5
index c321ea87f3..a6220524a4 100644
@@ -927,6 +927,15 @@ rte_eal_init(int argc, char **argv)
 	struct internal_config *internal_conf =
 		eal_get_internal_configuration();
 
+	/* setup log as early as possible */
+	if (eal_parse_log_options(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(program_invocation_short_name);
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -950,9 +959,6 @@ rte_eal_init(int argc, char **argv)
 
 	eal_reset_internal_config(internal_conf);
 
-	/* parse log options as early as possible */
-	eal_parse_log_options(argc, argv);
-
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
@@ -1104,8 +1110,6 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	eal_log_init(program_invocation_short_name);
-
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
 		rte_eal_init_alert("Cannot init VFIO");
lib/eal/windows/eal.c +7 -3
index b948c52670..5cdc053a02 100644
@@ -251,10 +251,14 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL);
+	/* setup log as early as possible */
+	if (eal_parse_log_options(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
 
-	/* parse log options as early as possible */
-	eal_parse_log_options(argc, argv);
+	eal_log_init(NULL);
 
 	if (eal_create_cpu_map() < 0) {
 		rte_eal_init_alert("Cannot discover CPU and NUMA.");
Signature · 1 line
2.47.0
#467 lore raw

PATCH v32 8/12 log: add hook for printing log messages

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

This is useful for when decorating log output for console or journal. Provide basic version in this patch.

---
 lib/log/log.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
lib/log/log.c +7 -1
index a5cae1f950..dbff223108 100644
@@ -29,16 +29,21 @@ struct rte_log_dynamic_type {
 	uint32_t loglevel;
 };
 
+/* Note: same as vfprintf() */
+typedef int (*log_print_t)(FILE *f, const char *fmt, 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. */
+	log_print_t print_func;
 	size_t dynamic_types_len;
 	struct rte_log_dynamic_type *dynamic_types;
 } rte_logs = {
 	.type = UINT32_MAX,
 	.level = RTE_LOG_DEBUG,
+	.print_func = vfprintf,
 };
 
 struct rte_eal_opt_loglevel {
@@ -75,6 +80,7 @@ int
 rte_openlog_stream(FILE *f)
 {
 	rte_logs.file = f;
+	rte_logs.print_func = vfprintf;
 	return 0;
 }
 
@@ -471,7 +477,7 @@ rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap)
 	RTE_PER_LCORE(log_cur_msg).loglevel = level;
 	RTE_PER_LCORE(log_cur_msg).logtype = logtype;
 
-	ret = vfprintf(f, format, ap);
+	ret = (*rte_logs.print_func)(f, format, ap);
 	fflush(f);
 	return ret;
 }
Signature · 1 line
2.47.0
#468 lore raw

PATCH v32 9/12 log: add timestamp option

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

When debugging driver or startup issues, it is useful to have a timestamp on each message printed.
The messages in syslog already have a timestamp, but often syslog is not available during testing.

There are multiple timestamp formats similar to Linux dmesg. The default is time relative since startup (when first step of logging initialization is done by constructor).
Other alternative formats are delta, ctime, reltime and iso formats.

Example:

$ dpdk-testpmd --log-timestamp -- -i
[     0.008610] EAL: Detected CPU lcores: 8
[     0.008634] EAL: Detected NUMA nodes: 1
[     0.008792] EAL: Detected static linkage of DPDK
[     0.010620] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
[     0.012618] EAL: Selected IOVA mode 'VA'
[     0.016675] testpmd: No probed ethernet devices
Interactive-mode selected

Note: Windows does not have localtime_r but it does have a similar function that can be used instead. Add it to rte_os_shim.h.

---
 app/test/test_eal_flags.c              |  24 +++
 doc/guides/prog_guide/log_lib.rst      |  28 +++
 doc/guides/rel_notes/release_24_11.rst |   2 +
 lib/eal/common/eal_common_options.c    |  14 +-
 lib/eal/common/eal_options.h           |   2 +
 lib/eal/windows/include/rte_os_shim.h  |  10 ++
 lib/log/log.c                          |  13 +-
 lib/log/log_internal.h                 |   9 +
 lib/log/log_private.h                  |   6 +
 lib/log/log_timestamp.c                | 240 +++++++++++++++++++++++++
 lib/log/meson.build                    |   1 +
 lib/log/version.map                    |   1 +
 12 files changed, 344 insertions(+), 6 deletions(-)
 create mode 100644 lib/log/log_timestamp.c
app/test/test_eal_flags.c +24 -0
index 9fcf0d56e6..1a062fe0e8 100644
@@ -1055,6 +1055,18 @@ test_misc_flags(void)
 	const char * const argv22[] = {prgname, prefix, mp_flag,
 				       "--huge-worker-stack=512"};
 
+	/* Try running with --log-timestamp */
+	const char * const argv23[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp" };
+
+	/* Try running with --log-timestamp=iso */
+	const char * const argv24[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=iso" };
+
+	/* Try running with invalid timestamp */
+	const char * const argv25[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=invalid" };
+
 	/* run all tests also applicable to FreeBSD first */
 
 	if (launch_proc(argv0) == 0) {
@@ -1162,6 +1174,18 @@ test_misc_flags(void)
 		printf("Error - process did not run ok with --huge-worker-stack=size parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv23) != 0) {
+		printf("Error - process did not run ok with --log-timestamp parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv24) != 0) {
+		printf("Error - process did not run ok with --log-timestamp=iso parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv25) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
 
 	rmdir(hugepath_dir3);
 	rmdir(hugepath_dir2);
doc/guides/prog_guide/log_lib.rst +28 -0
index 9cee75b88c..a2e95317f5 100644
@@ -110,3 +110,31 @@ Throughout the cfgfile library, all logging calls are therefore of the form:
 
 	CFG_LOG(ERR, "invalid comment characters %c",
 	       params->comment_character);
+
+Log timestamp
+~~~~~~~~~~~~~
+
+An optional timestamp can be added before each message by adding the ``--log-timestamp`` option.
+For example::
+
+	/path/to/app --log-level=lib.*:debug --log-timestamp
+
+Multiple alternative timestamp formats are available:
+
+.. csv-table:: Log time stamp format
+   :header: "Format", "Description", "Example"
+   :widths: 6, 30, 32
+
+   "ctime", "Unix ctime", "``[Wed Mar 20 07:26:12 2024]``"
+   "delta", "Offset since last", "``[<    3.162373>]``"
+   "reltime", "Seconds since last or time if minute changed", "``[  +3.001791]`` or ``[Mar20 07:26:12]``"
+   "iso", "ISO-8601", "``[2024-03-20T07:26:12−07:00]``"
+
+To prefix all console messages with ISO format time the syntax is::
+
+	/path/to/app --log-timestamp=iso
+
+.. note::
+
+   Timestamp option has no effect if using syslog
+   because the ``syslog()`` service already does timestamping internally.
doc/guides/rel_notes/release_24_11.rst +2 -0
index 3853af2798..d1226c78d1 100644
@@ -122,6 +122,8 @@ New Features
     By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
     Syslog is also supported on FreeBSD (but not on Windows).
 
+  * Log messages can be timestamped with ``--log-timestamp`` option.
+
 * **Updated Marvell cnxk mempool driver.**
 
   * Added mempool driver support for CN20K SoC.
lib/eal/common/eal_common_options.c +12 -2
index 9f4feb2611..7de6a25e62 100644
@@ -74,6 +74,7 @@ eal_long_options[] = {
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
+	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
 	{OPT_TRACE_DIR,         1, NULL, OPT_TRACE_DIR_NUM        },
 	{OPT_TRACE_BUF_SIZE,    1, NULL, OPT_TRACE_BUF_SIZE_NUM   },
@@ -1599,6 +1600,7 @@ eal_option_is_log(int opt)
 {
 	switch (opt) {
 	case OPT_LOG_LEVEL_NUM:
+	case OPT_LOG_TIMESTAMP_NUM:
 	case OPT_SYSLOG_NUM:
 		return true;
 	default:
@@ -1850,7 +1852,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		break;
 #endif
 
-	case OPT_LOG_LEVEL_NUM: {
+	case OPT_LOG_LEVEL_NUM:
 		if (eal_parse_log_level(optarg) < 0) {
 			EAL_LOG(ERR,
 				"invalid parameters for --"
@@ -1858,7 +1860,14 @@ eal_parse_common_option(int opt, const char *optarg,
 			return -1;
 		}
 		break;
-	}
+
+	case OPT_LOG_TIMESTAMP_NUM:
+		if (eal_log_timestamp(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_TIMESTAMP);
+			return -1;
+		}
+		break;
 
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
@@ -2225,6 +2234,7 @@ eal_common_usage(void)
 	       "  --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
+	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index 06ba023c5a..a1b52ae694 100644
@@ -35,6 +35,8 @@ enum {
 	OPT_LCORES_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
+#define OPT_LOG_TIMESTAMP     "log-timestamp"
+	OPT_LOG_TIMESTAMP_NUM,
 #define OPT_TRACE             "trace"
 	OPT_TRACE_NUM,
 #define OPT_TRACE_DIR         "trace-dir"
lib/eal/windows/include/rte_os_shim.h +10 -0
index eda8113662..665c9ac93b 100644
@@ -110,4 +110,14 @@ rte_clock_gettime(clockid_t clock_id, struct timespec *tp)
 }
 #define clock_gettime(clock_id, tp) rte_clock_gettime(clock_id, tp)
 
+static inline struct tm *
+rte_localtime_r(const time_t *timep, struct tm *result)
+{
+	if (localtime_s(result, timep) == 0)
+		return result;
+	else
+		return NULL;
+}
+#define localtime_r(timep, result) rte_localtime_r(timep, result)
+
 #endif /* _RTE_OS_SHIM_ */
lib/log/log.c +9 -4
index dbff223108..854d77887b 100644
@@ -17,13 +17,13 @@
 #include <rte_log.h>
 #include <rte_per_lcore.h>
 
-#include "log_internal.h"
-#include "log_private.h"
-
 #ifdef RTE_EXEC_ENV_WINDOWS
-#define strdup _strdup
+#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;
@@ -513,6 +513,11 @@ eal_log_init(const char *id)
 	if (logf)
 		rte_openlog_stream(logf);
 
+	if (log_timestamp_enabled())
+		rte_logs.print_func = log_print_with_timestamp;
+	else
+		rte_logs.print_func = vfprintf;
+
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
 		"Debug dataplane logs available - lower performance\n");
lib/log/log_internal.h +9 -0
index 3c46328e7b..7c7d44eed2 100644
@@ -5,8 +5,10 @@
 #ifndef LOG_INTERNAL_H
 #define LOG_INTERNAL_H
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <time.h>
 
 #include <rte_compat.h>
 
@@ -39,4 +41,11 @@ const char *eal_log_level2str(uint32_t level);
 __rte_internal
 void rte_eal_log_cleanup(void);
 
+/*
+ * Add timestamp to console logs
+ */
+__rte_internal
+int eal_log_timestamp(const char *fmt);
+
+
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +6 -0
index d5a8bf271a..5da9c9b438 100644
@@ -24,4 +24,10 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+bool log_timestamp_enabled(void);
+ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
+
+__rte_format_printf(2, 0)
+int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/log_timestamp.c new file +240 -0

240 lines not on this page · raw message

lib/log/meson.build +1 -0
index 160cf34f50..4ac232786e 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_timestamp.c',
 )
 
 if not is_windows
lib/log/version.map +1 -0
index 1637fba3b9..8be6907840 100644
@@ -30,5 +30,6 @@ INTERNAL {
 	eal_log_save_pattern;
 	eal_log_save_regexp;
 	eal_log_syslog; # WINDOWS_NO_EXPORT
+	eal_log_timestamp;
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.47.0
#469 lore raw

PATCH v32 10/12 log: support systemd journal

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

If DPDK application is being run as a systemd service, then it can use the journal protocol which allows putting more information in the log such as priority and other information.

The use of journal protocol is automatically detected and handled. Rather than having a dependency on libsystemd, just use the protocol directly as defined in:
https://systemd.io/JOURNAL_NATIVE_PROTOCOL/

---
 doc/guides/rel_notes/release_24_11.rst |   4 +
 lib/log/log.c                          |  31 +++--
 lib/log/log_internal.h                 |   3 +
 lib/log/log_journal.c                  | 153 +++++++++++++++++++++++++
 lib/log/log_private.h                  |  16 +++
 lib/log/meson.build                    |   4 +
 lib/log/version.map                    |   1 +
 7 files changed, 200 insertions(+), 12 deletions(-)
 create mode 100644 lib/log/log_journal.c
doc/guides/rel_notes/release_24_11.rst +4 -0
index d1226c78d1..341606f541 100644
@@ -118,6 +118,10 @@ New Features
 
   * The log subsystem is initialized earlier in startup so all messages go through the library.
 
+  * If the application is a systemd service and the log output is being sent to standard error
+    then DPDK will switch to journal native protocol.
+    This allows the more data such as severity to be sent.
+
   * The syslog option has changed.
     By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
     Syslog is also supported on FreeBSD (but not on Windows).
lib/log/log.c +19 -12
index 854d77887b..0974adc81f 100644
@@ -505,18 +505,25 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...)
 void
 eal_log_init(const char *id)
 {
-	FILE *logf = NULL;
-
-	if (log_syslog_enabled())
-		logf = log_syslog_open(id);
-
-	if (logf)
-		rte_openlog_stream(logf);
-
-	if (log_timestamp_enabled())
-		rte_logs.print_func = log_print_with_timestamp;
-	else
-		rte_logs.print_func = vfprintf;
+	/* If user has already set a log stream, then use it. */
+	if (rte_logs.file == NULL) {
+		FILE *logf = NULL;
+
+		/* if stderr is associated with systemd environment */
+		if (log_journal_enabled())
+			logf = log_journal_open(id);
+		/* If --syslog option was passed */
+		else if (log_syslog_enabled())
+			logf = log_syslog_open(id);
+
+		/* if either syslog or journal is used, then no special handling */
+		if (logf)
+			rte_openlog_stream(logf);
+		else if (log_timestamp_enabled())
+			rte_logs.print_func = log_print_with_timestamp;
+		else
+			rte_logs.print_func = vfprintf;
+	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
lib/log/log_internal.h +3 -0
index 7c7d44eed2..82fdc21ac2 100644
@@ -29,6 +29,9 @@ int eal_log_save_pattern(const char *pattern, uint32_t level);
 __rte_internal
 int eal_log_syslog(const char *name);
 
+__rte_internal
+int eal_log_journal(const char *opt);
+
 /*
  * Convert log level to string.
  */
lib/log/log_journal.c new file +153 -0

153 lines not on this page · raw message

lib/log/log_private.h +16 -0
index 5da9c9b438..1b66057fd6 100644
@@ -24,6 +24,22 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+#ifdef RTE_EXEC_ENV_LINUX
+bool log_journal_enabled(void);
+FILE *log_journal_open(const char *id);
+#else
+static inline bool
+log_journal_enabled(void)
+{
+	return false;
+}
+static inline FILE *
+log_journal_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#endif /* !RTE_EXEC_ENV_LINUX */
+
 bool log_timestamp_enabled(void);
 ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 
lib/log/meson.build +4 -0
index 4ac232786e..86e4452b19 100644
@@ -11,4 +11,8 @@ if not is_windows
     sources += files('log_syslog.c')
 endif
 
+if is_linux
+    sources += files('log_journal.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -0
index 8be6907840..800d3943bc 100644
@@ -26,6 +26,7 @@ INTERNAL {
 	global:
 
 	eal_log_init;
+	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
Signature · 1 line
2.47.0
#470 lore raw

PATCH v32 11/12 log: colorize log output

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

Like dmesg, colorize the log output (unless redirected to file). Timestamp is green, the subsystem is in yellow and the message is red if urgent, boldface if an error, and normal for info and debug messages.

The default is to not use color since it may disturb automatic tests and other embedded usage.

Note: add fileno() and isatty() to the Windows wrapper.

---
 app/test/test_eal_flags.c              |  24 +++
 doc/guides/prog_guide/log_lib.rst      |  24 +++
 doc/guides/rel_notes/release_24_11.rst |   2 +
 lib/eal/common/eal_common_options.c    |  11 ++
 lib/eal/common/eal_options.h           |   2 +
 lib/eal/windows/include/rte_os_shim.h  |   2 +
 lib/log/log.c                          |  23 ++-
 lib/log/log_color.c                    | 214 +++++++++++++++++++++++++
 lib/log/log_internal.h                 |   5 +
 lib/log/log_private.h                  |   8 +
 lib/log/meson.build                    |   1 +
 lib/log/version.map                    |   1 +
 12 files changed, 312 insertions(+), 5 deletions(-)
 create mode 100644 lib/log/log_color.c
app/test/test_eal_flags.c +24 -0
index 1a062fe0e8..d37d6b8627 100644
@@ -1067,6 +1067,18 @@ test_misc_flags(void)
 	const char * const argv25[] = {prgname, prefix, mp_flag,
 				       "--log-timestamp=invalid" };
 
+	/* Try running with --log-color */
+	const char * const argv26[] = {prgname, prefix, mp_flag,
+				       "--log-color" };
+
+	/* Try running with --log-color=never */
+	const char * const argv27[] = {prgname, prefix, mp_flag,
+				       "--log-color=never" };
+
+	/* Try running with --log-color=invalid */
+	const char * const argv28[] = {prgname, prefix, mp_flag,
+				       "--log-color=invalid" };
+
 	/* run all tests also applicable to FreeBSD first */
 
 	if (launch_proc(argv0) == 0) {
@@ -1186,6 +1198,18 @@ test_misc_flags(void)
 		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv26) != 0) {
+		printf("Error - process did not run ok with --log-color parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv27) != 0) {
+		printf("Error - process did not run ok with --log-color=never parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv28) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
 
 	rmdir(hugepath_dir3);
 	rmdir(hugepath_dir2);
doc/guides/prog_guide/log_lib.rst +24 -0
index a2e95317f5..3e888b8965 100644
@@ -59,6 +59,7 @@ For example::
 
 Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.
 
+
 Using Logging APIs to Generate Log Messages
 -------------------------------------------
 
@@ -138,3 +139,26 @@ To prefix all console messages with ISO format time the syntax is::
 
    Timestamp option has no effect if using syslog
    because the ``syslog()`` service already does timestamping internally.
+
+
+Color output
+~~~~~~~~~~~~
+
+The log library will highlight important messages.
+This is controlled by the ``--log-color`` option.
+The optional argument describes when color is enabled:
+
+:never: Do not enable color. This is the default behavior.
+
+:auto: Enable color only when printing to a terminal.
+       This is the same as ``--log-color`` with no argument.
+
+:always: Always print color.
+
+For example to enable color in logs if using terminal::
+
+	/path/to/app --log-color
+
+.. note::
+
+   Color output is never used for syslog or systemd journal logging.
doc/guides/rel_notes/release_24_11.rst +2 -0
index 341606f541..543becba28 100644
@@ -128,6 +128,8 @@ New Features
 
   * Log messages can be timestamped with ``--log-timestamp`` option.
 
+  * Log messages can be colorized with the ``--log-color`` option.
+
 * **Updated Marvell cnxk mempool driver.**
 
   * Added mempool driver support for CN20K SoC.
lib/eal/common/eal_common_options.c +11 -0
index 7de6a25e62..79db9a47dd 100644
@@ -73,6 +73,7 @@ eal_long_options[] = {
 	{OPT_HUGE_UNLINK,       2, NULL, OPT_HUGE_UNLINK_NUM      },
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
+	{OPT_LOG_COLOR,		2, NULL, OPT_LOG_COLOR_NUM	  },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
 	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
@@ -1599,6 +1600,7 @@ bool
 eal_option_is_log(int opt)
 {
 	switch (opt) {
+	case OPT_LOG_COLOR_NUM:
 	case OPT_LOG_LEVEL_NUM:
 	case OPT_LOG_TIMESTAMP_NUM:
 	case OPT_SYSLOG_NUM:
@@ -1869,6 +1871,14 @@ eal_parse_common_option(int opt, const char *optarg,
 		}
 		break;
 
+	case OPT_LOG_COLOR_NUM:
+		if (eal_log_color(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_COLOR);
+			return -1;
+		}
+		break;
+
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
 		if (eal_trace_args_save(optarg) < 0) {
@@ -2235,6 +2245,7 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
 	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
+	       "  --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index a1b52ae694..95fb4f6108 100644
@@ -33,6 +33,8 @@ enum {
 	OPT_HUGE_UNLINK_NUM,
 #define OPT_LCORES            "lcores"
 	OPT_LCORES_NUM,
+#define OPT_LOG_COLOR	      "log-color"
+	OPT_LOG_COLOR_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
 #define OPT_LOG_TIMESTAMP     "log-timestamp"
lib/eal/windows/include/rte_os_shim.h +2 -0
index 665c9ac93b..0e74eb19c7 100644
@@ -30,6 +30,8 @@
 #define write(fd, buf, n) _write(fd, buf, n)
 #define close(fd) _close(fd)
 #define unlink(path) _unlink(path)
+#define fileno(f) _fileno(f)
+#define isatty(fd) _isatty(fd)
 
 #define IPVERSION	4
 
lib/log/log.c +18 -5
index 0974adc81f..eb087d601e 100644
@@ -12,6 +12,7 @@
 #include <regex.h>
 #include <fnmatch.h>
 #include <sys/queue.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -517,12 +518,24 @@ eal_log_init(const char *id)
 			logf = log_syslog_open(id);
 
 		/* if either syslog or journal is used, then no special handling */
-		if (logf)
+		if (logf) {
 			rte_openlog_stream(logf);
-		else if (log_timestamp_enabled())
-			rte_logs.print_func = log_print_with_timestamp;
-		else
-			rte_logs.print_func = vfprintf;
+		} else {
+			bool is_terminal = isatty(fileno(stderr));
+			bool use_color = log_color_enabled(is_terminal);
+
+			if (log_timestamp_enabled()) {
+				if (use_color)
+					rte_logs.print_func = color_print_with_timestamp;
+				else
+					rte_logs.print_func = log_print_with_timestamp;
+			} else {
+				if (use_color)
+					rte_logs.print_func = color_print;
+				else
+					rte_logs.print_func = vfprintf;
+			}
+		}
 	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
lib/log/log_color.c new file +214 -0

214 lines not on this page · raw message

lib/log/log_internal.h +5 -0
index 82fdc21ac2..bba7041ea3 100644
@@ -50,5 +50,10 @@ void rte_eal_log_cleanup(void);
 __rte_internal
 int eal_log_timestamp(const char *fmt);
 
+/*
+ * Enable or disable color in log messages
+ */
+__rte_internal
+int eal_log_color(const char *mode);
 
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +8 -0
index 1b66057fd6..f275346c7b 100644
@@ -46,4 +46,12 @@ ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 __rte_format_printf(2, 0)
 int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
 
+bool log_color_enabled(bool is_tty);
+
+__rte_format_printf(2, 0)
+int color_print(FILE *f, const char *format, va_list ap);
+
+__rte_format_printf(2, 0)
+int color_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/meson.build +1 -0
index 86e4452b19..b3de57b9c7 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_color.c',
         'log_timestamp.c',
 )
 
lib/log/version.map +1 -0
index 800d3943bc..09d8a4289b 100644
@@ -25,6 +25,7 @@ DPDK_25 {
 INTERNAL {
 	global:
 
+	eal_log_color;
 	eal_log_init;
 	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
Signature · 1 line
2.47.0
#471 lore raw

PATCH v32 12/12 maintainers: update for log library

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

"You touch it you own it".
Add myself as maintainer for log library.

---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)
MAINTAINERS +1 -0
index 0eacf60b5a..0697924ff0 100644
@@ -193,6 +193,7 @@ F: app/test/test_threads.c
 F: app/test/test_version.c
 
 Logging
+M: Stephen Hemminger <[email protected]>
 F: lib/log/
 F: doc/guides/prog_guide/log_lib.rst
 F: app/test/test_logs.c
Signature · 1 line
2.47.0
#472 lore raw

v32 cover Log library enhancements

In reply to Stephen Hemminger

Improvements and unification of logging library.
This version works on all platforms: Linux, Windows and FreeBSD.

This is update to rework patch set. It adds several new features to the console log output.

* Putting a timestamp on console output which is useful for analyzing performance of startup codes. Timestamp is optional and must be enabled on command line.

* Displaying console output with colors.
It uses the standard conventions used by many other Linux commands for colorized display. The default is to enable color if the console output is going to a terminal. But it can be always on or disabled by command line flag. This default was chosen based on what dmesg(1) command does.

Color is used by many tools (vi, iproute2, git) because it is helpful; DPDK drivers and libraries print lots of not very useful messages. And having error messages highlighted in bold face helps. This might also get users to pay more attention to error messages. Many bug reports have earlier messages that are lost because there are so many info messages.

* Add support for automatic detection of systemd journal protocol. If running as systemd service will get enhanced logging.

* Use of syslog is optional and the meaning of the --syslog flag has changed. The default is *not* to use unless requested.

Add Stephen as maintainer for log because by now have added more than previous authors.

Resending for CI:

Changes since v31:
- rebased,
- fixed build with MSVC: escape character was restored to \033 (used until v25) instead of \e,

Changes since v30:
- added a little helper that identifies log options (this fixed a little bug with the color option being parsed twice) and
renamed eal_log_level_parse() as eal_parse_log_options(),
- adjusted log level to ALERT for EAL error on Windows,
- split RN updates in relevant patches and fixed style,
- fixed --syslog usage string,
- split and squashed Windows shim update in relevant patches,
- fixed typos,
- cleaned duplicate inclusion of headers,
- moved syslog facility code update in relevant patch,
- removed dead reference to eal_log_set_default,

Signature · 58 lines
David Marchand

David Marchand (1):
  eal: introduce log options parser

Stephen Hemminger (11):
  eal/windows: align getopt to FreeBSD
  eal: factorize parser for log level
  eal: do not log init failure twice
  eal: improve exit output log
  log: rework syslog handling
  eal: initialize log before everything else
  log: add hook for printing log messages
  log: add timestamp option
  log: support systemd journal
  log: colorize log output
  maintainers: update for log library

 MAINTAINERS                                   |   1 +
 app/test/test_eal_flags.c                     |  64 ++++-
 .../freebsd_gsg/freebsd_eal_parameters.rst    |  27 ++
 .../prog_guide/env_abstraction_layer.rst      |   6 +-
 doc/guides/prog_guide/log_lib.rst             |  58 ++++-
 doc/guides/rel_notes/release_24_11.rst        |  16 ++
 lib/eal/common/eal_common_debug.c             |   6 +-
 lib/eal/common/eal_common_options.c           | 132 ++++++----
 lib/eal/common/eal_internal_cfg.h             |   1 -
 lib/eal/common/eal_options.h                  |   6 +
 lib/eal/freebsd/eal.c                         |  63 +----
 lib/eal/linux/eal.c                           |  66 +----
 lib/eal/windows/eal.c                         |  51 +---
 lib/eal/windows/getopt.c                      |  23 +-
 lib/eal/windows/include/getopt.h              |   8 +-
 lib/eal/windows/include/rte_os_shim.h         |  12 +
 lib/log/log.c                                 |  82 ++++--
 lib/log/log_color.c                           | 214 ++++++++++++++++
 lib/log/log_freebsd.c                         |  12 -
 lib/log/log_internal.h                        |  28 +-
 lib/log/log_journal.c                         | 153 +++++++++++
 lib/log/log_linux.c                           |  61 -----
 lib/log/log_private.h                         |  57 +++++
 lib/log/log_syslog.c                          | 108 ++++++++
 lib/log/log_timestamp.c                       | 240 ++++++++++++++++++
 lib/log/log_windows.c                         |  18 --
 lib/log/meson.build                           |  12 +-
 lib/log/version.map                           |   5 +-
 28 files changed, 1171 insertions(+), 359 deletions(-)
 create mode 100644 lib/log/log_color.c
 delete mode 100644 lib/log/log_freebsd.c
 create mode 100644 lib/log/log_journal.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 create mode 100644 lib/log/log_timestamp.c
 delete mode 100644 lib/log/log_windows.c

-- 
2.47.0
#473 lore raw

PATCH v32 1/12 eal/windows: align getopt to FreeBSD

From: Stephen Hemminger <[email protected]>

Having different prototypes on different platforms can lead to lots of unnecessary workarounds. It looks like the version of getopt used from windows was based on an older out of date version from FreeBSD.

This patch changes getopt, getopt_long, etc to have the same const attributes as Linux and FreeBSD. The changes are derived from the current FreeBSD version of getopt_long.

---
 lib/eal/windows/getopt.c         | 23 ++++++++++++-----------
 lib/eal/windows/include/getopt.h |  8 ++++----
 2 files changed, 16 insertions(+), 15 deletions(-)
lib/eal/windows/getopt.c +12 -11
index a1f51c6c23..50ff71b930 100644
@@ -20,7 +20,7 @@
 #include <string.h>
 #include <stdlib.h>
 
-const char    *optarg;		/* argument associated with option */
+char    *optarg;		/* argument associated with option */
 int	opterr = 1;		/* if error message should be printed */
 int	optind = 1;		/* index into parent argv vector */
 int	optopt = '?';		/* character checked for validity */
@@ -39,9 +39,9 @@ static void pass(const char *a) {(void) a; }
 #define	BADARG		((*options == ':') ? (int)':' : (int)'?')
 #define	INORDER		1
 
-#define	EMSG		""
+static char EMSG[] = "";
 
-static const char *place = EMSG; /* option letter processing */
+static char *place = EMSG; /* option letter processing */
 
 /* XXX: set optreset to 1 rather than these two */
 static int nonopt_start = -1; /* first non option argument (for permute) */
@@ -80,7 +80,7 @@ gcd(int a, int b)
  */
 static void
 permute_args(int panonopt_start, int panonopt_end, int opt_end,
-	char **nargv)
+	char * const *nargv)
 {
 	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
 	char *swap;
@@ -101,11 +101,12 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
 				pos -= nnonopts;
 			else
 				pos += nopts;
+
 			swap = nargv[pos];
 			/* LINTED const cast */
-			((char **) nargv)[pos] = nargv[cstart];
+			((char **)(uintptr_t)nargv)[pos] = nargv[cstart];
 			/* LINTED const cast */
-			((char **)nargv)[cstart] = swap;
+			((char **)(uintptr_t)nargv)[cstart] = swap;
 		}
 	}
 }
@@ -116,7 +117,7 @@ permute_args(int panonopt_start, int panonopt_end, int opt_end,
  * Returns -1 if short_too is set and the option does not match long_options.
  */
 static int
-parse_long_options(char **nargv, const char *options,
+parse_long_options(char * const *nargv, const char *options,
 	const struct option *long_options, int *idx, int short_too)
 {
 	const char *current_argv;
@@ -236,7 +237,7 @@ parse_long_options(char **nargv, const char *options,
  *	Parse argc/argv argument vector.  Called by user level routines.
  */
 static int
-getopt_internal(int nargc, char **nargv, const char *options,
+getopt_internal(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx, int flags)
 {
 	char *oli;				/* option letter list index */
@@ -434,7 +435,7 @@ getopt_internal(int nargc, char **nargv, const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt(int nargc, char *nargv[], const char *options)
+getopt(int nargc, char *const nargv[], const char *options)
 {
 	return getopt_internal(nargc, nargv, options, NULL, NULL,
 			       FLAG_PERMUTE);
@@ -445,7 +446,7 @@ getopt(int nargc, char *nargv[], const char *options)
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long(int nargc, char *nargv[], const char *options,
+getopt_long(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
@@ -458,7 +459,7 @@ getopt_long(int nargc, char *nargv[], const char *options,
  *	Parse argc/argv argument vector.
  */
 int
-getopt_long_only(int nargc, char *nargv[], const char *options,
+getopt_long_only(int nargc, char *const nargv[], const char *options,
 	const struct option *long_options, int *idx)
 {
 
lib/eal/windows/include/getopt.h +4 -4
index 6f57af454b..e4cf6873cb 100644
@@ -44,7 +44,7 @@
 
 
 /** argument to current option, or NULL if it has none */
-extern const char *optarg;
+extern char *optarg;
 /** Current position in arg string.  Starts from 1.
  * Setting to 0 resets state.
  */
@@ -80,14 +80,14 @@ struct option {
 };
 
 /** Compat: getopt */
-int getopt(int argc, char *argv[], const char *options);
+int getopt(int argc, char *const argv[], const char *options);
 
 /** Compat: getopt_long */
-int getopt_long(int argc, char *argv[], const char *options,
+int getopt_long(int argc, char *const argv[], const char *options,
 		const struct option *longopts, int *longindex);
 
 /** Compat: getopt_long_only */
-int getopt_long_only(int nargc, char *argv[], const char *options,
+int getopt_long_only(int nargc, char *const argv[], const char *options,
 		     const struct option *long_options, int *idx);
 
 
Signature · 1 line
2.47.0
#474 lore raw

PATCH v32 2/12 eal: factorize parser for log level

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

The code to parse for log-level option should be same on all OS variants.

---
 lib/eal/common/eal_common_options.c | 40 +++++++++++++++++++++++++++
 lib/eal/common/eal_options.h        |  1 +
 lib/eal/freebsd/eal.c               | 42 -----------------------------
 lib/eal/linux/eal.c                 | 39 ---------------------------
 lib/eal/windows/eal.c               | 35 ------------------------
 5 files changed, 41 insertions(+), 116 deletions(-)
lib/eal/common/eal_common_options.c +40 -0
index f1a5e329a5..17c378f0c7 100644
@@ -1640,6 +1640,46 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
 	return -1;
 }
 
+/* Parse the arguments for --log-level only */
+int
+eal_log_level_parse(int argc, char * const argv[])
+{
+	struct internal_config *internal_conf = eal_get_internal_configuration();
+	int option_index, opt;
+	const int old_optind = optind;
+	const int old_optopt = optopt;
+	const int old_opterr = opterr;
+	char *old_optarg = optarg;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	const int old_optreset = optreset;
+	optreset = 1;
+#endif
+
+	optind = 1;
+	opterr = 0;
+
+	while ((opt = getopt_long(argc, argv, eal_short_options,
+				  eal_long_options, &option_index)) != EOF) {
+
+		switch (opt) {
+		case OPT_LOG_LEVEL_NUM:
+			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+				return -1;
+			break;
+		}
+	}
+
+	/* restore getopt lib */
+	optind = old_optind;
+	optopt = old_optopt;
+	optarg = old_optarg;
+	opterr = old_opterr;
+#ifdef RTE_EXEC_ENV_FREEBSD
+	optreset = old_optreset;
+#endif
+	return 0;
+}
+
 int
 eal_parse_common_option(int opt, const char *optarg,
 			struct internal_config *conf)
lib/eal/common/eal_options.h +1 -0
index 3cc9cb6412..f3f2e104f6 100644
@@ -96,6 +96,7 @@ enum {
 extern const char eal_short_options[];
 extern const struct option eal_long_options[];
 
+int eal_log_level_parse(int argc, char * const argv[]);
 int eal_parse_common_option(int opt, const char *argv,
 			    struct internal_config *conf);
 int eal_option_device_parse(void);
lib/eal/freebsd/eal.c +0 -42

48 lines not on this page · raw message

lib/eal/linux/eal.c +0 -39
index b568cb4481..f82a398d4b 100644
@@ -547,45 +547,6 @@ eal_parse_vfio_vf_token(const char *vf_token)
 	return -1;
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	const int old_optind = optind;
-	const int old_optopt = optopt;
-	char * const old_optarg = optarg;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-	optind = 1;
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-				  eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg, internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	/* restore getopt lib */
-	optind = old_optind;
-	optopt = old_optopt;
-	optarg = old_optarg;
-}
-
 static int
 eal_parse_huge_worker_stack(const char *arg)
 {
lib/eal/windows/eal.c +0 -35
index 620ac38677..25e69a429b 100644
@@ -97,41 +97,6 @@ eal_usage(const char *prgname)
 	}
 }
 
-/* Parse the arguments for --log-level only */
-static void
-eal_log_level_parse(int argc, char **argv)
-{
-	int opt;
-	char **argvopt;
-	int option_index;
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-
-	argvopt = argv;
-
-	eal_reset_internal_config(internal_conf);
-
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-		eal_long_options, &option_index)) != EOF) {
-
-		int ret;
-
-		/* getopt is not happy, stop right now */
-		if (opt == '?')
-			break;
-
-		ret = (opt == OPT_LOG_LEVEL_NUM) ?
-			eal_parse_common_option(opt, optarg,
-				internal_conf) : 0;
-
-		/* common parser is not happy */
-		if (ret < 0)
-			break;
-	}
-
-	optind = 0; /* reset getopt lib */
-}
-
 /* Parse the argument given in the command line of the application */
 static int
 eal_parse_args(int argc, char **argv)
Signature · 1 line
2.47.0
#475 lore raw

PATCH v32 3/12 eal: introduce log options parser

In reply to David Marchand

Rename existing log level option parser and add a little helper tracking all options related to logs.
This will make it easier to add more log options in the next commits.

---
 lib/eal/common/eal_common_options.c | 26 ++++++++++++++++++--------
 lib/eal/common/eal_options.h        |  3 ++-
 lib/eal/freebsd/eal.c               |  8 ++++----
 lib/eal/linux/eal.c                 |  8 ++++----
 lib/eal/windows/eal.c               |  7 ++++---
 5 files changed, 32 insertions(+), 20 deletions(-)
lib/eal/common/eal_common_options.c +18 -8
index 17c378f0c7..ab6cf8bebf 100644
@@ -1640,9 +1640,20 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
 	return -1;
 }
 
-/* Parse the arguments for --log-level only */
+bool
+eal_option_is_log(int opt)
+{
+	switch (opt) {
+	case OPT_LOG_LEVEL_NUM:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/* Parse all arguments looking for log related ones */
 int
-eal_log_level_parse(int argc, char * const argv[])
+eal_parse_log_options(int argc, char * const argv[])
 {
 	struct internal_config *internal_conf = eal_get_internal_configuration();
 	int option_index, opt;
@@ -1661,12 +1672,11 @@ eal_log_level_parse(int argc, char * const argv[])
 	while ((opt = getopt_long(argc, argv, eal_short_options,
 				  eal_long_options, &option_index)) != EOF) {
 
-		switch (opt) {
-		case OPT_LOG_LEVEL_NUM:
-			if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
-				return -1;
-			break;
-		}
+		if (!eal_option_is_log(opt))
+			continue;
+
+		if (eal_parse_common_option(opt, optarg, internal_conf) < 0)
+			return -1;
 	}
 
 	/* restore getopt lib */
lib/eal/common/eal_options.h +2 -1
index f3f2e104f6..06ba023c5a 100644
@@ -96,7 +96,8 @@ enum {
 extern const char eal_short_options[];
 extern const struct option eal_long_options[];
 
-int eal_log_level_parse(int argc, char * const argv[]);
+bool eal_option_is_log(int opt);
+int eal_parse_log_options(int argc, char * const argv[]);
 int eal_parse_common_option(int opt, const char *argv,
 			    struct internal_config *conf);
 int eal_option_device_parse(void);
lib/eal/freebsd/eal.c +4 -4
index 89dfc540f2..16b1c67cca 100644
@@ -393,8 +393,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_parse_log_options() already handled this option */
+		if (eal_option_is_log(opt))
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -575,8 +575,8 @@ rte_eal_init(int argc, char **argv)
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
+	/* parse log options as early as possible */
+	eal_parse_log_options(argc, argv);
 
 	if (rte_eal_cpu_init() < 0) {
 		rte_eal_init_alert("Cannot detect lcores.");
lib/eal/linux/eal.c +4 -4
index f82a398d4b..49a88cfbd5 100644
@@ -611,8 +611,8 @@ eal_parse_args(int argc, char **argv)
 			goto out;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_parse_log_options() already handled this option */
+		if (eal_option_is_log(opt))
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -951,8 +951,8 @@ rte_eal_init(int argc, char **argv)
 
 	eal_reset_internal_config(internal_conf);
 
-	/* set log level as early as possible */
-	eal_log_level_parse(argc, argv);
+	/* parse log options as early as possible */
+	eal_parse_log_options(argc, argv);
 
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
lib/eal/windows/eal.c +4 -3
index 25e69a429b..f77053eb7e 100644
@@ -121,8 +121,8 @@ eal_parse_args(int argc, char **argv)
 			return -1;
 		}
 
-		/* eal_log_level_parse() already handled this option */
-		if (opt == OPT_LOG_LEVEL_NUM)
+		/* eal_parse_log_options() already handled this option */
+		if (eal_option_is_log(opt))
 			continue;
 
 		ret = eal_parse_common_option(opt, optarg, internal_conf);
@@ -254,7 +254,8 @@ rte_eal_init(int argc, char **argv)
 
 	eal_log_init(NULL, 0);
 
-	eal_log_level_parse(argc, argv);
+	/* parse log options as early as possible */
+	eal_parse_log_options(argc, argv);
 
 	if (eal_create_cpu_map() < 0) {
 		rte_eal_init_alert("Cannot discover CPU and NUMA.");
Signature · 1 line
2.47.0
#476 lore raw

PATCH v32 4/12 eal: do not log init failure twice

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

The message already goes through logging, and does not need to be printed on stderr.
Message level should be ALERT to match function name.

---
 lib/eal/freebsd/eal.c | 3 +--
 lib/eal/linux/eal.c   | 3 +--
 lib/eal/windows/eal.c | 3 +--
 3 files changed, 3 insertions(+), 6 deletions(-)
lib/eal/freebsd/eal.c +1 -2
index 16b1c67cca..c84983ac3f 100644
@@ -530,8 +530,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /* Launch threads, called at application init(). */
lib/eal/linux/eal.c +1 -2
index 49a88cfbd5..3915cdb838 100644
@@ -831,8 +831,7 @@ rte_eal_iopl_init(void)
 
 static void rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /*
lib/eal/windows/eal.c +1 -2
index f77053eb7e..a3eb15ce00 100644
@@ -182,8 +182,7 @@ sync_func(void *arg __rte_unused)
 static void
 rte_eal_init_alert(const char *msg)
 {
-	fprintf(stderr, "EAL: FATAL: %s\n", msg);
-	EAL_LOG(ERR, "%s", msg);
+	EAL_LOG(ALERT, "%s", msg);
 }
 
 /* Stubs to enable EAL trace point compilation
Signature · 1 line
2.47.0
#477 lore raw

PATCH v32 5/12 eal: improve exit output log

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

The rte_exit() output format confuses the timestamp and coloring options. Change it to use be a single line with proper prefix.

Before:

[     0.006481] EAL: Error - exiting with code: 1
  Cause: [     0.006489] Cannot init EAL: Permission denied

After:

[     0.006238] EAL: Error - exiting with code: 1
[     0.006250] EAL: Cannot init EAL: Permission denied
---
 lib/eal/common/eal_common_debug.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
lib/eal/common/eal_common_debug.c +2 -4
index 3e77995896..bcfcd6df6f 100644
@@ -36,15 +36,13 @@ rte_exit(int exit_code, const char *format, ...)
 	va_list ap;
 
 	if (exit_code != 0)
-		RTE_LOG(CRIT, EAL, "Error - exiting with code: %d\n"
-				"  Cause: ", exit_code);
+		EAL_LOG(CRIT, "Error - exiting with code: %d", exit_code);
 
 	va_start(ap, format);
 	rte_vlog(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, format, ap);
 	va_end(ap);
 
 	if (rte_eal_cleanup() != 0 && rte_errno != EALREADY)
-		EAL_LOG(CRIT,
-			"EAL could not release all resources");
+		EAL_LOG(CRIT, "EAL could not release all resources");
 	exit(exit_code);
 }
Signature · 1 line
2.47.0
#478 lore raw

PATCH v32 6/12 log: rework syslog handling

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

Refactor how syslog is handled, make it common to Linux and FreeBSD The syslog facility property is better handled in lib/log rather than in eal.
This also adds syslog support to FreeBSD.

Log to syslog only if option is specified.
If no --syslog is given then use only standard error.

---
 app/test/test_eal_flags.c                     |  16 +--
 .../freebsd_gsg/freebsd_eal_parameters.rst    |  27 +++++
 .../prog_guide/env_abstraction_layer.rst      |   6 +-
 doc/guides/prog_guide/log_lib.rst             |   6 +-
 doc/guides/rel_notes/release_24_11.rst        |   6 +
 lib/eal/common/eal_common_options.c           |  57 +--------
 lib/eal/common/eal_internal_cfg.h             |   1 -
 lib/eal/freebsd/eal.c                         |   1 -
 lib/eal/linux/eal.c                           |   8 +-
 lib/eal/windows/eal.c                         |   2 +-
 lib/log/log.c                                 |  43 ++++---
 lib/log/log_freebsd.c                         |  12 --
 lib/log/log_internal.h                        |  11 +-
 lib/log/log_linux.c                           |  61 ----------
 lib/log/log_private.h                         |  27 +++++
 lib/log/log_syslog.c                          | 108 ++++++++++++++++++
 lib/log/log_windows.c                         |  18 ---
 lib/log/meson.build                           |   6 +-
 lib/log/version.map                           |   2 +-
 19 files changed, 220 insertions(+), 198 deletions(-)
 delete mode 100644 lib/log/log_freebsd.c
 delete mode 100644 lib/log/log_linux.c
 create mode 100644 lib/log/log_private.h
 create mode 100644 lib/log/log_syslog.c
 delete mode 100644 lib/log/log_windows.c
app/test/test_eal_flags.c +8 -8
index 71d8dba731..9fcf0d56e6 100644
@@ -985,12 +985,12 @@ test_misc_flags(void)
 	/* With -v */
 	const char *argv2[] = {prgname, prefix, mp_flag, "-v"};
 	/* With valid --syslog */
-	const char *argv3[] = {prgname, prefix, mp_flag,
-			"--syslog", "syslog"};
-	/* With empty --syslog (should fail) */
+	const char *argv3[] = {prgname, prefix, mp_flag, "--syslog=user"};
+	/* With empty --syslog (now defaults) */
 	const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"};
 	/* 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};
@@ -1080,15 +1080,15 @@ test_misc_flags(void)
 #endif
 
 	if (launch_proc(argv3) != 0) {
-		printf("Error - process did not run ok with --syslog flag\n");
+		printf("Error - process did not run ok with --syslog=user flag\n");
 		goto fail;
 	}
-	if (launch_proc(argv4) == 0) {
-		printf("Error - process run ok with empty --syslog flag\n");
+	if (launch_proc(argv4) != 0) {
+		printf("Error - process did not run ok with --syslog flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv5) == 0) {
-		printf("Error - process run ok with invalid --syslog flag\n");
+		printf("Error - process run ok with --syslog=invalid flag\n");
 		goto fail;
 	}
 	if (launch_proc(argv7) != 0) {
doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +27 -0
index fba467a2ce..9270d9fa3b 100644
@@ -18,3 +18,30 @@ FreeBSD-specific EAL parameters
 -------------------------------
 
 There are currently no FreeBSD-specific EAL command-line parameters available.
+
+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
doc/guides/prog_guide/env_abstraction_layer.rst +3 -3
index 272aeeb4ba..04214a05b2 100644
@@ -884,9 +884,9 @@ Signal Safety
   Other functions are not signal safe because they use one or more
   library routines that are not themselves signal safe.
   For example, calling ``rte_panic()`` is not safe in a signal handler
-  because it uses ``rte_log()`` and ``rte_log()`` calls the
-  ``syslog()`` library function which is in the list of
-  signal safe functions in
+  because it uses ``rte_log()`` and ``rte_log()`` may call ``vfprintf()`` or
+  ``syslog()`` library functions which are not in the list of
+  signal safe functions
   `Signal-Safety manual page <https://man7.org/linux/man-pages/man7/signal-safety.7.html>`_.
 
   The set of functions that are expected to be async-signal-safe in DPDK
doc/guides/prog_guide/log_lib.rst +3 -3
index ff9d1b54a2..9cee75b88c 100644
@@ -5,9 +5,9 @@ Log Library
 ===========
 
 The DPDK Log library provides the logging functionality for other DPDK libraries and drivers.
-By default, in a Linux application, logs are sent to syslog and also to the console.
-On FreeBSD and Windows applications, logs are sent only to the console.
-However, the log function can be overridden by the user to use a different logging mechanism.
+By default, logs are sent only to standard error output of the process.
+The syslog EAL option can be used to redirect to the stystem logger on Linux and FreeBSD.
+In addition, the log can be redirected to a different stdio file stream.
 
 Log Levels
 ----------
doc/guides/rel_notes/release_24_11.rst +6 -0
index d93343fd52..f27d283fab 100644
@@ -114,6 +114,12 @@ New Features
   (and vice versa); freeing the same pointer twice in the same routine;
   freeing an object that was not created by allocation; etc.
 
+* **Updated logging library**
+
+  * The syslog option has changed.
+    By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
+    Syslog is also supported on FreeBSD (but not on Windows).
+
 * **Updated Marvell cnxk mempool driver.**
 
   * Added mempool driver support for CN20K SoC.
lib/eal/common/eal_common_options.c +6 -51

99 lines not on this page · raw message

lib/eal/common/eal_internal_cfg.h +0 -1
index 167ec501fa..f53ab8b4aa 100644
@@ -84,7 +84,6 @@ struct internal_config {
 	/**< true if storing all pages within single files (per-page-size,
 	 * per-node) non-legacy mode only.
 	 */
-	volatile int syslog_facility;	  /**< facility passed to openlog() */
 	/** default interrupt mode for VFIO */
 	volatile enum rte_intr_mode vfio_intr_mode;
 	/** the shared VF token for VFIO-PCI bound PF and VFs devices */
lib/eal/freebsd/eal.c +0 -1
index c84983ac3f..e7fd4f141e 100644
@@ -11,7 +11,6 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <pthread.h>
-#include <syslog.h>
 #include <getopt.h>
 #include <sys/file.h>
 #include <stddef.h>
lib/eal/linux/eal.c +1 -7
index 3915cdb838..c321ea87f3 100644
@@ -1104,13 +1104,7 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	if (eal_log_init(program_invocation_short_name,
-			 internal_conf->syslog_facility) < 0) {
-		rte_eal_init_alert("Cannot init logging.");
-		rte_errno = ENOMEM;
-		rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed);
-		return -1;
-	}
+	eal_log_init(program_invocation_short_name);
 
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
lib/eal/windows/eal.c +1 -1
index a3eb15ce00..b948c52670 100644
@@ -251,7 +251,7 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL, 0);
+	eal_log_init(NULL);
 
 	/* parse log options as early as possible */
 	eal_parse_log_options(argc, argv);
lib/log/log.c +20 -23

90 lines not on this page · raw message

lib/log/log_freebsd.c deleted +0 -12
deleted file mode 100644
index 698d3c5423..0000000000
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2023 Intel Corporation
- */
-
-#include <rte_common.h>
-#include "log_internal.h"
-
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	return 0;
-}
lib/log/log_internal.h +4 -7
index 451629f1c1..3c46328e7b 100644
@@ -14,13 +14,7 @@
  * Initialize the default log stream.
  */
 __rte_internal
-int eal_log_init(const char *id, int facility);
-
-/*
- * Determine where log data is written when no call to rte_openlog_stream.
- */
-__rte_internal
-void eal_log_set_default(FILE *default_log);
+void eal_log_init(const char *id);
 
 /*
  * Save a log option for later.
@@ -30,6 +24,9 @@ int eal_log_save_regexp(const char *regexp, uint32_t level);
 __rte_internal
 int eal_log_save_pattern(const char *pattern, uint32_t level);
 
+__rte_internal
+int eal_log_syslog(const char *name);
+
 /*
  * Convert log level to string.
  */
lib/log/log_linux.c deleted +0 -61

61 lines not on this page · raw message

lib/log/log_private.h new file +27 -0
new file mode 100644
index 0000000000..d5a8bf271a
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#ifndef LOG_PRIVATE_H
+#define LOG_PRIVATE_H
+
+/* Defined in limits.h on Linux */
+#ifndef LINE_MAX
+#define LINE_MAX	2048 /* _POSIX2_LINE_MAX */
+#endif
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+static inline bool
+log_syslog_enabled(void)
+{
+	return false;
+}
+static inline FILE *
+log_syslog_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#else
+bool log_syslog_enabled(void);
+FILE *log_syslog_open(const char *id);
+#endif
+
+#endif /* LOG_PRIVATE_H */
lib/log/log_syslog.c new file +108 -0

108 lines not on this page · raw message

lib/log/log_windows.c deleted +0 -18
deleted file mode 100644
index a6a0889550..0000000000
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2017-2018 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_log.h>
-#include "log_internal.h"
-
-/* set the log to default function, called during eal init process. */
-int
-eal_log_init(__rte_unused const char *id, __rte_unused int facility)
-{
-	rte_openlog_stream(stderr);
-
-	eal_log_set_default(stderr);
-
-	return 0;
-}
lib/log/meson.build +5 -1
index 0d4319b36f..160cf34f50 100644
@@ -4,6 +4,10 @@
 includes += global_inc
 sources = files(
         'log.c',
-        'log_' + exec_env + '.c',
 )
+
+if not is_windows
+    sources += files('log_syslog.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -1
index 19d7f9cdb6..1637fba3b9 100644
@@ -29,6 +29,6 @@ INTERNAL {
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
-	eal_log_set_default;
+	eal_log_syslog; # WINDOWS_NO_EXPORT
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.47.0
#479 lore raw

PATCH v32 7/12 eal: initialize log before everything else

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

In order for all log messages (including CPU mismatch) to come out through the logging library, it must be initialized as early in rte_eal_init() as possible on all platforms.

Where it was done before was likely historical, based on the support of non-OS isolated CPU's which required a shared memory buffer. That support was dropped before DPDK was publicly released.

---
 doc/guides/rel_notes/release_24_11.rst |  2 ++
 lib/eal/freebsd/eal.c                  | 13 ++++++++++---
 lib/eal/linux/eal.c                    | 14 +++++++++-----
 lib/eal/windows/eal.c                  | 10 +++++++---
 4 files changed, 28 insertions(+), 11 deletions(-)
doc/guides/rel_notes/release_24_11.rst +2 -0
index f27d283fab..3853af2798 100644
@@ -116,6 +116,8 @@ New Features
 
 * **Updated logging library**
 
+  * The log subsystem is initialized earlier in startup so all messages go through the library.
+
   * The syslog option has changed.
     By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
     Syslog is also supported on FreeBSD (but not on Windows).
lib/eal/freebsd/eal.c +10 -3
index e7fd4f141e..a96bbf5836 100644
@@ -53,6 +53,7 @@
 #include "eal_options.h"
 #include "eal_memcfg.h"
 #include "eal_trace.h"
+#include "log_internal.h"
 
 #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
 
@@ -547,6 +548,15 @@ rte_eal_init(int argc, char **argv)
 	bool has_phys_addr;
 	enum rte_iova_mode iova_mode;
 
+	/* setup log as early as possible */
+	if (eal_parse_log_options(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(getprogname());
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -573,9 +583,6 @@ rte_eal_init(int argc, char **argv)
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
-	/* parse log options as early as possible */
-	eal_parse_log_options(argc, argv);
-
 	if (rte_eal_cpu_init() < 0) {
 		rte_eal_init_alert("Cannot detect lcores.");
 		rte_errno = ENOTSUP;
lib/eal/linux/eal.c +9 -5
index c321ea87f3..a6220524a4 100644
@@ -927,6 +927,15 @@ rte_eal_init(int argc, char **argv)
 	struct internal_config *internal_conf =
 		eal_get_internal_configuration();
 
+	/* setup log as early as possible */
+	if (eal_parse_log_options(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	eal_log_init(program_invocation_short_name);
+
 	/* checks if the machine is adequate */
 	if (!rte_cpu_is_supported()) {
 		rte_eal_init_alert("unsupported cpu type.");
@@ -950,9 +959,6 @@ rte_eal_init(int argc, char **argv)
 
 	eal_reset_internal_config(internal_conf);
 
-	/* parse log options as early as possible */
-	eal_parse_log_options(argc, argv);
-
 	/* clone argv to report out later in telemetry */
 	eal_save_args(argc, argv);
 
@@ -1104,8 +1110,6 @@ rte_eal_init(int argc, char **argv)
 #endif
 	}
 
-	eal_log_init(program_invocation_short_name);
-
 #ifdef VFIO_PRESENT
 	if (rte_vfio_enable("vfio")) {
 		rte_eal_init_alert("Cannot init VFIO");
lib/eal/windows/eal.c +7 -3
index b948c52670..5cdc053a02 100644
@@ -251,10 +251,14 @@ rte_eal_init(int argc, char **argv)
 	char cpuset[RTE_CPU_AFFINITY_STR_LEN];
 	char thread_name[RTE_THREAD_NAME_SIZE];
 
-	eal_log_init(NULL);
+	/* setup log as early as possible */
+	if (eal_parse_log_options(argc, argv) < 0) {
+		rte_eal_init_alert("invalid log arguments.");
+		rte_errno = EINVAL;
+		return -1;
+	}
 
-	/* parse log options as early as possible */
-	eal_parse_log_options(argc, argv);
+	eal_log_init(NULL);
 
 	if (eal_create_cpu_map() < 0) {
 		rte_eal_init_alert("Cannot discover CPU and NUMA.");
Signature · 1 line
2.47.0
#480 lore raw

PATCH v32 8/12 log: add hook for printing log messages

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

This is useful for when decorating log output for console or journal. Provide basic version in this patch.

---
 lib/log/log.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
lib/log/log.c +7 -1
index a5cae1f950..dbff223108 100644
@@ -29,16 +29,21 @@ struct rte_log_dynamic_type {
 	uint32_t loglevel;
 };
 
+/* Note: same as vfprintf() */
+typedef int (*log_print_t)(FILE *f, const char *fmt, 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. */
+	log_print_t print_func;
 	size_t dynamic_types_len;
 	struct rte_log_dynamic_type *dynamic_types;
 } rte_logs = {
 	.type = UINT32_MAX,
 	.level = RTE_LOG_DEBUG,
+	.print_func = vfprintf,
 };
 
 struct rte_eal_opt_loglevel {
@@ -75,6 +80,7 @@ int
 rte_openlog_stream(FILE *f)
 {
 	rte_logs.file = f;
+	rte_logs.print_func = vfprintf;
 	return 0;
 }
 
@@ -471,7 +477,7 @@ rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap)
 	RTE_PER_LCORE(log_cur_msg).loglevel = level;
 	RTE_PER_LCORE(log_cur_msg).logtype = logtype;
 
-	ret = vfprintf(f, format, ap);
+	ret = (*rte_logs.print_func)(f, format, ap);
 	fflush(f);
 	return ret;
 }
Signature · 1 line
2.47.0
#481 lore raw

PATCH v32 9/12 log: add timestamp option

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

When debugging driver or startup issues, it is useful to have a timestamp on each message printed.
The messages in syslog already have a timestamp, but often syslog is not available during testing.

There are multiple timestamp formats similar to Linux dmesg. The default is time relative since startup (when first step of logging initialization is done by constructor).
Other alternative formats are delta, ctime, reltime and iso formats.

Example:

$ dpdk-testpmd --log-timestamp -- -i
[     0.008610] EAL: Detected CPU lcores: 8
[     0.008634] EAL: Detected NUMA nodes: 1
[     0.008792] EAL: Detected static linkage of DPDK
[     0.010620] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
[     0.012618] EAL: Selected IOVA mode 'VA'
[     0.016675] testpmd: No probed ethernet devices
Interactive-mode selected

Note: Windows does not have localtime_r but it does have a similar function that can be used instead. Add it to rte_os_shim.h.

---
 app/test/test_eal_flags.c              |  24 +++
 doc/guides/prog_guide/log_lib.rst      |  28 +++
 doc/guides/rel_notes/release_24_11.rst |   2 +
 lib/eal/common/eal_common_options.c    |  14 +-
 lib/eal/common/eal_options.h           |   2 +
 lib/eal/windows/include/rte_os_shim.h  |  10 ++
 lib/log/log.c                          |  13 +-
 lib/log/log_internal.h                 |   9 +
 lib/log/log_private.h                  |   6 +
 lib/log/log_timestamp.c                | 240 +++++++++++++++++++++++++
 lib/log/meson.build                    |   1 +
 lib/log/version.map                    |   1 +
 12 files changed, 344 insertions(+), 6 deletions(-)
 create mode 100644 lib/log/log_timestamp.c
app/test/test_eal_flags.c +24 -0
index 9fcf0d56e6..1a062fe0e8 100644
@@ -1055,6 +1055,18 @@ test_misc_flags(void)
 	const char * const argv22[] = {prgname, prefix, mp_flag,
 				       "--huge-worker-stack=512"};
 
+	/* Try running with --log-timestamp */
+	const char * const argv23[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp" };
+
+	/* Try running with --log-timestamp=iso */
+	const char * const argv24[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=iso" };
+
+	/* Try running with invalid timestamp */
+	const char * const argv25[] = {prgname, prefix, mp_flag,
+				       "--log-timestamp=invalid" };
+
 	/* run all tests also applicable to FreeBSD first */
 
 	if (launch_proc(argv0) == 0) {
@@ -1162,6 +1174,18 @@ test_misc_flags(void)
 		printf("Error - process did not run ok with --huge-worker-stack=size parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv23) != 0) {
+		printf("Error - process did not run ok with --log-timestamp parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv24) != 0) {
+		printf("Error - process did not run ok with --log-timestamp=iso parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv25) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
 
 	rmdir(hugepath_dir3);
 	rmdir(hugepath_dir2);
doc/guides/prog_guide/log_lib.rst +28 -0
index 9cee75b88c..a2e95317f5 100644
@@ -110,3 +110,31 @@ Throughout the cfgfile library, all logging calls are therefore of the form:
 
 	CFG_LOG(ERR, "invalid comment characters %c",
 	       params->comment_character);
+
+Log timestamp
+~~~~~~~~~~~~~
+
+An optional timestamp can be added before each message by adding the ``--log-timestamp`` option.
+For example::
+
+	/path/to/app --log-level=lib.*:debug --log-timestamp
+
+Multiple alternative timestamp formats are available:
+
+.. csv-table:: Log time stamp format
+   :header: "Format", "Description", "Example"
+   :widths: 6, 30, 32
+
+   "ctime", "Unix ctime", "``[Wed Mar 20 07:26:12 2024]``"
+   "delta", "Offset since last", "``[<    3.162373>]``"
+   "reltime", "Seconds since last or time if minute changed", "``[  +3.001791]`` or ``[Mar20 07:26:12]``"
+   "iso", "ISO-8601", "``[2024-03-20T07:26:12−07:00]``"
+
+To prefix all console messages with ISO format time the syntax is::
+
+	/path/to/app --log-timestamp=iso
+
+.. note::
+
+   Timestamp option has no effect if using syslog
+   because the ``syslog()`` service already does timestamping internally.
doc/guides/rel_notes/release_24_11.rst +2 -0
index 3853af2798..d1226c78d1 100644
@@ -122,6 +122,8 @@ New Features
     By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
     Syslog is also supported on FreeBSD (but not on Windows).
 
+  * Log messages can be timestamped with ``--log-timestamp`` option.
+
 * **Updated Marvell cnxk mempool driver.**
 
   * Added mempool driver support for CN20K SoC.
lib/eal/common/eal_common_options.c +12 -2
index 9f4feb2611..7de6a25e62 100644
@@ -74,6 +74,7 @@ eal_long_options[] = {
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
+	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
 	{OPT_TRACE_DIR,         1, NULL, OPT_TRACE_DIR_NUM        },
 	{OPT_TRACE_BUF_SIZE,    1, NULL, OPT_TRACE_BUF_SIZE_NUM   },
@@ -1599,6 +1600,7 @@ eal_option_is_log(int opt)
 {
 	switch (opt) {
 	case OPT_LOG_LEVEL_NUM:
+	case OPT_LOG_TIMESTAMP_NUM:
 	case OPT_SYSLOG_NUM:
 		return true;
 	default:
@@ -1850,7 +1852,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		break;
 #endif
 
-	case OPT_LOG_LEVEL_NUM: {
+	case OPT_LOG_LEVEL_NUM:
 		if (eal_parse_log_level(optarg) < 0) {
 			EAL_LOG(ERR,
 				"invalid parameters for --"
@@ -1858,7 +1860,14 @@ eal_parse_common_option(int opt, const char *optarg,
 			return -1;
 		}
 		break;
-	}
+
+	case OPT_LOG_TIMESTAMP_NUM:
+		if (eal_log_timestamp(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_TIMESTAMP);
+			return -1;
+		}
+		break;
 
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
@@ -2225,6 +2234,7 @@ eal_common_usage(void)
 	       "  --"OPT_LOG_LEVEL"=<type-match>:<level>\n"
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
+	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index 06ba023c5a..a1b52ae694 100644
@@ -35,6 +35,8 @@ enum {
 	OPT_LCORES_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
+#define OPT_LOG_TIMESTAMP     "log-timestamp"
+	OPT_LOG_TIMESTAMP_NUM,
 #define OPT_TRACE             "trace"
 	OPT_TRACE_NUM,
 #define OPT_TRACE_DIR         "trace-dir"
lib/eal/windows/include/rte_os_shim.h +10 -0
index eda8113662..665c9ac93b 100644
@@ -110,4 +110,14 @@ rte_clock_gettime(clockid_t clock_id, struct timespec *tp)
 }
 #define clock_gettime(clock_id, tp) rte_clock_gettime(clock_id, tp)
 
+static inline struct tm *
+rte_localtime_r(const time_t *timep, struct tm *result)
+{
+	if (localtime_s(result, timep) == 0)
+		return result;
+	else
+		return NULL;
+}
+#define localtime_r(timep, result) rte_localtime_r(timep, result)
+
 #endif /* _RTE_OS_SHIM_ */
lib/log/log.c +9 -4
index dbff223108..854d77887b 100644
@@ -17,13 +17,13 @@
 #include <rte_log.h>
 #include <rte_per_lcore.h>
 
-#include "log_internal.h"
-#include "log_private.h"
-
 #ifdef RTE_EXEC_ENV_WINDOWS
-#define strdup _strdup
+#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;
@@ -513,6 +513,11 @@ eal_log_init(const char *id)
 	if (logf)
 		rte_openlog_stream(logf);
 
+	if (log_timestamp_enabled())
+		rte_logs.print_func = log_print_with_timestamp;
+	else
+		rte_logs.print_func = vfprintf;
+
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
 		"Debug dataplane logs available - lower performance\n");
lib/log/log_internal.h +9 -0
index 3c46328e7b..7c7d44eed2 100644
@@ -5,8 +5,10 @@
 #ifndef LOG_INTERNAL_H
 #define LOG_INTERNAL_H
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <time.h>
 
 #include <rte_compat.h>
 
@@ -39,4 +41,11 @@ const char *eal_log_level2str(uint32_t level);
 __rte_internal
 void rte_eal_log_cleanup(void);
 
+/*
+ * Add timestamp to console logs
+ */
+__rte_internal
+int eal_log_timestamp(const char *fmt);
+
+
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +6 -0
index d5a8bf271a..5da9c9b438 100644
@@ -24,4 +24,10 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+bool log_timestamp_enabled(void);
+ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
+
+__rte_format_printf(2, 0)
+int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/log_timestamp.c new file +240 -0

240 lines not on this page · raw message

lib/log/meson.build +1 -0
index 160cf34f50..4ac232786e 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_timestamp.c',
 )
 
 if not is_windows
lib/log/version.map +1 -0
index 1637fba3b9..8be6907840 100644
@@ -30,5 +30,6 @@ INTERNAL {
 	eal_log_save_pattern;
 	eal_log_save_regexp;
 	eal_log_syslog; # WINDOWS_NO_EXPORT
+	eal_log_timestamp;
 	rte_eal_log_cleanup;
 };
Signature · 1 line
2.47.0
#482 lore raw

PATCH v32 10/12 log: support systemd journal

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

If DPDK application is being run as a systemd service, then it can use the journal protocol which allows putting more information in the log such as priority and other information.

The use of journal protocol is automatically detected and handled. Rather than having a dependency on libsystemd, just use the protocol directly as defined in:
https://systemd.io/JOURNAL_NATIVE_PROTOCOL/

---
 doc/guides/rel_notes/release_24_11.rst |   4 +
 lib/log/log.c                          |  31 +++--
 lib/log/log_internal.h                 |   3 +
 lib/log/log_journal.c                  | 153 +++++++++++++++++++++++++
 lib/log/log_private.h                  |  16 +++
 lib/log/meson.build                    |   4 +
 lib/log/version.map                    |   1 +
 7 files changed, 200 insertions(+), 12 deletions(-)
 create mode 100644 lib/log/log_journal.c
doc/guides/rel_notes/release_24_11.rst +4 -0
index d1226c78d1..341606f541 100644
@@ -118,6 +118,10 @@ New Features
 
   * The log subsystem is initialized earlier in startup so all messages go through the library.
 
+  * If the application is a systemd service and the log output is being sent to standard error
+    then DPDK will switch to journal native protocol.
+    This allows the more data such as severity to be sent.
+
   * The syslog option has changed.
     By default, messages are no longer sent to syslog unless the ``--syslog`` option is specified.
     Syslog is also supported on FreeBSD (but not on Windows).
lib/log/log.c +19 -12
index 854d77887b..0974adc81f 100644
@@ -505,18 +505,25 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...)
 void
 eal_log_init(const char *id)
 {
-	FILE *logf = NULL;
-
-	if (log_syslog_enabled())
-		logf = log_syslog_open(id);
-
-	if (logf)
-		rte_openlog_stream(logf);
-
-	if (log_timestamp_enabled())
-		rte_logs.print_func = log_print_with_timestamp;
-	else
-		rte_logs.print_func = vfprintf;
+	/* If user has already set a log stream, then use it. */
+	if (rte_logs.file == NULL) {
+		FILE *logf = NULL;
+
+		/* if stderr is associated with systemd environment */
+		if (log_journal_enabled())
+			logf = log_journal_open(id);
+		/* If --syslog option was passed */
+		else if (log_syslog_enabled())
+			logf = log_syslog_open(id);
+
+		/* if either syslog or journal is used, then no special handling */
+		if (logf)
+			rte_openlog_stream(logf);
+		else if (log_timestamp_enabled())
+			rte_logs.print_func = log_print_with_timestamp;
+		else
+			rte_logs.print_func = vfprintf;
+	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
lib/log/log_internal.h +3 -0
index 7c7d44eed2..82fdc21ac2 100644
@@ -29,6 +29,9 @@ int eal_log_save_pattern(const char *pattern, uint32_t level);
 __rte_internal
 int eal_log_syslog(const char *name);
 
+__rte_internal
+int eal_log_journal(const char *opt);
+
 /*
  * Convert log level to string.
  */
lib/log/log_journal.c new file +153 -0

153 lines not on this page · raw message

lib/log/log_private.h +16 -0
index 5da9c9b438..1b66057fd6 100644
@@ -24,6 +24,22 @@ bool log_syslog_enabled(void);
 FILE *log_syslog_open(const char *id);
 #endif
 
+#ifdef RTE_EXEC_ENV_LINUX
+bool log_journal_enabled(void);
+FILE *log_journal_open(const char *id);
+#else
+static inline bool
+log_journal_enabled(void)
+{
+	return false;
+}
+static inline FILE *
+log_journal_open(const char *id __rte_unused)
+{
+	return NULL;
+}
+#endif /* !RTE_EXEC_ENV_LINUX */
+
 bool log_timestamp_enabled(void);
 ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 
lib/log/meson.build +4 -0
index 4ac232786e..86e4452b19 100644
@@ -11,4 +11,8 @@ if not is_windows
     sources += files('log_syslog.c')
 endif
 
+if is_linux
+    sources += files('log_journal.c')
+endif
+
 headers = files('rte_log.h')
lib/log/version.map +1 -0
index 8be6907840..800d3943bc 100644
@@ -26,6 +26,7 @@ INTERNAL {
 	global:
 
 	eal_log_init;
+	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
 	eal_log_save_pattern;
 	eal_log_save_regexp;
Signature · 1 line
2.47.0
#483 lore raw

PATCH v32 11/12 log: colorize log output

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

Like dmesg, colorize the log output (unless redirected to file). Timestamp is green, the subsystem is in yellow and the message is red if urgent, boldface if an error, and normal for info and debug messages.

The default is to not use color since it may disturb automatic tests and other embedded usage.

Note: add fileno() and isatty() to the Windows wrapper.

---
 app/test/test_eal_flags.c              |  24 +++
 doc/guides/prog_guide/log_lib.rst      |  24 +++
 doc/guides/rel_notes/release_24_11.rst |   2 +
 lib/eal/common/eal_common_options.c    |  11 ++
 lib/eal/common/eal_options.h           |   2 +
 lib/eal/windows/include/rte_os_shim.h  |   2 +
 lib/log/log.c                          |  23 ++-
 lib/log/log_color.c                    | 214 +++++++++++++++++++++++++
 lib/log/log_internal.h                 |   5 +
 lib/log/log_private.h                  |   8 +
 lib/log/meson.build                    |   1 +
 lib/log/version.map                    |   1 +
 12 files changed, 312 insertions(+), 5 deletions(-)
 create mode 100644 lib/log/log_color.c
app/test/test_eal_flags.c +24 -0
index 1a062fe0e8..d37d6b8627 100644
@@ -1067,6 +1067,18 @@ test_misc_flags(void)
 	const char * const argv25[] = {prgname, prefix, mp_flag,
 				       "--log-timestamp=invalid" };
 
+	/* Try running with --log-color */
+	const char * const argv26[] = {prgname, prefix, mp_flag,
+				       "--log-color" };
+
+	/* Try running with --log-color=never */
+	const char * const argv27[] = {prgname, prefix, mp_flag,
+				       "--log-color=never" };
+
+	/* Try running with --log-color=invalid */
+	const char * const argv28[] = {prgname, prefix, mp_flag,
+				       "--log-color=invalid" };
+
 	/* run all tests also applicable to FreeBSD first */
 
 	if (launch_proc(argv0) == 0) {
@@ -1186,6 +1198,18 @@ test_misc_flags(void)
 		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
 		goto fail;
 	}
+	if (launch_proc(argv26) != 0) {
+		printf("Error - process did not run ok with --log-color parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv27) != 0) {
+		printf("Error - process did not run ok with --log-color=never parameter\n");
+		goto fail;
+	}
+	if (launch_proc(argv28) == 0) {
+		printf("Error - process did run ok with --log-timestamp=invalid parameter\n");
+		goto fail;
+	}
 
 	rmdir(hugepath_dir3);
 	rmdir(hugepath_dir2);
doc/guides/prog_guide/log_lib.rst +24 -0
index a2e95317f5..3e888b8965 100644
@@ -59,6 +59,7 @@ For example::
 
 Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.
 
+
 Using Logging APIs to Generate Log Messages
 -------------------------------------------
 
@@ -138,3 +139,26 @@ To prefix all console messages with ISO format time the syntax is::
 
    Timestamp option has no effect if using syslog
    because the ``syslog()`` service already does timestamping internally.
+
+
+Color output
+~~~~~~~~~~~~
+
+The log library will highlight important messages.
+This is controlled by the ``--log-color`` option.
+The optional argument describes when color is enabled:
+
+:never: Do not enable color. This is the default behavior.
+
+:auto: Enable color only when printing to a terminal.
+       This is the same as ``--log-color`` with no argument.
+
+:always: Always print color.
+
+For example to enable color in logs if using terminal::
+
+	/path/to/app --log-color
+
+.. note::
+
+   Color output is never used for syslog or systemd journal logging.
doc/guides/rel_notes/release_24_11.rst +2 -0
index 341606f541..543becba28 100644
@@ -128,6 +128,8 @@ New Features
 
   * Log messages can be timestamped with ``--log-timestamp`` option.
 
+  * Log messages can be colorized with the ``--log-color`` option.
+
 * **Updated Marvell cnxk mempool driver.**
 
   * Added mempool driver support for CN20K SoC.
lib/eal/common/eal_common_options.c +11 -0
index 7de6a25e62..79db9a47dd 100644
@@ -73,6 +73,7 @@ eal_long_options[] = {
 	{OPT_HUGE_UNLINK,       2, NULL, OPT_HUGE_UNLINK_NUM      },
 	{OPT_IOVA_MODE,	        1, NULL, OPT_IOVA_MODE_NUM        },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
+	{OPT_LOG_COLOR,		2, NULL, OPT_LOG_COLOR_NUM	  },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
 	{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },
 	{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },
@@ -1599,6 +1600,7 @@ bool
 eal_option_is_log(int opt)
 {
 	switch (opt) {
+	case OPT_LOG_COLOR_NUM:
 	case OPT_LOG_LEVEL_NUM:
 	case OPT_LOG_TIMESTAMP_NUM:
 	case OPT_SYSLOG_NUM:
@@ -1869,6 +1871,14 @@ eal_parse_common_option(int opt, const char *optarg,
 		}
 		break;
 
+	case OPT_LOG_COLOR_NUM:
+		if (eal_log_color(optarg) < 0) {
+			EAL_LOG(ERR, "invalid parameters for --"
+				OPT_LOG_COLOR);
+			return -1;
+		}
+		break;
+
 #ifndef RTE_EXEC_ENV_WINDOWS
 	case OPT_TRACE_NUM: {
 		if (eal_trace_args_save(optarg) < 0) {
@@ -2235,6 +2245,7 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  --"OPT_LOG_LEVEL"=help    Show log types and levels\n"
 	       "  --"OPT_LOG_TIMESTAMP"[=<format>]  Timestamp log output\n"
+	       "  --"OPT_LOG_COLOR"[=<when>] Colorize log messages\n"
 #ifndef RTE_EXEC_ENV_WINDOWS
 	       "  --"OPT_TRACE"=<regex-match>\n"
 	       "                      Enable trace based on regular expression trace name.\n"
lib/eal/common/eal_options.h +2 -0
index a1b52ae694..95fb4f6108 100644
@@ -33,6 +33,8 @@ enum {
 	OPT_HUGE_UNLINK_NUM,
 #define OPT_LCORES            "lcores"
 	OPT_LCORES_NUM,
+#define OPT_LOG_COLOR	      "log-color"
+	OPT_LOG_COLOR_NUM,
 #define OPT_LOG_LEVEL         "log-level"
 	OPT_LOG_LEVEL_NUM,
 #define OPT_LOG_TIMESTAMP     "log-timestamp"
lib/eal/windows/include/rte_os_shim.h +2 -0
index 665c9ac93b..0e74eb19c7 100644
@@ -30,6 +30,8 @@
 #define write(fd, buf, n) _write(fd, buf, n)
 #define close(fd) _close(fd)
 #define unlink(path) _unlink(path)
+#define fileno(f) _fileno(f)
+#define isatty(fd) _isatty(fd)
 
 #define IPVERSION	4
 
lib/log/log.c +18 -5
index 0974adc81f..eb087d601e 100644
@@ -12,6 +12,7 @@
 #include <regex.h>
 #include <fnmatch.h>
 #include <sys/queue.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -517,12 +518,24 @@ eal_log_init(const char *id)
 			logf = log_syslog_open(id);
 
 		/* if either syslog or journal is used, then no special handling */
-		if (logf)
+		if (logf) {
 			rte_openlog_stream(logf);
-		else if (log_timestamp_enabled())
-			rte_logs.print_func = log_print_with_timestamp;
-		else
-			rte_logs.print_func = vfprintf;
+		} else {
+			bool is_terminal = isatty(fileno(stderr));
+			bool use_color = log_color_enabled(is_terminal);
+
+			if (log_timestamp_enabled()) {
+				if (use_color)
+					rte_logs.print_func = color_print_with_timestamp;
+				else
+					rte_logs.print_func = log_print_with_timestamp;
+			} else {
+				if (use_color)
+					rte_logs.print_func = color_print;
+				else
+					rte_logs.print_func = vfprintf;
+			}
+		}
 	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
lib/log/log_color.c new file +214 -0

214 lines not on this page · raw message

lib/log/log_internal.h +5 -0
index 82fdc21ac2..bba7041ea3 100644
@@ -50,5 +50,10 @@ void rte_eal_log_cleanup(void);
 __rte_internal
 int eal_log_timestamp(const char *fmt);
 
+/*
+ * Enable or disable color in log messages
+ */
+__rte_internal
+int eal_log_color(const char *mode);
 
 #endif /* LOG_INTERNAL_H */
lib/log/log_private.h +8 -0
index 1b66057fd6..f275346c7b 100644
@@ -46,4 +46,12 @@ ssize_t log_timestamp(char *tsbuf, size_t tsbuflen);
 __rte_format_printf(2, 0)
 int log_print_with_timestamp(FILE *f, const char *format, va_list ap);
 
+bool log_color_enabled(bool is_tty);
+
+__rte_format_printf(2, 0)
+int color_print(FILE *f, const char *format, va_list ap);
+
+__rte_format_printf(2, 0)
+int color_print_with_timestamp(FILE *f, const char *format, va_list ap);
+
 #endif /* LOG_PRIVATE_H */
lib/log/meson.build +1 -0
index 86e4452b19..b3de57b9c7 100644
@@ -4,6 +4,7 @@
 includes += global_inc
 sources = files(
         'log.c',
+        'log_color.c',
         'log_timestamp.c',
 )
 
lib/log/version.map +1 -0
index 800d3943bc..09d8a4289b 100644
@@ -25,6 +25,7 @@ DPDK_25 {
 INTERNAL {
 	global:
 
+	eal_log_color;
 	eal_log_init;
 	eal_log_journal; # WINDOWS_NO_EXPORT
 	eal_log_level2str;
Signature · 1 line
2.47.0
#484 lore raw

PATCH v32 12/12 maintainers: update for log library

In reply to David Marchand

From: Stephen Hemminger <[email protected]>

"You touch it you own it".
Add myself as maintainer for log library.

---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)
MAINTAINERS +1 -0
index 0eacf60b5a..0697924ff0 100644
@@ -193,6 +193,7 @@ F: app/test/test_threads.c
 F: app/test/test_version.c
 
 Logging
+M: Stephen Hemminger <[email protected]>
 F: lib/log/
 F: doc/guides/prog_guide/log_lib.rst
 F: app/test/test_logs.c
Signature · 1 line
2.47.0
#485 lore raw

Re: [PATCH v32 00/12] Log library enhancements

In reply to David Marchand
Quoted 37 lines · David Marchand

Improvements and unification of logging library.
This version works on all platforms: Linux, Windows and FreeBSD.

This is update to rework patch set. It adds several new features to the console log output.

* Putting a timestamp on console output which is useful for analyzing performance of startup codes. Timestamp is optional and must be enabled on command line.

* Displaying console output with colors.
It uses the standard conventions used by many other Linux commands for colorized display. The default is to enable color if the console output is going to a terminal. But it can be always on or disabled by command line flag. This default was chosen based on what dmesg(1) command does.

Color is used by many tools (vi, iproute2, git) because it is helpful; DPDK drivers and libraries print lots of not very useful messages. And having error messages highlighted in bold face helps. This might also get users to pay more attention to error messages. Many bug reports have earlier messages that are lost because there are so many info messages.

* Add support for automatic detection of systemd journal protocol. If running as systemd service will get enhanced logging.

* Use of syslog is optional and the meaning of the --syslog flag has changed. The default is *not* to use unless requested.

Add Stephen as maintainer for log because by now have added more than previous authors.

Quoted 6 lines

Resending for CI:

Changes since v31:
- rebased,
- fixed build with MSVC: escape character was restored to \033 (used until v25) instead of \e,

Applied, thanks.

Signature · 1 line
David Marchand