* [dpdk-dev] [PATCH] eal: add option to put timestamp on console output @ 2020-08-14 17:34 Stephen Hemminger 2020-08-14 18:39 ` Dmitry Kozlyuk ` (29 more replies) 0 siblings, 30 replies; 445+ messages in thread From: Stephen Hemminger @ 2020-08-14 17:34 UTC (permalink / raw) To: dev; +Cc: 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. The timestamp format is chosen to look like the default Linux dmesg timestamp. Example: [ 0.000040] EAL: Probing VFIO support... Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ lib/librte_eal/common/eal_common_options.c | 5 +++ lib/librte_eal/common/eal_internal_cfg.h | 1 + lib/librte_eal/common/eal_options.h | 2 + lib/librte_eal/linux/eal_log.c | 41 +++++++++++++++++-- 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index bd3977cb3d91..9336046c63a9 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -118,3 +118,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c index a5426e12346a..240610770ee1 100644 --- a/lib/librte_eal/common/eal_common_options.c +++ b/lib/librte_eal/common/eal_common_options.c @@ -76,6 +76,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, 0, 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 }, @@ -1626,6 +1627,9 @@ eal_parse_common_option(int opt, const char *optarg, } break; } + case OPT_LOG_TIMESTAMP_NUM: + conf->log_timestamp = 1; + break; #ifndef RTE_EXEC_ENV_WINDOWS case OPT_TRACE_NUM: { @@ -1945,6 +1949,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<int> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<int>\n" diff --git a/lib/librte_eal/common/eal_internal_cfg.h b/lib/librte_eal/common/eal_internal_cfg.h index 13f93388a781..75c476870c57 100644 --- a/lib/librte_eal/common/eal_internal_cfg.h +++ b/lib/librte_eal/common/eal_internal_cfg.h @@ -70,6 +70,7 @@ struct internal_config { * per-node) non-legacy mode only. */ volatile int syslog_facility; /**< facility passed to openlog() */ + volatile uint8_t log_timestamp; /**< add timestamp to console output */ /** 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 */ diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h index 89769d48b487..7c86f2e19109 100644 --- a/lib/librte_eal/common/eal_options.h +++ b/lib/librte_eal/common/eal_options.h @@ -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" diff --git a/lib/librte_eal/linux/eal_log.c b/lib/librte_eal/linux/eal_log.c index 43c8460bfb07..cbd0924ec847 100644 --- a/lib/librte_eal/linux/eal_log.c +++ b/lib/librte_eal/linux/eal_log.c @@ -5,9 +5,12 @@ #include <string.h> #include <stdio.h> #include <stdint.h> +#include <unistd.h> +#include <time.h> #include <sys/types.h> #include <syslog.h> #include <sys/queue.h> +#include <sys/uio.h> #include <rte_memory.h> #include <rte_eal.h> @@ -18,6 +21,9 @@ #include <rte_log.h> #include "eal_private.h" +#include "eal_internal_cfg.h" + +static struct timespec log_start_time; /* * default log function @@ -25,11 +31,38 @@ static ssize_t console_log_write(__rte_unused void *c, const char *buf, size_t size) { + const struct internal_config *internal_conf + = eal_get_internal_configuration(); ssize_t ret; + char tbuf[64]; + struct iovec iov[2]; + + if (internal_conf->log_timestamp) { + struct timespec ts; + + /* format up monotonic timestamp */ + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec -= log_start_time.tv_sec; + ts.tv_nsec -= log_start_time.tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000ul; + } - /* write on stdout */ - ret = fwrite(buf, 1, size, stdout); - fflush(stdout); + iov[0].iov_base = tbuf; + iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "[%8lu.%06lu] ", + ts.tv_sec, ts.tv_nsec / 1000u); + + /* extra cast is workaround to remove const quallifier */ + iov[1].iov_base = (void *)(uintptr_t)buf; + iov[1].iov_len = size; + + fflush(stdout); + ret = writev(STDOUT_FILENO, iov, 2); + } else { + /* write on stdout */ + ret = fwrite(buf, 1, size, stdout); + } /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); @@ -50,6 +83,8 @@ rte_eal_log_init(const char *id, int facility) { FILE *log_stream; + clock_gettime(CLOCK_MONOTONIC, &log_start_time); + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.27.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [dpdk-dev] [PATCH] eal: add option to put timestamp on console output 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger @ 2020-08-14 18:39 ` Dmitry Kozlyuk 2020-08-14 18:45 ` Stephen Hemminger 2023-03-06 18:18 ` [PATCH v2 0/2] Add option to timestamp console log Stephen Hemminger ` (28 subsequent siblings) 29 siblings, 1 reply; 445+ messages in thread From: Dmitry Kozlyuk @ 2020-08-14 18:39 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Fri, 14 Aug 2020 10:34:41 -0700, Stephen Hemminger wrote: > 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. The timestamp format is chosen to look > like the default Linux dmesg timestamp. > > Example: > [ 0.000040] EAL: Probing VFIO support... > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- > doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ > lib/librte_eal/common/eal_common_options.c | 5 +++ > lib/librte_eal/common/eal_internal_cfg.h | 1 + > lib/librte_eal/common/eal_options.h | 2 + > lib/librte_eal/linux/eal_log.c | 41 +++++++++++++++++-- > 5 files changed, 51 insertions(+), 3 deletions(-) [snip] > @@ -1945,6 +1949,7 @@ eal_common_usage(void) > " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" > #ifndef RTE_EXEC_ENV_WINDOWS > " --"OPT_SYSLOG" Set syslog facility\n" > + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" > #endif Seems like FreeBSD doesn't support this option as well. It is clear that iovec approach saves a syscall on each write, but is it worth implementing log timestamps on each platform instead of prepending it in common code (with a second fwrite call)? For fast event stream with precise timestamps, there is tracing framework. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [dpdk-dev] [PATCH] eal: add option to put timestamp on console output 2020-08-14 18:39 ` Dmitry Kozlyuk @ 2020-08-14 18:45 ` Stephen Hemminger 2020-08-14 19:09 ` Dmitry Kozlyuk 0 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2020-08-14 18:45 UTC (permalink / raw) To: Dmitry Kozlyuk; +Cc: dev On Fri, 14 Aug 2020 21:39:29 +0300 Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > On Fri, 14 Aug 2020 10:34:41 -0700, Stephen Hemminger wrote: > > 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. The timestamp format is chosen to look > > like the default Linux dmesg timestamp. > > > > Example: > > [ 0.000040] EAL: Probing VFIO support... > > > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > > --- > > doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ > > lib/librte_eal/common/eal_common_options.c | 5 +++ > > lib/librte_eal/common/eal_internal_cfg.h | 1 + > > lib/librte_eal/common/eal_options.h | 2 + > > lib/librte_eal/linux/eal_log.c | 41 +++++++++++++++++-- > > 5 files changed, 51 insertions(+), 3 deletions(-) > [snip] > > > @@ -1945,6 +1949,7 @@ eal_common_usage(void) > > " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" > > #ifndef RTE_EXEC_ENV_WINDOWS > > " --"OPT_SYSLOG" Set syslog facility\n" > > + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" > > #endif > > Seems like FreeBSD doesn't support this option as well. > > It is clear that iovec approach saves a syscall on each write, but is it worth > implementing log timestamps on each platform instead of prepending it in > common code (with a second fwrite call)? For fast event stream with precise > timestamps, there is tracing framework. FreeBsd doesn't go through the same log code. Iovec is to keep timestamp and message as an atomic message. There is no good way to use fwrite to get anything atomic. Fwrite is unnecessary here anyway saving a copy and avoid issues with library getting corrupted is good. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [dpdk-dev] [PATCH] eal: add option to put timestamp on console output 2020-08-14 18:45 ` Stephen Hemminger @ 2020-08-14 19:09 ` Dmitry Kozlyuk 2020-08-14 19:20 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Dmitry Kozlyuk @ 2020-08-14 19:09 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Fri, 14 Aug 2020 11:45:49 -0700, Stephen Hemminger wrote: > On Fri, 14 Aug 2020 21:39:29 +0300 > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: [...] > FreeBsd doesn't go through the same log code. Then --log-timestamp shouldn't appear on FreeBSD if it's unsupported. > Iovec is to keep timestamp and message as an atomic message. > There is no good way to use fwrite to get anything atomic. > Fwrite is unnecessary here anyway saving a copy and avoid issues with library > getting corrupted is good. Got it, thanks. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [dpdk-dev] [PATCH] eal: add option to put timestamp on console output 2020-08-14 19:09 ` Dmitry Kozlyuk @ 2020-08-14 19:20 ` Stephen Hemminger 2020-08-17 10:37 ` Bruce Richardson 0 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2020-08-14 19:20 UTC (permalink / raw) To: Dmitry Kozlyuk; +Cc: dev On Fri, 14 Aug 2020 22:09:11 +0300 Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > On Fri, 14 Aug 2020 11:45:49 -0700, Stephen Hemminger wrote: > > On Fri, 14 Aug 2020 21:39:29 +0300 > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > [...] > > FreeBsd doesn't go through the same log code. > > Then --log-timestamp shouldn't appear on FreeBSD if it's unsupported. Was using same ifdef that is already there. There are several options already (like syslog facility) which do nothing on FreeBSD anyway. > > > Iovec is to keep timestamp and message as an atomic message. > > There is no good way to use fwrite to get anything atomic. > > Fwrite is unnecessary here anyway saving a copy and avoid issues with library > > getting corrupted is good. > > Got it, thanks. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [dpdk-dev] [PATCH] eal: add option to put timestamp on console output 2020-08-14 19:20 ` Stephen Hemminger @ 2020-08-17 10:37 ` Bruce Richardson 2020-08-17 15:11 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Bruce Richardson @ 2020-08-17 10:37 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Dmitry Kozlyuk, dev On Fri, Aug 14, 2020 at 12:20:28PM -0700, Stephen Hemminger wrote: > On Fri, 14 Aug 2020 22:09:11 +0300 > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > > On Fri, 14 Aug 2020 11:45:49 -0700, Stephen Hemminger wrote: > > > On Fri, 14 Aug 2020 21:39:29 +0300 > > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > [...] > > > FreeBsd doesn't go through the same log code. > > > > Then --log-timestamp shouldn't appear on FreeBSD if it's unsupported. > > Was using same ifdef that is already there. There are several options already > (like syslog facility) which do nothing on FreeBSD anyway. > While that is correct, I think that we really should support this on FreeBSD also, since I don't think there is any technical reason we can't do so, right? Even a sub-optimal solution where the timestamp write and log write are non-atomic would be better than nothing. /Bruce ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [dpdk-dev] [PATCH] eal: add option to put timestamp on console output 2020-08-17 10:37 ` Bruce Richardson @ 2020-08-17 15:11 ` Stephen Hemminger 2020-10-19 14:11 ` Thomas Monjalon 0 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2020-08-17 15:11 UTC (permalink / raw) To: Bruce Richardson; +Cc: Dmitry Kozlyuk, dev On Mon, 17 Aug 2020 11:37:40 +0100 Bruce Richardson <bruce.richardson@intel.com> wrote: > On Fri, Aug 14, 2020 at 12:20:28PM -0700, Stephen Hemminger wrote: > > On Fri, 14 Aug 2020 22:09:11 +0300 > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > > > > On Fri, 14 Aug 2020 11:45:49 -0700, Stephen Hemminger wrote: > > > > On Fri, 14 Aug 2020 21:39:29 +0300 > > > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > > [...] > > > > FreeBsd doesn't go through the same log code. > > > > > > Then --log-timestamp shouldn't appear on FreeBSD if it's unsupported. > > > > Was using same ifdef that is already there. There are several options already > > (like syslog facility) which do nothing on FreeBSD anyway. > > > While that is correct, I think that we really should support this on > FreeBSD also, since I don't think there is any technical reason we can't do > so, right? Even a sub-optimal solution where the timestamp write and log > write are non-atomic would be better than nothing. > > /Bruce FreeBSD now just uses default log stream (stdout). Linux has log stream to syslog and stdout. There is nothing Linux specific in the old or new code. The Linux code could just be moved to common, and both could use it. That is a separate patch, and someone with expertise and build setup for FreeBSD needs to do it. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [dpdk-dev] [PATCH] eal: add option to put timestamp on console output 2020-08-17 15:11 ` Stephen Hemminger @ 2020-10-19 14:11 ` Thomas Monjalon 2020-10-19 15:25 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Thomas Monjalon @ 2020-10-19 14:11 UTC (permalink / raw) To: Bruce Richardson, Dmitry Kozlyuk, Stephen Hemminger Cc: dev, david.marchand, olivier.matz There was no ack or conclusion for this patch. 17/08/2020 17:11, Stephen Hemminger: > On Mon, 17 Aug 2020 11:37:40 +0100 > Bruce Richardson <bruce.richardson@intel.com> wrote: > > > On Fri, Aug 14, 2020 at 12:20:28PM -0700, Stephen Hemminger wrote: > > > On Fri, 14 Aug 2020 22:09:11 +0300 > > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > > > > > > On Fri, 14 Aug 2020 11:45:49 -0700, Stephen Hemminger wrote: > > > > > On Fri, 14 Aug 2020 21:39:29 +0300 > > > > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > > > [...] > > > > > FreeBsd doesn't go through the same log code. > > > > > > > > Then --log-timestamp shouldn't appear on FreeBSD if it's unsupported. > > > > > > Was using same ifdef that is already there. There are several options already > > > (like syslog facility) which do nothing on FreeBSD anyway. > > > > > While that is correct, I think that we really should support this on > > FreeBSD also, since I don't think there is any technical reason we can't do > > so, right? Even a sub-optimal solution where the timestamp write and log > > write are non-atomic would be better than nothing. > > > > /Bruce > > FreeBSD now just uses default log stream (stdout). > Linux has log stream to syslog and stdout. > > There is nothing Linux specific in the old or new code. > The Linux code could just be moved to common, and both could use it. > That is a separate patch, and someone with expertise and build setup for FreeBSD needs to do it. > ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [dpdk-dev] [PATCH] eal: add option to put timestamp on console output 2020-10-19 14:11 ` Thomas Monjalon @ 2020-10-19 15:25 ` Stephen Hemminger 2024-03-21 17:22 ` Thomas Monjalon 0 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2020-10-19 15:25 UTC (permalink / raw) To: Thomas Monjalon Cc: Bruce Richardson, Dmitry Kozlyuk, dev, david.marchand, olivier.matz On Mon, 19 Oct 2020 16:11:19 +0200 Thomas Monjalon <thomas@monjalon.net> wrote: > There was no ack or conclusion for this patch. > > 17/08/2020 17:11, Stephen Hemminger: > > On Mon, 17 Aug 2020 11:37:40 +0100 > > Bruce Richardson <bruce.richardson@intel.com> wrote: > > > > > On Fri, Aug 14, 2020 at 12:20:28PM -0700, Stephen Hemminger wrote: > > > > On Fri, 14 Aug 2020 22:09:11 +0300 > > > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > > > > > > > > On Fri, 14 Aug 2020 11:45:49 -0700, Stephen Hemminger wrote: > > > > > > On Fri, 14 Aug 2020 21:39:29 +0300 > > > > > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > > > > [...] > > > > > > FreeBsd doesn't go through the same log code. > > > > > > > > > > Then --log-timestamp shouldn't appear on FreeBSD if it's unsupported. > > > > > > > > Was using same ifdef that is already there. There are several options already > > > > (like syslog facility) which do nothing on FreeBSD anyway. > > > > > > > While that is correct, I think that we really should support this on > > > FreeBSD also, since I don't think there is any technical reason we can't do > > > so, right? Even a sub-optimal solution where the timestamp write and log > > > write are non-atomic would be better than nothing. > > > > > > /Bruce > > > > FreeBSD now just uses default log stream (stdout). > > Linux has log stream to syslog and stdout. > > > > There is nothing Linux specific in the old or new code. > > The Linux code could just be moved to common, and both could use it. > > That is a separate patch, and someone with expertise and build setup for FreeBSD needs to do it. > > Lets fix FreeBSD to use common code for logging, then timestamp option can be added? ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [dpdk-dev] [PATCH] eal: add option to put timestamp on console output 2020-10-19 15:25 ` Stephen Hemminger @ 2024-03-21 17:22 ` Thomas Monjalon 0 siblings, 0 replies; 445+ messages in thread From: Thomas Monjalon @ 2024-03-21 17:22 UTC (permalink / raw) To: Stephen Hemminger Cc: Bruce Richardson, Dmitry Kozlyuk, dev, david.marchand, olivier.matz 19/10/2020 17:25, Stephen Hemminger: > On Mon, 19 Oct 2020 16:11:19 +0200 > Thomas Monjalon <thomas@monjalon.net> wrote: > > > There was no ack or conclusion for this patch. > > > > 17/08/2020 17:11, Stephen Hemminger: > > > On Mon, 17 Aug 2020 11:37:40 +0100 > > > Bruce Richardson <bruce.richardson@intel.com> wrote: > > > > > > > On Fri, Aug 14, 2020 at 12:20:28PM -0700, Stephen Hemminger wrote: > > > > > On Fri, 14 Aug 2020 22:09:11 +0300 > > > > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > > > > > > > > > > On Fri, 14 Aug 2020 11:45:49 -0700, Stephen Hemminger wrote: > > > > > > > On Fri, 14 Aug 2020 21:39:29 +0300 > > > > > > > Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> wrote: > > > > > > [...] > > > > > > > FreeBsd doesn't go through the same log code. > > > > > > > > > > > > Then --log-timestamp shouldn't appear on FreeBSD if it's unsupported. > > > > > > > > > > Was using same ifdef that is already there. There are several options already > > > > > (like syslog facility) which do nothing on FreeBSD anyway. > > > > > > > > > While that is correct, I think that we really should support this on > > > > FreeBSD also, since I don't think there is any technical reason we can't do > > > > so, right? Even a sub-optimal solution where the timestamp write and log > > > > write are non-atomic would be better than nothing. > > > > > > > > /Bruce > > > > > > FreeBSD now just uses default log stream (stdout). > > > Linux has log stream to syslog and stdout. > > > > > > There is nothing Linux specific in the old or new code. > > > The Linux code could just be moved to common, and both could use it. > > > That is a separate patch, and someone with expertise and build setup for FreeBSD needs to do it. > > > > > Lets fix FreeBSD to use common code for logging, then timestamp option can be added? OK ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v2 0/2] Add option to timestamp console log 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger 2020-08-14 18:39 ` Dmitry Kozlyuk @ 2023-03-06 18:18 ` Stephen Hemminger 2023-03-06 18:18 ` [PATCH v2 1/2] eal: unify logging code for FreeBsd and Linux Stephen Hemminger ` (2 more replies) 2023-03-06 19:28 ` [PATCH v3 " Stephen Hemminger ` (27 subsequent siblings) 29 siblings, 3 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-03-06 18:18 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is a reprise of earlier patch to add timestamp to console messages. Example: # dpdk-testpmd -l 1-4 -n 4 --vdev net_null0 --log-timestamp -- -i EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 EAL: Detected static linkage of DPDK EAL: Multi-process socket /var/run/dpdk/rte/mp_socket EAL: Selected IOVA mode 'VA' Interactive-mode selected [ 0.191407] testpmd: create a new mbuf pool <mb_pool_0>: n=171456, size=2176, socket=0 [ 0.191510] testpmd: preferred mempool ops selected: ring_mp_mc v2 - rebase to current DPDK - make linux log code common to freebsd Stephen Hemminger (2): eal: unify logging code for FreeBsd and Linux eal: add option to put timestamp on console output .../freebsd_gsg/freebsd_eal_parameters.rst | 32 ++++++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 + lib/eal/common/eal_common_options.c | 5 + lib/eal/common/eal_internal_cfg.h | 1 + lib/eal/common/eal_options.h | 2 + lib/eal/freebsd/eal.c | 6 ++ lib/eal/linux/eal_log.c | 61 ------------ lib/eal/linux/meson.build | 1 - lib/eal/unix/eal_log.c | 97 +++++++++++++++++++ lib/eal/unix/meson.build | 1 + 10 files changed, 149 insertions(+), 62 deletions(-) delete mode 100644 lib/eal/linux/eal_log.c create mode 100644 lib/eal/unix/eal_log.c -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v2 1/2] eal: unify logging code for FreeBsd and Linux 2023-03-06 18:18 ` [PATCH v2 0/2] Add option to timestamp console log Stephen Hemminger @ 2023-03-06 18:18 ` Stephen Hemminger 2023-03-06 18:18 ` [PATCH v2 2/2] eal: add option to put timestamp on console output Stephen Hemminger 2023-03-07 9:09 ` [PATCH v2 0/2] Add option to timestamp console log Bruce Richardson 2 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-03-06 18:18 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger FreeBSD logging code was not using syslog and did not have the same options as Linux. Move the log writing code to common tree. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 6 ++++++ lib/eal/linux/meson.build | 1 - lib/eal/{linux => unix}/eal_log.c | 0 lib/eal/unix/meson.build | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) rename lib/eal/{linux => unix}/eal_log.c (100%) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7db4239c5187..15326ccc321d 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -744,6 +744,12 @@ rte_eal_init(int argc, char **argv) #endif } + if (eal_log_init(logid, internal_conf->syslog_facility) < 0) { + rte_eal_init_alert("Cannot init logging."); + rte_errno = ENOMEM; + return -1; + } + /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/meson.build b/lib/eal/linux/meson.build index 3cccfa36c0a4..1b913acc0681 100644 --- a/lib/eal/linux/meson.build +++ b/lib/eal/linux/meson.build @@ -11,7 +11,6 @@ sources += files( 'eal_hugepage_info.c', 'eal_interrupts.c', 'eal_lcore.c', - 'eal_log.c', 'eal_memalloc.c', 'eal_memory.c', 'eal_thread.c', diff --git a/lib/eal/linux/eal_log.c b/lib/eal/unix/eal_log.c similarity index 100% rename from lib/eal/linux/eal_log.c rename to lib/eal/unix/eal_log.c diff --git a/lib/eal/unix/meson.build b/lib/eal/unix/meson.build index cc7d67dd321d..37d07594df29 100644 --- a/lib/eal/unix/meson.build +++ b/lib/eal/unix/meson.build @@ -6,6 +6,7 @@ sources += files( 'eal_file.c', 'eal_filesystem.c', 'eal_firmware.c', + 'eal_log.c', 'eal_unix_memory.c', 'eal_unix_thread.c', 'eal_unix_timer.c', -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v2 2/2] eal: add option to put timestamp on console output 2023-03-06 18:18 ` [PATCH v2 0/2] Add option to timestamp console log Stephen Hemminger 2023-03-06 18:18 ` [PATCH v2 1/2] eal: unify logging code for FreeBsd and Linux Stephen Hemminger @ 2023-03-06 18:18 ` Stephen Hemminger 2023-03-07 9:09 ` [PATCH v2 0/2] Add option to timestamp console log Bruce Richardson 2 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-03-06 18:18 UTC (permalink / raw) To: dev; +Cc: 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. The timestamp format was chosen to be the same as the default Linux dmesg timestamp. The messages are written using writev() which avoids unnecessary buffering and ensures that if multiple threads are logging at the same time that timestamp and message buffer don't get interleaved. Example: [ 0.000040] EAL: Probing VFIO support... Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- .../freebsd_gsg/freebsd_eal_parameters.rst | 32 ++++++++++++++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ lib/eal/common/eal_common_options.c | 5 +++ lib/eal/common/eal_internal_cfg.h | 1 + lib/eal/common/eal_options.h | 2 + lib/eal/unix/eal_log.c | 42 +++++++++++++++++-- 6 files changed, 84 insertions(+), 3 deletions(-) diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index fba467a2ce92..99cff10e963c 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -18,3 +18,35 @@ 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 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f38139119..719ca6851625 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -135,3 +135,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 03059336987d..2d3d8e82f7f3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -76,6 +76,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, 0, 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 }, @@ -1833,6 +1834,9 @@ eal_parse_common_option(int opt, const char *optarg, } break; } + case OPT_LOG_TIMESTAMP_NUM: + conf->log_timestamp = 1; + break; #ifndef RTE_EXEC_ENV_WINDOWS case OPT_TRACE_NUM: { @@ -2194,6 +2198,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa79..33144c3619dd 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -85,6 +85,7 @@ struct internal_config { * per-node) non-legacy mode only. */ volatile int syslog_facility; /**< facility passed to openlog() */ + volatile uint8_t log_timestamp; /**< add timestamp to console output */ /** 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 */ diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb641284..cc9723868e3c 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index d44416fd6570..d8a900efedea 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -4,11 +4,17 @@ #include <stdio.h> #include <sys/types.h> +#include <sys/uio.h> #include <syslog.h> +#include <time.h> +#include <unistd.h> #include <rte_log.h> #include "eal_log.h" +#include "eal_private.h" + +static struct timespec log_start_time; /* * default log function @@ -16,11 +22,39 @@ static ssize_t console_log_write(__rte_unused void *c, const char *buf, size_t size) { + const struct internal_config *internal_conf = + eal_get_internal_configuration(); ssize_t ret; - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); + /* add optional timestamp for stderr */ + if (internal_conf->log_timestamp) { + struct iovec iov[2]; + struct timespec ts; + char tbuf[64]; + + /* format up monotonic timestamp */ + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec -= log_start_time.tv_sec; + ts.tv_nsec -= log_start_time.tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000ul; + } + + /* use writev to put timestamp and buf in same operation */ + iov[0].iov_base = tbuf; + iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "[%8lu.%06lu] ", + ts.tv_sec, ts.tv_nsec / 1000u); + + /* casts are to unconstify the buf */ + iov[1].iov_base = (void *)(uintptr_t)buf; + iov[1].iov_len = size; + ret = writev(STDERR_FILENO, iov, 2); + } else { + /* write on stderr */ + ret = fwrite(buf, 1, size, stderr); + fflush(stderr); + } /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); @@ -49,6 +83,8 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; + clock_gettime(CLOCK_MONOTONIC, &log_start_time); + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v2 0/2] Add option to timestamp console log 2023-03-06 18:18 ` [PATCH v2 0/2] Add option to timestamp console log Stephen Hemminger 2023-03-06 18:18 ` [PATCH v2 1/2] eal: unify logging code for FreeBsd and Linux Stephen Hemminger 2023-03-06 18:18 ` [PATCH v2 2/2] eal: add option to put timestamp on console output Stephen Hemminger @ 2023-03-07 9:09 ` Bruce Richardson 2 siblings, 0 replies; 445+ messages in thread From: Bruce Richardson @ 2023-03-07 9:09 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Mon, Mar 06, 2023 at 10:18:14AM -0800, Stephen Hemminger wrote: > This is a reprise of earlier patch to add timestamp to console > messages. > > Example: > # dpdk-testpmd -l 1-4 -n 4 --vdev net_null0 --log-timestamp -- -i > EAL: Detected CPU lcores: 16 > EAL: Detected NUMA nodes: 1 > EAL: Detected static linkage of DPDK > EAL: Multi-process socket /var/run/dpdk/rte/mp_socket > EAL: Selected IOVA mode 'VA' > Interactive-mode selected > [ 0.191407] testpmd: create a new mbuf pool <mb_pool_0>: n=171456, size=2176, socket=0 > [ 0.191510] testpmd: preferred mempool ops selected: ring_mp_mc > > > v2 > - rebase to current DPDK > - make linux log code common to freebsd > > Stephen Hemminger (2): > eal: unify logging code for FreeBsd and Linux > eal: add option to put timestamp on console output > Series-acked-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v3 0/2] Add option to timestamp console log 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger 2020-08-14 18:39 ` Dmitry Kozlyuk 2023-03-06 18:18 ` [PATCH v2 0/2] Add option to timestamp console log Stephen Hemminger @ 2023-03-06 19:28 ` Stephen Hemminger 2023-03-06 19:28 ` [PATCH v3 1/2] eal: unify logging code for FreeBsd and Linux Stephen Hemminger ` (2 more replies) 2023-06-26 18:42 ` [PATCH v4 0/5] Logging related patchs Stephen Hemminger ` (26 subsequent siblings) 29 siblings, 3 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-03-06 19:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is a reprise of earlier patch to add timestamp to console messages. Example: # dpdk-testpmd -l 1-4 -n 4 --vdev net_null0 --log-timestamp -- -i EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 EAL: Detected static linkage of DPDK EAL: Multi-process socket /var/run/dpdk/rte/mp_socket EAL: Selected IOVA mode 'VA' Interactive-mode selected [ 0.191407] testpmd: create a new mbuf pool <mb_pool_0>: n=171456, size=2176, socket=0 [ 0.191510] testpmd: preferred mempool ops selected: ring_mp_mc v3 - fix log init on FreeBSD v2 - rebase to current DPDK - make linux log code common to freebsd Stephen Hemminger (2): eal: unify logging code for FreeBsd and Linux eal: add option to put timestamp on console output .../freebsd_gsg/freebsd_eal_parameters.rst | 32 ++++++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 + lib/eal/common/eal_common_options.c | 5 + lib/eal/common/eal_internal_cfg.h | 1 + lib/eal/common/eal_options.h | 2 + lib/eal/freebsd/eal.c | 7 ++ lib/eal/linux/eal_log.c | 61 ------------ lib/eal/linux/meson.build | 1 - lib/eal/unix/eal_log.c | 97 +++++++++++++++++++ lib/eal/unix/meson.build | 1 + 10 files changed, 150 insertions(+), 62 deletions(-) delete mode 100644 lib/eal/linux/eal_log.c create mode 100644 lib/eal/unix/eal_log.c -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v3 1/2] eal: unify logging code for FreeBsd and Linux 2023-03-06 19:28 ` [PATCH v3 " Stephen Hemminger @ 2023-03-06 19:28 ` Stephen Hemminger 2023-03-06 19:28 ` [PATCH v3 2/2] eal: add option to put timestamp on console output Stephen Hemminger 2023-03-07 7:33 ` [PATCH v3 0/2] Add option to timestamp console log Morten Brørup 2 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-03-06 19:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson FreeBSD logging code was not using syslog and did not have the same options as Linux. Move the log writing code to common tree. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 7 +++++++ lib/eal/linux/meson.build | 1 - lib/eal/{linux => unix}/eal_log.c | 0 lib/eal/unix/meson.build | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) rename lib/eal/{linux => unix}/eal_log.c (100%) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7db4239c5187..3a53f9e13887 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -51,6 +51,7 @@ #include "eal_hugepages.h" #include "eal_options.h" #include "eal_memcfg.h" +#include "eal_log.h" #include "eal_trace.h" #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL) @@ -744,6 +745,12 @@ rte_eal_init(int argc, char **argv) #endif } + if (eal_log_init(getprogname(), internal_conf->syslog_facility) < 0) { + rte_eal_init_alert("Cannot init logging."); + rte_errno = ENOMEM; + return -1; + } + /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/meson.build b/lib/eal/linux/meson.build index 3cccfa36c0a4..1b913acc0681 100644 --- a/lib/eal/linux/meson.build +++ b/lib/eal/linux/meson.build @@ -11,7 +11,6 @@ sources += files( 'eal_hugepage_info.c', 'eal_interrupts.c', 'eal_lcore.c', - 'eal_log.c', 'eal_memalloc.c', 'eal_memory.c', 'eal_thread.c', diff --git a/lib/eal/linux/eal_log.c b/lib/eal/unix/eal_log.c similarity index 100% rename from lib/eal/linux/eal_log.c rename to lib/eal/unix/eal_log.c diff --git a/lib/eal/unix/meson.build b/lib/eal/unix/meson.build index cc7d67dd321d..37d07594df29 100644 --- a/lib/eal/unix/meson.build +++ b/lib/eal/unix/meson.build @@ -6,6 +6,7 @@ sources += files( 'eal_file.c', 'eal_filesystem.c', 'eal_firmware.c', + 'eal_log.c', 'eal_unix_memory.c', 'eal_unix_thread.c', 'eal_unix_timer.c', -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v3 2/2] eal: add option to put timestamp on console output 2023-03-06 19:28 ` [PATCH v3 " Stephen Hemminger 2023-03-06 19:28 ` [PATCH v3 1/2] eal: unify logging code for FreeBsd and Linux Stephen Hemminger @ 2023-03-06 19:28 ` Stephen Hemminger 2023-03-07 9:35 ` fengchengwen 2023-03-07 7:33 ` [PATCH v3 0/2] Add option to timestamp console log Morten Brørup 2 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2023-03-06 19:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson 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. The timestamp format is chosen to look like the default Linux dmesg timestamp. Example: [ 0.000040] EAL: Probing VFIO support... Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- .../freebsd_gsg/freebsd_eal_parameters.rst | 32 ++++++++++++++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ lib/eal/common/eal_common_options.c | 5 +++ lib/eal/common/eal_internal_cfg.h | 1 + lib/eal/common/eal_options.h | 2 + lib/eal/unix/eal_log.c | 42 +++++++++++++++++-- 6 files changed, 84 insertions(+), 3 deletions(-) diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index fba467a2ce92..99cff10e963c 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -18,3 +18,35 @@ 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 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f38139119..719ca6851625 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -135,3 +135,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 03059336987d..2d3d8e82f7f3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -76,6 +76,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, 0, 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 }, @@ -1833,6 +1834,9 @@ eal_parse_common_option(int opt, const char *optarg, } break; } + case OPT_LOG_TIMESTAMP_NUM: + conf->log_timestamp = 1; + break; #ifndef RTE_EXEC_ENV_WINDOWS case OPT_TRACE_NUM: { @@ -2194,6 +2198,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa79..33144c3619dd 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -85,6 +85,7 @@ struct internal_config { * per-node) non-legacy mode only. */ volatile int syslog_facility; /**< facility passed to openlog() */ + volatile uint8_t log_timestamp; /**< add timestamp to console output */ /** 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 */ diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb641284..cc9723868e3c 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index d44416fd6570..d8a900efedea 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -4,11 +4,17 @@ #include <stdio.h> #include <sys/types.h> +#include <sys/uio.h> #include <syslog.h> +#include <time.h> +#include <unistd.h> #include <rte_log.h> #include "eal_log.h" +#include "eal_private.h" + +static struct timespec log_start_time; /* * default log function @@ -16,11 +22,39 @@ static ssize_t console_log_write(__rte_unused void *c, const char *buf, size_t size) { + const struct internal_config *internal_conf = + eal_get_internal_configuration(); ssize_t ret; - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); + /* add optional timestamp for stderr */ + if (internal_conf->log_timestamp) { + struct iovec iov[2]; + struct timespec ts; + char tbuf[64]; + + /* format up monotonic timestamp */ + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec -= log_start_time.tv_sec; + ts.tv_nsec -= log_start_time.tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000ul; + } + + /* use writev to put timestamp and buf in same operation */ + iov[0].iov_base = tbuf; + iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "[%8lu.%06lu] ", + ts.tv_sec, ts.tv_nsec / 1000u); + + /* casts are to unconstify the buf */ + iov[1].iov_base = (void *)(uintptr_t)buf; + iov[1].iov_len = size; + ret = writev(STDERR_FILENO, iov, 2); + } else { + /* write on stderr */ + ret = fwrite(buf, 1, size, stderr); + fflush(stderr); + } /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); @@ -49,6 +83,8 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; + clock_gettime(CLOCK_MONOTONIC, &log_start_time); + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v3 2/2] eal: add option to put timestamp on console output 2023-03-06 19:28 ` [PATCH v3 2/2] eal: add option to put timestamp on console output Stephen Hemminger @ 2023-03-07 9:35 ` fengchengwen 2023-03-07 16:05 ` Stephen Hemminger 2023-03-07 16:06 ` Stephen Hemminger 0 siblings, 2 replies; 445+ messages in thread From: fengchengwen @ 2023-03-07 9:35 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Bruce Richardson On 2023/3/7 3:28, Stephen Hemminger wrote: > 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. The timestamp format is chosen to look > like the default Linux dmesg timestamp. > > Example: > [ 0.000040] EAL: Probing VFIO support... > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- > .../freebsd_gsg/freebsd_eal_parameters.rst | 32 ++++++++++++++ > doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ > lib/eal/common/eal_common_options.c | 5 +++ > lib/eal/common/eal_internal_cfg.h | 1 + > lib/eal/common/eal_options.h | 2 + > lib/eal/unix/eal_log.c | 42 +++++++++++++++++-- > 6 files changed, 84 insertions(+), 3 deletions(-) > > diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst > index fba467a2ce92..99cff10e963c 100644 > --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst > +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst > @@ -18,3 +18,35 @@ 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 This should add to commit 1/2 [PATCH v3 1/2] eal: unify logging code for FreeBsd and Linux > + > +* ``--log-timestamp`` > + > + Add a timestamp of seconds and microseconds to each log message > + written to standard output. > diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst > index ea8f38139119..719ca6851625 100644 > --- a/doc/guides/linux_gsg/linux_eal_parameters.rst > +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst > @@ -135,3 +135,8 @@ Other options > local5 > local6 > local7 > + > +* ``--log-timestamp`` > + > + Add a timestamp of seconds and microseconds to each log message > + written to standard output. > diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c > index 03059336987d..2d3d8e82f7f3 100644 > --- a/lib/eal/common/eal_common_options.c > +++ b/lib/eal/common/eal_common_options.c > @@ -76,6 +76,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, 0, 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 }, > @@ -1833,6 +1834,9 @@ eal_parse_common_option(int opt, const char *optarg, > } > break; > } > + case OPT_LOG_TIMESTAMP_NUM: > + conf->log_timestamp = 1; > + break; > > #ifndef RTE_EXEC_ENV_WINDOWS > case OPT_TRACE_NUM: { > @@ -2194,6 +2198,7 @@ eal_common_usage(void) > " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" > #ifndef RTE_EXEC_ENV_WINDOWS > " --"OPT_SYSLOG" Set syslog facility\n" > + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" > #endif > " --"OPT_LOG_LEVEL"=<level> Set global log level\n" > " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" > diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h > index 167ec501fa79..33144c3619dd 100644 > --- a/lib/eal/common/eal_internal_cfg.h > +++ b/lib/eal/common/eal_internal_cfg.h > @@ -85,6 +85,7 @@ struct internal_config { > * per-node) non-legacy mode only. > */ > volatile int syslog_facility; /**< facility passed to openlog() */ > + volatile uint8_t log_timestamp; /**< add timestamp to console output */ > /** 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 */ > diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h > index 3cc9cb641284..cc9723868e3c 100644 > --- a/lib/eal/common/eal_options.h > +++ b/lib/eal/common/eal_options.h > @@ -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" > diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c > index d44416fd6570..d8a900efedea 100644 > --- a/lib/eal/unix/eal_log.c > +++ b/lib/eal/unix/eal_log.c > @@ -4,11 +4,17 @@ > > #include <stdio.h> > #include <sys/types.h> > +#include <sys/uio.h> > #include <syslog.h> > +#include <time.h> > +#include <unistd.h> > > #include <rte_log.h> > > #include "eal_log.h" > +#include "eal_private.h" > + > +static struct timespec log_start_time; This is process's private, how about support multi-process ? so that all process has the same base? > > /* > * default log function > @@ -16,11 +22,39 @@ > static ssize_t > console_log_write(__rte_unused void *c, const char *buf, size_t size) > { > + const struct internal_config *internal_conf = > + eal_get_internal_configuration(); > ssize_t ret; > > - /* write on stderr */ > - ret = fwrite(buf, 1, size, stderr); > - fflush(stderr); > + /* add optional timestamp for stderr */ > + if (internal_conf->log_timestamp) { > + struct iovec iov[2]; > + struct timespec ts; > + char tbuf[64]; > + > + /* format up monotonic timestamp */ > + clock_gettime(CLOCK_MONOTONIC, &ts); > + ts.tv_sec -= log_start_time.tv_sec; > + ts.tv_nsec -= log_start_time.tv_nsec; > + if (ts.tv_nsec < 0) { > + --ts.tv_sec; > + ts.tv_nsec += 1000000000ul; > + } > + > + /* use writev to put timestamp and buf in same operation */ > + iov[0].iov_base = tbuf; > + iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "[%8lu.%06lu] ", > + ts.tv_sec, ts.tv_nsec / 1000u); > + > + /* casts are to unconstify the buf */ > + iov[1].iov_base = (void *)(uintptr_t)buf; > + iov[1].iov_len = size; > + ret = writev(STDERR_FILENO, iov, 2); > + } else { > + /* write on stderr */ > + ret = fwrite(buf, 1, size, stderr); > + fflush(stderr); > + } > > /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ > syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); The syslog will add timestamp, but the syslog backend will re-write timestamp, so in the last, you can't find the real-timestamp of this log print. sometimes it requires to get real log time. PS: we found it in our test environment because RR schedule hang too long (similar question also found: https://bugzilla.redhat.com/show_bug.cgi?id=1855447). So suggest add timestamp in syslog string also, and don't convert to monotonic and just print as normal format (just like syslog). > @@ -49,6 +83,8 @@ eal_log_init(const char *id, int facility) > { > FILE *log_stream; > > + clock_gettime(CLOCK_MONOTONIC, &log_start_time); > + > log_stream = fopencookie(NULL, "w+", console_log_func); > if (log_stream == NULL) > return -1; > ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v3 2/2] eal: add option to put timestamp on console output 2023-03-07 9:35 ` fengchengwen @ 2023-03-07 16:05 ` Stephen Hemminger 2023-03-07 16:06 ` Stephen Hemminger 1 sibling, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-03-07 16:05 UTC (permalink / raw) To: fengchengwen; +Cc: dev, Bruce Richardson On Tue, 7 Mar 2023 17:35:32 +0800 fengchengwen <fengchengwen@huawei.com> wrote: > On 2023/3/7 3:28, Stephen Hemminger wrote: > > 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. The timestamp format is chosen to look > > like the default Linux dmesg timestamp. > > > > Example: > > [ 0.000040] EAL: Probing VFIO support... > > > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > > --- > > .../freebsd_gsg/freebsd_eal_parameters.rst | 32 ++++++++++++++ > > doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ > > lib/eal/common/eal_common_options.c | 5 +++ > > lib/eal/common/eal_internal_cfg.h | 1 + > > lib/eal/common/eal_options.h | 2 + > > lib/eal/unix/eal_log.c | 42 +++++++++++++++++-- > > 6 files changed, 84 insertions(+), 3 deletions(-) > > > > diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst > > index fba467a2ce92..99cff10e963c 100644 > > --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst > > +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst > > @@ -18,3 +18,35 @@ 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 > > This should add to commit 1/2 [PATCH v3 1/2] eal: unify logging code for FreeBsd and Linux > > > + > > +* ``--log-timestamp`` > > + > > + Add a timestamp of seconds and microseconds to each log message > > + written to standard output. > > diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst > > index ea8f38139119..719ca6851625 100644 > > --- a/doc/guides/linux_gsg/linux_eal_parameters.rst > > +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst > > @@ -135,3 +135,8 @@ Other options > > local5 > > local6 > > local7 > > + > > +* ``--log-timestamp`` > > + > > + Add a timestamp of seconds and microseconds to each log message > > + written to standard output. > > diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c > > index 03059336987d..2d3d8e82f7f3 100644 > > --- a/lib/eal/common/eal_common_options.c > > +++ b/lib/eal/common/eal_common_options.c > > @@ -76,6 +76,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, 0, 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 }, > > @@ -1833,6 +1834,9 @@ eal_parse_common_option(int opt, const char *optarg, > > } > > break; > > } > > + case OPT_LOG_TIMESTAMP_NUM: > > + conf->log_timestamp = 1; > > + break; > > > > #ifndef RTE_EXEC_ENV_WINDOWS > > case OPT_TRACE_NUM: { > > @@ -2194,6 +2198,7 @@ eal_common_usage(void) > > " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" > > #ifndef RTE_EXEC_ENV_WINDOWS > > " --"OPT_SYSLOG" Set syslog facility\n" > > + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" > > #endif > > " --"OPT_LOG_LEVEL"=<level> Set global log level\n" > > " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" > > diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h > > index 167ec501fa79..33144c3619dd 100644 > > --- a/lib/eal/common/eal_internal_cfg.h > > +++ b/lib/eal/common/eal_internal_cfg.h > > @@ -85,6 +85,7 @@ struct internal_config { > > * per-node) non-legacy mode only. > > */ > > volatile int syslog_facility; /**< facility passed to openlog() */ > > + volatile uint8_t log_timestamp; /**< add timestamp to console output */ > > /** 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 */ > > diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h > > index 3cc9cb641284..cc9723868e3c 100644 > > --- a/lib/eal/common/eal_options.h > > +++ b/lib/eal/common/eal_options.h > > @@ -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" > > diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c > > index d44416fd6570..d8a900efedea 100644 > > --- a/lib/eal/unix/eal_log.c > > +++ b/lib/eal/unix/eal_log.c > > @@ -4,11 +4,17 @@ > > > > #include <stdio.h> > > #include <sys/types.h> > > +#include <sys/uio.h> > > #include <syslog.h> > > +#include <time.h> > > +#include <unistd.h> > > > > #include <rte_log.h> > > > > #include "eal_log.h" > > +#include "eal_private.h" > > + > > +static struct timespec log_start_time; > > This is process's private, how about support multi-process ? so that all process has the same base? If using primary/secondary, then the secondary's output would have time zero of when secondary started. Not sure if that is good or bad? ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v3 2/2] eal: add option to put timestamp on console output 2023-03-07 9:35 ` fengchengwen 2023-03-07 16:05 ` Stephen Hemminger @ 2023-03-07 16:06 ` Stephen Hemminger 2023-03-08 0:36 ` fengchengwen 1 sibling, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2023-03-07 16:06 UTC (permalink / raw) To: fengchengwen; +Cc: dev, Bruce Richardson On Tue, 7 Mar 2023 17:35:32 +0800 fengchengwen <fengchengwen@huawei.com> wrote: > The syslog will add timestamp, but the syslog backend will re-write timestamp, so > in the last, you can't find the real-timestamp of this log print. sometimes it requires > to get real log time. > PS: we found it in our test environment because RR schedule hang too long (similar question > also found: https://bugzilla.redhat.com/show_bug.cgi?id=1855447). > > So suggest add timestamp in syslog string also, and don't convert to monotonic and just > print as normal format (just like syslog). Are you using systemd? Never, never configure a DPDK application with real-time process priority. Polling model and RT don't mix. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v3 2/2] eal: add option to put timestamp on console output 2023-03-07 16:06 ` Stephen Hemminger @ 2023-03-08 0:36 ` fengchengwen 2023-03-08 2:03 ` Stephen Hemminger 2023-03-08 2:51 ` Stephen Hemminger 0 siblings, 2 replies; 445+ messages in thread From: fengchengwen @ 2023-03-08 0:36 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Bruce Richardson On 2023/3/8 0:06, Stephen Hemminger wrote: > On Tue, 7 Mar 2023 17:35:32 +0800 > fengchengwen <fengchengwen@huawei.com> wrote: > >> The syslog will add timestamp, but the syslog backend will re-write timestamp, so >> in the last, you can't find the real-timestamp of this log print. sometimes it requires >> to get real log time. >> PS: we found it in our test environment because RR schedule hang too long (similar question >> also found: https://bugzilla.redhat.com/show_bug.cgi?id=1855447). >> >> So suggest add timestamp in syslog string also, and don't convert to monotonic and just >> print as normal format (just like syslog). > > > Are you using systemd? Yes > > Never, never configure a DPDK application with real-time process priority. > Polling model and RT don't mix. Maybe we should document them ? > . > ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v3 2/2] eal: add option to put timestamp on console output 2023-03-08 0:36 ` fengchengwen @ 2023-03-08 2:03 ` Stephen Hemminger 2023-03-09 0:55 ` fengchengwen 2023-03-08 2:51 ` Stephen Hemminger 1 sibling, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2023-03-08 2:03 UTC (permalink / raw) To: fengchengwen; +Cc: dev, Bruce Richardson On Wed, 8 Mar 2023 08:36:48 +0800 fengchengwen <fengchengwen@huawei.com> wrote: > On 2023/3/8 0:06, Stephen Hemminger wrote: > > On Tue, 7 Mar 2023 17:35:32 +0800 > > fengchengwen <fengchengwen@huawei.com> wrote: > > > >> The syslog will add timestamp, but the syslog backend will re-write timestamp, so > >> in the last, you can't find the real-timestamp of this log print. sometimes it requires > >> to get real log time. > >> PS: we found it in our test environment because RR schedule hang too long (similar question > >> also found: https://bugzilla.redhat.com/show_bug.cgi?id=1855447). > >> > >> So suggest add timestamp in syslog string also, and don't convert to monotonic and just > >> print as normal format (just like syslog). > > > > > > Are you using systemd? > > Yes There is redhat bug about this: https://bugzilla.redhat.com/show_bug.cgi?id=991678 > > Never, never configure a DPDK application with real-time process priority. > > Polling model and RT don't mix. > > Maybe we should document them ? Part of previous discussion here: https://mails.dpdk.org/archives/dev/2021-April/203778.html In my experience running DPDK on isolated threads (cgroup or scheduler isolation) combined with remapping interrupts gives best response without lockup. I.e don't depend on scheduler to do the right thing. Instead ensure that each thread runs on dedicated CPU. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v3 2/2] eal: add option to put timestamp on console output 2023-03-08 2:03 ` Stephen Hemminger @ 2023-03-09 0:55 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2023-03-09 0:55 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Bruce Richardson On 2023/3/8 10:03, Stephen Hemminger wrote: > On Wed, 8 Mar 2023 08:36:48 +0800 > fengchengwen <fengchengwen@huawei.com> wrote: > >> On 2023/3/8 0:06, Stephen Hemminger wrote: >>> On Tue, 7 Mar 2023 17:35:32 +0800 >>> fengchengwen <fengchengwen@huawei.com> wrote: >>> >>>> The syslog will add timestamp, but the syslog backend will re-write timestamp, so >>>> in the last, you can't find the real-timestamp of this log print. sometimes it requires >>>> to get real log time. >>>> PS: we found it in our test environment because RR schedule hang too long (similar question >>>> also found: https://bugzilla.redhat.com/show_bug.cgi?id=1855447). >>>> >>>> So suggest add timestamp in syslog string also, and don't convert to monotonic and just >>>> print as normal format (just like syslog). >>> >>> >>> Are you using systemd? >> >> Yes > > There is redhat bug about this: > https://bugzilla.redhat.com/show_bug.cgi?id=991678 > >>> Never, never configure a DPDK application with real-time process priority. >>> Polling model and RT don't mix. >> >> Maybe we should document them ? > > Part of previous discussion here: > https://mails.dpdk.org/archives/dev/2021-April/203778.html > > In my experience running DPDK on isolated threads (cgroup or scheduler isolation) > combined with remapping interrupts gives best response without lockup. > > I.e don't depend on scheduler to do the right thing. Instead ensure that > each thread runs on dedicated CPU. Got it, thanks. > > > > . > ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v3 2/2] eal: add option to put timestamp on console output 2023-03-08 0:36 ` fengchengwen 2023-03-08 2:03 ` Stephen Hemminger @ 2023-03-08 2:51 ` Stephen Hemminger 1 sibling, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-03-08 2:51 UTC (permalink / raw) To: fengchengwen; +Cc: dev, Bruce Richardson On Wed, 8 Mar 2023 08:36:48 +0800 fengchengwen <fengchengwen@huawei.com> wrote: > > Never, never configure a DPDK application with real-time process priority. > > Polling model and RT don't mix. > > Maybe we should document them ? LOL - ChatGPT is amusing if you ask it. The answer is pro grammatically correct, but will not work. The caveat at the end is much bigger than it understands. Question: Is Dataplane Development Kit (DPDK) compatible with Linux Real Time thread priority like SCH_FIFO? Yes, Dataplane Development Kit (DPDK) is compatible with Linux Real-Time thread priority scheduling policies, such as SCHED_FIFO. Answer: DPDK supports setting the thread priority using the standard Linux pthread APIs, including pthread_setschedparam() and pthread_attr_setschedpolicy(). This allows the application to configure the thread scheduling policy and priority for DPDK worker threads. To set the real-time priority of DPDK threads, you can use the pthread_setschedparam() function to set the scheduling policy to SCHED_FIFO or SCHED_RR and the priority value to a value between 1 and 99. Here is an example of how to set the real-time priority of a DPDK thread: > pthread_t tid; > struct sched_param sched_param; > pthread_attr_t attr; > > pthread_attr_init(&attr); > pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); > > sched_param.sched_priority = 50; > pthread_attr_setschedparam(&attr, &sched_param); > pthread_attr_setschedpolicy(&attr, SCHED_FIFO); > > pthread_create(&tid, &attr, thread_func, arg); In this example, the SCHED_FIFO scheduling policy is used, and the priority value is set to 50. You can adjust the priority value according to your needs. Note that using real-time scheduling policies like SCHED_FIFO or SCHED_RR requires careful consideration of system resources and may impact system performance if not used properly. It is recommended to consult the Linux documentation and to test the system thoroughly before deploying any application using real-time scheduling policies. ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v3 0/2] Add option to timestamp console log 2023-03-06 19:28 ` [PATCH v3 " Stephen Hemminger 2023-03-06 19:28 ` [PATCH v3 1/2] eal: unify logging code for FreeBsd and Linux Stephen Hemminger 2023-03-06 19:28 ` [PATCH v3 2/2] eal: add option to put timestamp on console output Stephen Hemminger @ 2023-03-07 7:33 ` Morten Brørup 2023-03-07 9:12 ` Bruce Richardson 2023-03-07 16:04 ` Stephen Hemminger 2 siblings, 2 replies; 445+ messages in thread From: Morten Brørup @ 2023-03-07 7:33 UTC (permalink / raw) To: Stephen Hemminger, dev > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > Sent: Monday, 6 March 2023 20.28 > > This is a reprise of earlier patch to add timestamp to console > messages. > > Example: > # dpdk-testpmd -l 1-4 -n 4 --vdev net_null0 --log-timestamp -- -i > EAL: Detected CPU lcores: 16 > EAL: Detected NUMA nodes: 1 > EAL: Detected static linkage of DPDK > EAL: Multi-process socket /var/run/dpdk/rte/mp_socket > EAL: Selected IOVA mode 'VA' > Interactive-mode selected > [ 0.191407] testpmd: create a new mbuf pool <mb_pool_0>: n=171456, > size=2176, socket=0 > [ 0.191510] testpmd: preferred mempool ops selected: ring_mp_mc This is useful. Here's some feature creep: Since the timestamp output is configurable, there is no need to settle on one specific timestamp format. The option could allow a choice between MONOTONIC and REALTIME, with an option for REALTIME to include the date in ISO 8601 format (YYYY-MM-DD). And REALTIME could be UTC or local time. You could consider taking a format string for strftime(), with the extension that %f expands to 6 digit microseconds like in Python [1]. [1]: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes With or without feature creep, Series-acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v3 0/2] Add option to timestamp console log 2023-03-07 7:33 ` [PATCH v3 0/2] Add option to timestamp console log Morten Brørup @ 2023-03-07 9:12 ` Bruce Richardson 2023-03-07 16:04 ` Stephen Hemminger 1 sibling, 0 replies; 445+ messages in thread From: Bruce Richardson @ 2023-03-07 9:12 UTC (permalink / raw) To: Morten Brørup; +Cc: Stephen Hemminger, dev On Tue, Mar 07, 2023 at 08:33:17AM +0100, Morten Brørup wrote: > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > Sent: Monday, 6 March 2023 20.28 > > > > This is a reprise of earlier patch to add timestamp to console > > messages. > > > > Example: > > # dpdk-testpmd -l 1-4 -n 4 --vdev net_null0 --log-timestamp -- -i > > EAL: Detected CPU lcores: 16 > > EAL: Detected NUMA nodes: 1 > > EAL: Detected static linkage of DPDK > > EAL: Multi-process socket /var/run/dpdk/rte/mp_socket > > EAL: Selected IOVA mode 'VA' > > Interactive-mode selected > > [ 0.191407] testpmd: create a new mbuf pool <mb_pool_0>: n=171456, > > size=2176, socket=0 > > [ 0.191510] testpmd: preferred mempool ops selected: ring_mp_mc > > This is useful. > > Here's some feature creep: Since the timestamp output is configurable, there is no need to settle on one specific timestamp format. The option could allow a choice between MONOTONIC and REALTIME, with an option for REALTIME to include the date in ISO 8601 format (YYYY-MM-DD). And REALTIME could be UTC or local time. You could consider taking a format string for strftime(), with the extension that %f expands to 6 digit microseconds like in Python [1]. > > [1]: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes > > With or without feature creep, > > Series-acked-by: Morten Brørup <mb@smartsharesystems.com> > Missed the fact there was already a v3 when I acked v2, so repeating here. Series-acked-by: Bruce Richardson <bruce.richardson@intel.com> I'd rather not have the feature creep on it though - at least not yet! ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v3 0/2] Add option to timestamp console log 2023-03-07 7:33 ` [PATCH v3 0/2] Add option to timestamp console log Morten Brørup 2023-03-07 9:12 ` Bruce Richardson @ 2023-03-07 16:04 ` Stephen Hemminger 1 sibling, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-03-07 16:04 UTC (permalink / raw) To: Morten Brørup; +Cc: dev On Tue, 7 Mar 2023 08:33:17 +0100 Morten Brørup <mb@smartsharesystems.com> wrote: > Here's some feature creep: Since the timestamp output is configurable, there is no need to settle on one specific timestamp format. The option could allow a choice between MONOTONIC and REALTIME, with an option for REALTIME to include the date in ISO 8601 format (YYYY-MM-DD). And REALTIME could be UTC or local time. You could consider taking a format string for strftime(), with the extension that %f expands to 6 digit microseconds like in Python [1]. Does that have compiler static checking issues if you allow user to set formats? ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v4 0/5] Logging related patchs 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (2 preceding siblings ...) 2023-03-06 19:28 ` [PATCH v3 " Stephen Hemminger @ 2023-06-26 18:42 ` Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 1/5] eal: unify logging code for FreeBsd and Linux Stephen Hemminger ` (5 more replies) 2023-06-28 17:58 ` [PATCH v5 0/6] Logging related patches Stephen Hemminger ` (25 subsequent siblings) 29 siblings, 6 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-26 18:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch set rebases and extends some earlier work on logging. Stephen Hemminger (5): eal: unify logging code for FreeBsd and Linux eal: turn off getopt_long error message during eal_log_level eal: skip stdio on console logging eal: move logging initialization earlier eal: add option to put timestamp on console output .../freebsd_gsg/freebsd_eal_parameters.rst | 32 +++++++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 + lib/eal/common/eal_common_options.c | 6 ++ lib/eal/common/eal_internal_cfg.h | 3 + lib/eal/common/eal_options.h | 2 + lib/eal/freebsd/eal.c | 39 +++++--- lib/eal/linux/eal.c | 48 +++++----- lib/eal/linux/eal_log.c | 61 ------------ lib/eal/linux/meson.build | 1 - lib/eal/unix/eal_log.c | 93 +++++++++++++++++++ lib/eal/unix/meson.build | 1 + lib/eal/windows/eal.c | 3 + 12 files changed, 194 insertions(+), 100 deletions(-) delete mode 100644 lib/eal/linux/eal_log.c create mode 100644 lib/eal/unix/eal_log.c -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v4 1/5] eal: unify logging code for FreeBsd and Linux 2023-06-26 18:42 ` [PATCH v4 0/5] Logging related patchs Stephen Hemminger @ 2023-06-26 18:42 ` Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 2/5] eal: turn off getopt_long error message during eal_log_level Stephen Hemminger ` (4 subsequent siblings) 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-26 18:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson FreeBSD logging code was not using syslog and did not have the same options as Linux. Move the log writing code to common source tree. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- .../freebsd_gsg/freebsd_eal_parameters.rst | 27 +++++++++++++++++++ lib/eal/freebsd/eal.c | 7 +++++ lib/eal/linux/meson.build | 1 - lib/eal/{linux => unix}/eal_log.c | 0 lib/eal/unix/meson.build | 1 + 5 files changed, 35 insertions(+), 1 deletion(-) rename lib/eal/{linux => unix}/eal_log.c (100%) diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index fba467a2ce92..9270d9fa3bfc 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -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 diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7008303e112a..6df6873e3889 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -52,6 +52,7 @@ #include "eal_hugepages.h" #include "eal_options.h" #include "eal_memcfg.h" +#include "eal_log.h" #include "eal_trace.h" #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL) @@ -759,6 +760,12 @@ rte_eal_init(int argc, char **argv) #endif } + if (eal_log_init(getprogname(), internal_conf->syslog_facility) < 0) { + rte_eal_init_alert("Cannot init logging."); + rte_errno = ENOMEM; + return -1; + } + /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/meson.build b/lib/eal/linux/meson.build index 5af456db9edb..e99ebed25692 100644 --- a/lib/eal/linux/meson.build +++ b/lib/eal/linux/meson.build @@ -11,7 +11,6 @@ sources += files( 'eal_hugepage_info.c', 'eal_interrupts.c', 'eal_lcore.c', - 'eal_log.c', 'eal_memalloc.c', 'eal_memory.c', 'eal_thread.c', diff --git a/lib/eal/linux/eal_log.c b/lib/eal/unix/eal_log.c similarity index 100% rename from lib/eal/linux/eal_log.c rename to lib/eal/unix/eal_log.c diff --git a/lib/eal/unix/meson.build b/lib/eal/unix/meson.build index cc7d67dd321d..37d07594df29 100644 --- a/lib/eal/unix/meson.build +++ b/lib/eal/unix/meson.build @@ -6,6 +6,7 @@ sources += files( 'eal_file.c', 'eal_filesystem.c', 'eal_firmware.c', + 'eal_log.c', 'eal_unix_memory.c', 'eal_unix_thread.c', 'eal_unix_timer.c', -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v4 2/5] eal: turn off getopt_long error message during eal_log_level 2023-06-26 18:42 ` [PATCH v4 0/5] Logging related patchs Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 1/5] eal: unify logging code for FreeBsd and Linux Stephen Hemminger @ 2023-06-26 18:42 ` Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 3/5] eal: skip stdio on console logging Stephen Hemminger ` (3 subsequent siblings) 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-26 18:42 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Keith Wiles, Bruce Richardson, Dmitry Kozlyuk, Narcisa Ana Maria Vasile, Dmitry Malloy, Pallavi Kadam If DPDK application is given a bogus option, the error message would get printed twice. Once during scan for log level and again during parsing of arguments. Example: # ./build/app/dpdk-testpmd --bogus ./build/app/dpdk-testpmd: unrecognized option '--bogus' EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 ./build/app/dpdk-testpmd: unrecognized option '--bogus' Usage: ./build/app/dpdk-testpmd [options] Fix by suppressing printing error message on first pass. Signed-off-by: Keith Wiles <keith.wiles@intel.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 2 ++ lib/eal/linux/eal.c | 2 ++ lib/eal/windows/eal.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6df6873e3889..70087837da18 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -381,6 +381,7 @@ eal_log_level_parse(int argc, char **argv) argvopt = argv; optind = 1; optreset = 1; + opterr = 0; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { @@ -424,6 +425,7 @@ eal_parse_args(int argc, char **argv) argvopt = argv; optind = 1; optreset = 1; + opterr = 1; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 145afafde234..60bb130aea15 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -561,6 +561,7 @@ eal_log_level_parse(int argc, char **argv) argvopt = argv; optind = 1; + opterr = 0; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { @@ -638,6 +639,7 @@ eal_parse_args(int argc, char **argv) argvopt = argv; optind = 1; + opterr = 1; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 2d7a0e9ab27e..0800a9e5c2d2 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -106,6 +106,8 @@ eal_log_level_parse(int argc, char **argv) struct internal_config *internal_conf = eal_get_internal_configuration(); + opterr = 0; + argvopt = argv; eal_reset_internal_config(internal_conf); @@ -143,6 +145,7 @@ eal_parse_args(int argc, char **argv) eal_get_internal_configuration(); argvopt = argv; + opterr = 1; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v4 3/5] eal: skip stdio on console logging 2023-06-26 18:42 ` [PATCH v4 0/5] Logging related patchs Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 1/5] eal: unify logging code for FreeBsd and Linux Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 2/5] eal: turn off getopt_long error message during eal_log_level Stephen Hemminger @ 2023-06-26 18:42 ` Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 4/5] eal: move logging initialization earlier Stephen Hemminger ` (2 subsequent siblings) 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-26 18:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger There is no need to use stdio when logging to console. Using the write system call directly avoids unnecessary copy to stdio output buffer. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/unix/eal_log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index d44416fd6570..baa721021991 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <sys/types.h> #include <syslog.h> +#include <unistd.h> #include <rte_log.h> @@ -19,8 +20,7 @@ console_log_write(__rte_unused void *c, const char *buf, size_t size) ssize_t ret; /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); + ret = write(STDERR_FILENO, buf, size); /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v4 4/5] eal: move logging initialization earlier 2023-06-26 18:42 ` [PATCH v4 0/5] Logging related patchs Stephen Hemminger ` (2 preceding siblings ...) 2023-06-26 18:42 ` [PATCH v4 3/5] eal: skip stdio on console logging Stephen Hemminger @ 2023-06-26 18:42 ` Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 5/5] eal: add option to put timestamp on console output Stephen Hemminger 2023-06-27 7:40 ` [PATCH v4 0/5] Logging related patchs Morten Brørup 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-26 18:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson The log stream should be setup before any messages. This ensures that any startup problems are captured on the syslog output, not only shown on the stderr. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 40 +++++++++++++++++++-------------------- lib/eal/linux/eal.c | 44 +++++++++++++++++++++---------------------- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 70087837da18..d3aac3d628a8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -364,7 +364,7 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* Parse the arguments for --log-level only */ +/* Parse the arguments for --log-level and --syslog */ static void eal_log_level_parse(int argc, char **argv) { @@ -386,20 +386,18 @@ eal_log_level_parse(int argc, char **argv) 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) + switch (opt) { + case OPT_SYSLOG_NUM: /* fallthrough */ + case OPT_LOG_LEVEL_NUM: + if (eal_parse_common_option(opt, optarg, internal_conf) < 0) + goto error; break; + case '?': + /* getopt is not happy, stop right now */ + goto error; + } } - +error: /* restore getopt lib */ optind = old_optind; optopt = old_optopt; @@ -437,8 +435,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_SYSLOG_NUM) continue; ret = eal_parse_common_option(opt, optarg, internal_conf); @@ -615,6 +613,12 @@ rte_eal_init(int argc, char **argv) /* set log level as early as possible */ eal_log_level_parse(argc, argv); + if (eal_log_init(getprogname(), internal_conf->syslog_facility) < 0) { + rte_eal_init_alert("Cannot init logging."); + rte_errno = ENOMEM; + return -1; + } + if (rte_eal_cpu_init() < 0) { rte_eal_init_alert("Cannot detect lcores."); rte_errno = ENOTSUP; @@ -762,12 +766,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(getprogname(), internal_conf->syslog_facility) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - return -1; - } - /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 60bb130aea15..51c4ec75d57b 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -546,7 +546,7 @@ eal_parse_vfio_vf_token(const char *vf_token) return -1; } -/* Parse the arguments for --log-level only */ +/* Parse the arguments for --log-level and --syslog */ static void eal_log_level_parse(int argc, char **argv) { @@ -566,20 +566,18 @@ eal_log_level_parse(int argc, char **argv) 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) + switch (opt) { + case OPT_SYSLOG_NUM: /* fallthrough */ + case OPT_LOG_LEVEL_NUM: + if (eal_parse_common_option(opt, optarg, internal_conf) < 0) + goto error; break; + case '?': + /* getopt is not happy, stop right now */ + goto error; + } } - +error: /* restore getopt lib */ optind = old_optind; optopt = old_optopt; @@ -651,8 +649,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_SYSLOG_NUM) continue; ret = eal_parse_common_option(opt, optarg, internal_conf); @@ -997,6 +995,14 @@ rte_eal_init(int argc, char **argv) /* set log level as early as possible */ eal_log_level_parse(argc, argv); + if (eal_log_init(program_invocation_short_name, + internal_conf->syslog_facility) < 0) { + rte_eal_init_alert("Cannot init logging."); + rte_errno = ENOMEM; + __atomic_store_n(&run_once, 0, __ATOMIC_RELAXED); + return -1; + } + /* clone argv to report out later in telemetry */ eal_save_args(argc, argv); @@ -1167,14 +1173,6 @@ 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; - __atomic_store_n(&run_once, 0, __ATOMIC_RELAXED); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v4 5/5] eal: add option to put timestamp on console output 2023-06-26 18:42 ` [PATCH v4 0/5] Logging related patchs Stephen Hemminger ` (3 preceding siblings ...) 2023-06-26 18:42 ` [PATCH v4 4/5] eal: move logging initialization earlier Stephen Hemminger @ 2023-06-26 18:42 ` Stephen Hemminger 2023-06-27 7:40 ` [PATCH v4 0/5] Logging related patchs Morten Brørup 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-26 18:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson 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. The timestamp format is chosen to look like the default Linux dmesg timestamp. Example: $ dpdk-testpmd --log-timestamp -- -i [ 0.007615] EAL: Detected CPU lcores: 16 [ 0.007657] EAL: Detected NUMA nodes: 1 [ 0.007878] EAL: Detected static linkage of DPDK [ 0.009469] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket [ 0.012175] EAL: Selected IOVA mode 'VA' [ 0.120016] testpmd: No probed ethernet devices Interactive-mode selected [ 0.155959] testpmd: create a new mbuf pool <mb_pool_0>: n=267456, size=2176, socket=0 [ 0.155990] testpmd: preferred mempool ops selected: ring_mp_mc Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- .../freebsd_gsg/freebsd_eal_parameters.rst | 5 +++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ lib/eal/common/eal_common_options.c | 6 ++++ lib/eal/common/eal_internal_cfg.h | 3 ++ lib/eal/common/eal_options.h | 2 ++ lib/eal/freebsd/eal.c | 4 ++- lib/eal/linux/eal.c | 4 ++- lib/eal/unix/eal_log.c | 36 +++++++++++++++++-- 8 files changed, 61 insertions(+), 4 deletions(-) diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index 9270d9fa3bfc..99cff10e963c 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -45,3 +45,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f38139119..719ca6851625 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -135,3 +135,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 03059336987d..c6c74cc31e9c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -76,6 +76,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, 0, 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 }, @@ -1835,6 +1836,10 @@ eal_parse_common_option(int opt, const char *optarg, } #ifndef RTE_EXEC_ENV_WINDOWS + case OPT_LOG_TIMESTAMP_NUM: + conf->log_timestamp = 1; + break; + case OPT_TRACE_NUM: { if (eal_trace_args_save(optarg) < 0) { RTE_LOG(ERR, EAL, "invalid parameters for --" @@ -2194,6 +2199,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa79..1a1a7fdcfa8c 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -84,7 +84,10 @@ struct internal_config { /**< true if storing all pages within single files (per-page-size, * per-node) non-legacy mode only. */ + volatile uint8_t log_timestamp; /**< add timestamp to console output */ volatile int syslog_facility; /**< facility passed to openlog() */ + struct timespec log_start_time; /**< when logging was started */ + /** 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 */ diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb641284..cc9723868e3c 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3aac3d628a8..5c7cea8809bd 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -388,6 +388,7 @@ eal_log_level_parse(int argc, char **argv) switch (opt) { case OPT_SYSLOG_NUM: /* fallthrough */ + case OPT_LOG_TIMESTAMP_NUM: /* fallthrough */ case OPT_LOG_LEVEL_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) goto error; @@ -436,7 +437,8 @@ eal_parse_args(int argc, char **argv) } /* eal_log_level_parse() already handled these */ - if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM) + if (opt == OPT_SYSLOG_NUM || + opt == OPT_LOG_TIMESTAMP_NUM || opt == OPT_LOG_LEVEL_NUM) continue; ret = eal_parse_common_option(opt, optarg, internal_conf); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 51c4ec75d57b..051f9ad7f5bf 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -568,6 +568,7 @@ eal_log_level_parse(int argc, char **argv) switch (opt) { case OPT_SYSLOG_NUM: /* fallthrough */ + case OPT_LOG_TIMESTAMP_NUM: /* fallthrough */ case OPT_LOG_LEVEL_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) goto error; @@ -650,7 +651,8 @@ eal_parse_args(int argc, char **argv) } /* eal_log_level_parse() already handled these */ - if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM) + if (opt == OPT_SYSLOG_NUM || + opt == OPT_LOG_TIMESTAMP_NUM || opt == OPT_LOG_LEVEL_NUM) continue; ret = eal_parse_common_option(opt, optarg, internal_conf); diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index baa721021991..f65a22612310 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -4,12 +4,15 @@ #include <stdio.h> #include <sys/types.h> +#include <sys/uio.h> #include <syslog.h> +#include <time.h> #include <unistd.h> #include <rte_log.h> #include "eal_log.h" +#include "eal_private.h" /* * default log function @@ -17,10 +20,36 @@ static ssize_t console_log_write(__rte_unused void *c, const char *buf, size_t size) { + const struct internal_config *internal_conf = eal_get_internal_configuration(); ssize_t ret; - /* write on stderr */ - ret = write(STDERR_FILENO, buf, size); + /* add optional timestamp for stderr */ + if (internal_conf->log_timestamp) { + struct iovec iov[2]; + struct timespec ts; + char tbuf[64]; + + /* format up monotonic timestamp */ + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec -= internal_conf->log_start_time.tv_sec; + ts.tv_nsec -= internal_conf->log_start_time.tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000ul; + } + + /* use writev to put timestamp and buf in single operation */ + iov[0].iov_base = tbuf; + iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "[%8lu.%06lu] ", + ts.tv_sec, ts.tv_nsec / 1000u); + + /* casts are to unconstify the buf */ + iov[1].iov_base = (void *)(uintptr_t)buf; + iov[1].iov_len = size; + ret = writev(STDERR_FILENO, iov, 2); + } else { + ret = write(STDERR_FILENO, buf, size); + } /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); @@ -47,8 +76,11 @@ static cookie_io_functions_t console_log_func = { int eal_log_init(const char *id, int facility) { + struct internal_config *internal_conf = eal_get_internal_configuration(); FILE *log_stream; + clock_gettime(CLOCK_MONOTONIC, &internal_conf->log_start_time); + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v4 0/5] Logging related patchs 2023-06-26 18:42 ` [PATCH v4 0/5] Logging related patchs Stephen Hemminger ` (4 preceding siblings ...) 2023-06-26 18:42 ` [PATCH v4 5/5] eal: add option to put timestamp on console output Stephen Hemminger @ 2023-06-27 7:40 ` Morten Brørup 2023-06-27 14:49 ` Stephen Hemminger 2023-06-27 15:02 ` Bruce Richardson 5 siblings, 2 replies; 445+ messages in thread From: Morten Brørup @ 2023-06-27 7:40 UTC (permalink / raw) To: Stephen Hemminger, dev > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > Sent: Monday, 26 June 2023 20.42 > To: dev@dpdk.org > Cc: Stephen Hemminger > Subject: [PATCH v4 0/5] Logging related patchs > > This patch set rebases and extends some earlier work on logging. > > Stephen Hemminger (5): > eal: unify logging code for FreeBsd and Linux > eal: turn off getopt_long error message during eal_log_level > eal: skip stdio on console logging > eal: move logging initialization earlier > eal: add option to put timestamp on console output Series-acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v4 0/5] Logging related patchs 2023-06-27 7:40 ` [PATCH v4 0/5] Logging related patchs Morten Brørup @ 2023-06-27 14:49 ` Stephen Hemminger 2023-06-27 15:04 ` Morten Brørup 2023-06-27 15:02 ` Bruce Richardson 1 sibling, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2023-06-27 14:49 UTC (permalink / raw) To: Morten Brørup; +Cc: dev On Tue, 27 Jun 2023 09:40:01 +0200 Morten Brørup <mb@smartsharesystems.com> wrote: > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > Sent: Monday, 26 June 2023 20.42 > > To: dev@dpdk.org > > Cc: Stephen Hemminger > > Subject: [PATCH v4 0/5] Logging related patchs > > > > This patch set rebases and extends some earlier work on logging. > > > > Stephen Hemminger (5): > > eal: unify logging code for FreeBsd and Linux > > eal: turn off getopt_long error message during eal_log_level > > eal: skip stdio on console logging > > eal: move logging initialization earlier > > eal: add option to put timestamp on console output > > Series-acked-by: Morten Brørup <mb@smartsharesystems.com> > There are a few bugs, still working them out. In initial review feedback there was desire for timestamp feature to be global. I.e secondary process would show time since start of primary. But this would hard to implement due to chicken/egg issues during argument parsing during startup; so made a decision that it wasn't worth doing. ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v4 0/5] Logging related patchs 2023-06-27 14:49 ` Stephen Hemminger @ 2023-06-27 15:04 ` Morten Brørup 0 siblings, 0 replies; 445+ messages in thread From: Morten Brørup @ 2023-06-27 15:04 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > Sent: Tuesday, 27 June 2023 16.49 > > On Tue, 27 Jun 2023 09:40:01 +0200 > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > > Sent: Monday, 26 June 2023 20.42 > > > To: dev@dpdk.org > > > Cc: Stephen Hemminger > > > Subject: [PATCH v4 0/5] Logging related patchs > > > > > > This patch set rebases and extends some earlier work on logging. > > > > > > Stephen Hemminger (5): > > > eal: unify logging code for FreeBsd and Linux > > > eal: turn off getopt_long error message during eal_log_level > > > eal: skip stdio on console logging > > > eal: move logging initialization earlier > > > eal: add option to put timestamp on console output > > > > Series-acked-by: Morten Brørup <mb@smartsharesystems.com> > > > > There are a few bugs, still working them out. > In initial review feedback there was desire for timestamp feature > to be global. I.e secondary process would show time since start > of primary. But this would hard to implement due to chicken/egg > issues during argument parsing during startup; so made a decision > that it wasn't worth doing. I suppose it could be implemented with a piece of shared memory set by the primary process and read by secondary processes, holding the start time offset from a system global timer (e.g. CLOCK_MONOTONIC) and a tristate variable telling if timestamps are configured - which, if true or false, overrides any timestamp parameter given to the secondary process. Anyway, secondary process support is far from perfect, so I wouldn't worry too much about getting timestamp parameters from the primary process to the secondary process either. In short: I agree with your decision. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v4 0/5] Logging related patchs 2023-06-27 7:40 ` [PATCH v4 0/5] Logging related patchs Morten Brørup 2023-06-27 14:49 ` Stephen Hemminger @ 2023-06-27 15:02 ` Bruce Richardson 1 sibling, 0 replies; 445+ messages in thread From: Bruce Richardson @ 2023-06-27 15:02 UTC (permalink / raw) To: Morten Brørup; +Cc: Stephen Hemminger, dev On Tue, Jun 27, 2023 at 09:40:01AM +0200, Morten Brørup wrote: > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > Sent: Monday, 26 June 2023 20.42 > > To: dev@dpdk.org > > Cc: Stephen Hemminger > > Subject: [PATCH v4 0/5] Logging related patchs > > > > This patch set rebases and extends some earlier work on logging. > > > > Stephen Hemminger (5): > > eal: unify logging code for FreeBsd and Linux > > eal: turn off getopt_long error message during eal_log_level > > eal: skip stdio on console logging > > eal: move logging initialization earlier > > eal: add option to put timestamp on console output > > Series-acked-by: Morten Brørup <mb@smartsharesystems.com> > Gave it a quick sanity-test run on FreeBSD and all looks ok to me. Tested-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v5 0/6] Logging related patches 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (3 preceding siblings ...) 2023-06-26 18:42 ` [PATCH v4 0/5] Logging related patchs Stephen Hemminger @ 2023-06-28 17:58 ` Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 1/6] eal: unify logging code for FreeBsd and Linux Stephen Hemminger ` (5 more replies) 2023-06-29 15:58 ` [PATCH v6 0/6] Logging related patches Stephen Hemminger ` (24 subsequent siblings) 29 siblings, 6 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-28 17:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch set rebases and extends some earlier work on logging. Stephen Hemminger (6): eal: unify logging code for FreeBsd and Linux eal: turn off getopt_long error message during eal_log_level eal: fix handling of syslog facility eal: skip stdio on console logging eal: allow user to set default log stream before init eal: add option to put timestamp on console output v6 - make more of the log arg parsing common - handle --syslog argument better - drop the early logging initialization (need shmem to be setup) - base timestamp on start of primary process (in shmem) .../freebsd_gsg/freebsd_eal_parameters.rst | 32 ++++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 + lib/eal/common/eal_common_log.c | 6 + lib/eal/common/eal_common_options.c | 8 +- lib/eal/common/eal_internal_cfg.h | 3 + lib/eal/common/eal_log.h | 6 + lib/eal/common/eal_options.h | 2 + lib/eal/freebsd/eal.c | 59 ++----- lib/eal/linux/eal.c | 52 ++---- lib/eal/linux/eal_log.c | 61 ------- lib/eal/linux/meson.build | 1 - lib/eal/unix/eal_log.c | 165 ++++++++++++++++++ lib/eal/unix/meson.build | 1 + lib/eal/windows/eal.c | 3 + 14 files changed, 255 insertions(+), 149 deletions(-) delete mode 100644 lib/eal/linux/eal_log.c create mode 100644 lib/eal/unix/eal_log.c -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v5 1/6] eal: unify logging code for FreeBsd and Linux 2023-06-28 17:58 ` [PATCH v5 0/6] Logging related patches Stephen Hemminger @ 2023-06-28 17:58 ` Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 2/6] eal: turn off getopt_long error message during eal_log_level Stephen Hemminger ` (4 subsequent siblings) 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-28 17:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson FreeBSD logging code was not using syslog and did not have the same options as Linux. Move the log writing code to common source tree. Also fix a number of argument parsing bugs: 1. If application is given a bogus option, the error message would get printed twice. Once during scan for log level and again during parsing of arguments. 2. A bad argument give to --log-level option was given the code would keep going. 3. The syslog facility argument was parsed too late to all log to be initialized before other errors. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- .../freebsd_gsg/freebsd_eal_parameters.rst | 27 ++++ lib/eal/common/eal_log.h | 5 + lib/eal/freebsd/eal.c | 55 ++------ lib/eal/linux/eal.c | 48 +------ lib/eal/linux/eal_log.c | 61 --------- lib/eal/linux/meson.build | 1 - lib/eal/unix/eal_log.c | 121 ++++++++++++++++++ lib/eal/unix/meson.build | 1 + 8 files changed, 173 insertions(+), 146 deletions(-) delete mode 100644 lib/eal/linux/eal_log.c create mode 100644 lib/eal/unix/eal_log.c diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index fba467a2ce92..9270d9fa3bfc 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -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 diff --git a/lib/eal/common/eal_log.h b/lib/eal/common/eal_log.h index c784fa604389..31dc489350f6 100644 --- a/lib/eal/common/eal_log.h +++ b/lib/eal/common/eal_log.h @@ -13,6 +13,11 @@ */ int eal_log_init(const char *id, int facility); +/* + * Scan command line args for log settings. + */ +int eal_log_level_parse(int argc, char * const argv[]); + /* * Determine where log data is written when no call to rte_openlog_stream. */ diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7008303e112a..bb9a2b1653d9 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -52,6 +52,7 @@ #include "eal_hugepages.h" #include "eal_options.h" #include "eal_memcfg.h" +#include "eal_log.h" #include "eal_trace.h" #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL) @@ -363,48 +364,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) @@ -610,7 +569,11 @@ rte_eal_init(int argc, char **argv) eal_save_args(argc, argv); /* set log level as early as possible */ - eal_log_level_parse(argc, argv); + if (eal_log_level_parse(argc, argv) < 0) { + rte_eal_init_alert("invalid log option."); + rte_errno = EINVAL; + return -1; + } if (rte_eal_cpu_init() < 0) { rte_eal_init_alert("Cannot detect lcores."); @@ -759,6 +722,12 @@ rte_eal_init(int argc, char **argv) #endif } + if (eal_log_init(getprogname(), internal_conf->syslog_facility) < 0) { + rte_eal_init_alert("Cannot init logging."); + rte_errno = ENOMEM; + return -1; + } + /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 145afafde234..d7f268fc8116 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { @@ -649,7 +610,7 @@ eal_parse_args(int argc, char **argv) goto out; } - /* eal_log_level_parse() already handled this option */ + /* eal_log_level_parse() already handled these */ if (opt == OPT_LOG_LEVEL_NUM) continue; @@ -993,7 +954,12 @@ 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); + if (eal_log_level_parse(argc, argv) < 0) { + rte_eal_init_alert("invalid log option."); + rte_errno = EINVAL; + __atomic_store_n(&run_once, 0, __ATOMIC_RELAXED); + return -1; + } /* clone argv to report out later in telemetry */ eal_save_args(argc, argv); diff --git a/lib/eal/linux/eal_log.c b/lib/eal/linux/eal_log.c deleted file mode 100644 index d44416fd6570..000000000000 --- a/lib/eal/linux/eal_log.c +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_log.h> - -#include "eal_log.h" - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -int -eal_log_init(const char *id, int facility) -{ - FILE *log_stream; - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - - openlog(id, LOG_NDELAY | LOG_PID, facility); - - eal_log_set_default(log_stream); - - return 0; -} diff --git a/lib/eal/linux/meson.build b/lib/eal/linux/meson.build index 5af456db9edb..e99ebed25692 100644 --- a/lib/eal/linux/meson.build +++ b/lib/eal/linux/meson.build @@ -11,7 +11,6 @@ sources += files( 'eal_hugepage_info.c', 'eal_interrupts.c', 'eal_lcore.c', - 'eal_log.c', 'eal_memalloc.c', 'eal_memory.c', 'eal_thread.c', diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c new file mode 100644 index 000000000000..f8a5c853f2df --- /dev/null +++ b/lib/eal/unix/eal_log.c @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include <getopt.h> +#include <stdio.h> +#include <sys/types.h> +#include <syslog.h> + +#include <rte_log.h> + +#include "eal_log.h" +#include "eal_internal_cfg.h" +#include "eal_options.h" +#include "eal_private.h" + +/* + * default log function + */ +static ssize_t +console_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + ssize_t ret; + + /* write on stderr */ + ret = fwrite(buf, 1, size, stderr); + fflush(stderr); + + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + +#ifdef RTE_EXEC_ENV_LINUX + /* Handle glibc quirk: write function should return the number of bytes + * copied from buf, or 0 on error. (The function must not return a negative value.) + * FreeBSD expects that write function behaves like write(2). + */ + if (ret < 0) + ret = 0; +#endif + + return ret; +} + +static int +console_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t console_log_func = { + .write = console_log_write, + .close = console_log_close, +}; + + +/* + * Parse the arguments for --log-level and --syslog + */ +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; + char * const old_optarg = optarg; +#ifdef RTE_EXEC_ENV_FREEBSD + const int old_optrset = optreset; +#endif + + optind = 1; +#ifdef RTE_EXEC_ENV_FREEBSD + optreset = 1; +#endif + + 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* restore getopt lib */ + optind = old_optind; + optopt = old_optopt; + optarg = old_optarg; +#ifdef RTE_EXEC_ENV_FREEBSD + optreset = old_optreset; +#endif + return 0; +} + +/* + * set the log to default function, called during eal init process, + * once memzones are available. + */ +int +eal_log_init(const char *id, int facility) +{ + FILE *log_stream; + + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream == NULL) + return -1; + + openlog(id, LOG_NDELAY | LOG_PID, facility); + + eal_log_set_default(log_stream); + + return 0; +} diff --git a/lib/eal/unix/meson.build b/lib/eal/unix/meson.build index cc7d67dd321d..37d07594df29 100644 --- a/lib/eal/unix/meson.build +++ b/lib/eal/unix/meson.build @@ -6,6 +6,7 @@ sources += files( 'eal_file.c', 'eal_filesystem.c', 'eal_firmware.c', + 'eal_log.c', 'eal_unix_memory.c', 'eal_unix_thread.c', 'eal_unix_timer.c', -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v5 2/6] eal: turn off getopt_long error message during eal_log_level 2023-06-28 17:58 ` [PATCH v5 0/6] Logging related patches Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 1/6] eal: unify logging code for FreeBsd and Linux Stephen Hemminger @ 2023-06-28 17:58 ` Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 3/6] eal: fix handling of syslog facility Stephen Hemminger ` (3 subsequent siblings) 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-28 17:58 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Keith Wiles, Dmitry Kozlyuk, Narcisa Ana Maria Vasile, Dmitry Malloy, Pallavi Kadam If DPDK application is given a bogus option, the error message would get printed twice. Once during scan for log level and again during parsing of arguments. Example: # ./build/app/dpdk-testpmd --bogus ./build/app/dpdk-testpmd: unrecognized option '--bogus' EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 ./build/app/dpdk-testpmd: unrecognized option '--bogus' Usage: ./build/app/dpdk-testpmd [options] Fix by suppressing printing error message on first pass. Signed-off-by: Keith Wiles <keith.wiles@intel.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/unix/eal_log.c | 3 +++ lib/eal/windows/eal.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index f8a5c853f2df..3f54284494d7 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -64,12 +64,14 @@ eal_log_level_parse(int argc, char *const argv[]) int option_index, opt; const int old_optind = optind; const int old_optopt = optopt; + const int old_opterr = opterr; char * const old_optarg = optarg; #ifdef RTE_EXEC_ENV_FREEBSD const int old_optrset = optreset; #endif optind = 1; + opterr = 0; #ifdef RTE_EXEC_ENV_FREEBSD optreset = 1; #endif @@ -94,6 +96,7 @@ eal_log_level_parse(int argc, char *const argv[]) optind = old_optind; optopt = old_optopt; optarg = old_optarg; + opterr = old_opterr; #ifdef RTE_EXEC_ENV_FREEBSD optreset = old_optreset; #endif diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 2d7a0e9ab27e..0800a9e5c2d2 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -106,6 +106,8 @@ eal_log_level_parse(int argc, char **argv) struct internal_config *internal_conf = eal_get_internal_configuration(); + opterr = 0; + argvopt = argv; eal_reset_internal_config(internal_conf); @@ -143,6 +145,7 @@ eal_parse_args(int argc, char **argv) eal_get_internal_configuration(); argvopt = argv; + opterr = 1; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v5 3/6] eal: fix handling of syslog facility 2023-06-28 17:58 ` [PATCH v5 0/6] Logging related patches Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 1/6] eal: unify logging code for FreeBsd and Linux Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 2/6] eal: turn off getopt_long error message during eal_log_level Stephen Hemminger @ 2023-06-28 17:58 ` Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 4/6] eal: skip stdio on console logging Stephen Hemminger ` (2 subsequent siblings) 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-28 17:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson The syslog facility option needs to be parsed before log_init is called. Also help message whas missing the required argument. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 2 +- lib/eal/freebsd/eal.c | 2 +- lib/eal/linux/eal.c | 2 +- lib/eal/unix/eal_log.c | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 03059336987d..005da4d12001 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2193,7 +2193,7 @@ eal_common_usage(void) " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_SYSLOG"=<facility> Set syslog facility\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bb9a2b1653d9..104507b61514 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -394,7 +394,7 @@ eal_parse_args(int argc, char **argv) } /* eal_log_level_parse() already handled this option */ - if (opt == OPT_LOG_LEVEL_NUM) + if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM) continue; ret = eal_parse_common_option(opt, optarg, internal_conf); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index d7f268fc8116..e30c44380e30 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -611,7 +611,7 @@ eal_parse_args(int argc, char **argv) } /* eal_log_level_parse() already handled these */ - if (opt == OPT_LOG_LEVEL_NUM) + if (opt == OPT_LOG_LEVEL_NUM || opt == OPT_SYSLOG_NUM) continue; ret = eal_parse_common_option(opt, optarg, internal_conf); diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index 3f54284494d7..93cf04fae043 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -80,6 +80,7 @@ eal_log_level_parse(int argc, char *const argv[]) eal_long_options, &option_index)) != EOF) { switch (opt) { + case OPT_SYSLOG_NUM: case OPT_LOG_LEVEL_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v5 4/6] eal: skip stdio on console logging 2023-06-28 17:58 ` [PATCH v5 0/6] Logging related patches Stephen Hemminger ` (2 preceding siblings ...) 2023-06-28 17:58 ` [PATCH v5 3/6] eal: fix handling of syslog facility Stephen Hemminger @ 2023-06-28 17:58 ` Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 5/6] eal: allow user to set default log stream before init Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 6/6] eal: add option to put timestamp on console output Stephen Hemminger 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-28 17:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger There is no need to use stdio when logging to console. Using the write system call directly avoids unnecessary copy to stdio output buffer. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/unix/eal_log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index 93cf04fae043..7921417b050a 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -6,6 +6,7 @@ #include <stdio.h> #include <sys/types.h> #include <syslog.h> +#include <unistd.h> #include <rte_log.h> @@ -23,8 +24,7 @@ console_log_write(__rte_unused void *c, const char *buf, size_t size) ssize_t ret; /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); + ret = write(STDERR_FILENO, buf, size); /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v5 5/6] eal: allow user to set default log stream before init 2023-06-28 17:58 ` [PATCH v5 0/6] Logging related patches Stephen Hemminger ` (3 preceding siblings ...) 2023-06-28 17:58 ` [PATCH v5 4/6] eal: skip stdio on console logging Stephen Hemminger @ 2023-06-28 17:58 ` Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 6/6] eal: add option to put timestamp on console output Stephen Hemminger 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-28 17:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger It is useful for application to be able to set the default log stream before call rte_eal_init(). This makes all messages go to the new default. For example, to skip using syslog; just doing rte_log_set_default(stderr); Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_log.c | 6 ++++++ lib/eal/common/eal_log.h | 1 + lib/eal/unix/eal_log.c | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c index bd7b188ceb4a..9b158c201205 100644 --- a/lib/eal/common/eal_common_log.c +++ b/lib/eal/common/eal_common_log.c @@ -535,6 +535,12 @@ eal_log_set_default(FILE *default_log) #endif } +FILE * +eal_log_get_default(void) +{ + return default_log_stream; +} + /* * Called by eal_cleanup */ diff --git a/lib/eal/common/eal_log.h b/lib/eal/common/eal_log.h index 31dc489350f6..268c2a264382 100644 --- a/lib/eal/common/eal_log.h +++ b/lib/eal/common/eal_log.h @@ -22,6 +22,7 @@ int eal_log_level_parse(int argc, char * const argv[]); * Determine where log data is written when no call to rte_openlog_stream. */ void eal_log_set_default(FILE *default_log); +FILE *eal_log_get_default(void); /* * Save a log option for later. diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index 7921417b050a..3bfe5853095f 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -113,6 +113,10 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; + /* has user has already setup a log stream */ + if (eal_log_get_default()) + return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v5 6/6] eal: add option to put timestamp on console output 2023-06-28 17:58 ` [PATCH v5 0/6] Logging related patches Stephen Hemminger ` (4 preceding siblings ...) 2023-06-28 17:58 ` [PATCH v5 5/6] eal: allow user to set default log stream before init Stephen Hemminger @ 2023-06-28 17:58 ` Stephen Hemminger 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-28 17:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Anatoly Burakov 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. The timestamp format is chosen to look like the default Linux dmesg timestamp. The first few lines are not timestamped because the flag is stored in internal configuration which is stored in shared memory which is not setup up until a little later in startup process. Example: $ dpdk-testpmd --log-timestamp -- -i EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 EAL: Detected static linkage of DPDK EAL: Multi-process socket /var/run/dpdk/rte/mp_socket EAL: Selected IOVA mode 'VA' [ 0.112264] testpmd: No probed ethernet devices Interactive-mode selected [ 0.184573] testpmd: create a new mbuf pool <mb_pool_0>: n=163456, size=2176, socket=0 [ 0.184612] testpmd: preferred mempool ops selected: ring_mp_mc Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- .../freebsd_gsg/freebsd_eal_parameters.rst | 5 +++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ lib/eal/common/eal_common_options.c | 6 +++ lib/eal/common/eal_internal_cfg.h | 3 ++ lib/eal/common/eal_options.h | 2 + lib/eal/freebsd/eal.c | 4 +- lib/eal/linux/eal.c | 4 +- lib/eal/unix/eal_log.c | 44 +++++++++++++++++-- 8 files changed, 67 insertions(+), 6 deletions(-) diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index 9270d9fa3bfc..99cff10e963c 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -45,3 +45,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f38139119..719ca6851625 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -135,3 +135,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 005da4d12001..67fe6efb4526 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -76,6 +76,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, 0, 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 }, @@ -1835,6 +1836,10 @@ eal_parse_common_option(int opt, const char *optarg, } #ifndef RTE_EXEC_ENV_WINDOWS + case OPT_LOG_TIMESTAMP_NUM: + conf->log_timestamp = 1; + break; + case OPT_TRACE_NUM: { if (eal_trace_args_save(optarg) < 0) { RTE_LOG(ERR, EAL, "invalid parameters for --" @@ -2194,6 +2199,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"=<facility> Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa79..ca502d5dd365 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -84,7 +84,10 @@ struct internal_config { /**< true if storing all pages within single files (per-page-size, * per-node) non-legacy mode only. */ + uint8_t log_timestamp; /**< add timestamp to console output */ + struct timespec log_start_time; /**< monotonic clock when started */ 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 */ diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb641284..cc9723868e3c 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 104507b61514..ae3a736e862d 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -394,7 +394,9 @@ eal_parse_args(int argc, char **argv) } /* eal_log_level_parse() already handled this option */ - 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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index e30c44380e30..6deb694e7242 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -611,7 +611,9 @@ eal_parse_args(int argc, char **argv) } /* eal_log_level_parse() already handled these */ - 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); diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index 3bfe5853095f..172b332b8417 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -5,7 +5,9 @@ #include <getopt.h> #include <stdio.h> #include <sys/types.h> +#include <sys/uio.h> #include <syslog.h> +#include <time.h> #include <unistd.h> #include <rte_log.h> @@ -19,12 +21,38 @@ * default log function */ static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) +console_log_write(void *c, const char *buf, size_t size) { + const struct internal_config *internal_conf = c; ssize_t ret; - /* write on stderr */ - ret = write(STDERR_FILENO, buf, size); + /* add optional timestamp for stderr */ + if (internal_conf->log_timestamp) { + struct iovec iov[2]; + struct timespec ts; + char tbuf[64]; + + /* format up monotonic timestamp */ + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec -= internal_conf->log_start_time.tv_sec; + ts.tv_nsec -= internal_conf->log_start_time.tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000ul; + } + + /* use writev to put timestamp and buf in single operation */ + iov[0].iov_base = tbuf; + iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "[%8lu.%06lu] ", + ts.tv_sec, ts.tv_nsec / 1000u); + + /* casts are to unconstify the buf */ + iov[1].iov_base = (void *)(uintptr_t)buf; + iov[1].iov_len = size; + ret = writev(STDERR_FILENO, iov, 2); + } else { + ret = write(STDERR_FILENO, buf, size); + } /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); @@ -82,6 +110,7 @@ eal_log_level_parse(int argc, char *const argv[]) switch (opt) { case OPT_SYSLOG_NUM: case OPT_LOG_LEVEL_NUM: + case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -111,13 +140,20 @@ eal_log_level_parse(int argc, char *const argv[]) int eal_log_init(const char *id, int facility) { + struct internal_config *internal_conf = eal_get_internal_configuration(); FILE *log_stream; /* has user has already setup a log stream */ if (eal_log_get_default()) return 0; - log_stream = fopencookie(NULL, "w+", console_log_func); + if (internal_conf->process_type == RTE_PROC_PRIMARY && + internal_conf->log_timestamp) { + if (clock_gettime(CLOCK_MONOTONIC, &internal_conf->log_start_time) < 0) + return -1; + } + + log_stream = fopencookie(internal_conf, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v6 0/6] Logging related patches 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (4 preceding siblings ...) 2023-06-28 17:58 ` [PATCH v5 0/6] Logging related patches Stephen Hemminger @ 2023-06-29 15:58 ` Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 1/6] eal: unify logging code Stephen Hemminger ` (5 more replies) 2023-07-05 22:48 ` [PATCH v7 0/5] Logging timetamp and related patches Stephen Hemminger ` (23 subsequent siblings) 29 siblings, 6 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-29 15:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Patchset that includes: - unified code for more of log argument handling - fix for duplicate option errors - timestamp option for logging v6 - fix build on freebsd and windows - add test for log timestamp Stephen Hemminger (6): eal: unify logging code eal: turn off getopt_long error message during eal_log_level eal: fix help message for syslog option eal: skip stdio on console logging eal: allow user to set default log stream before init eal: add option to put timestamp on console output app/dumpcap/main.c | 3 + app/pdump/main.c | 3 + app/proc-info/main.c | 3 + app/test/test_eal_flags.c | 9 ++ .../freebsd_gsg/freebsd_eal_parameters.rst | 32 +++++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 + lib/eal/common/eal_common_log.c | 55 +++++++++ lib/eal/common/eal_common_options.c | 8 +- lib/eal/common/eal_internal_cfg.h | 3 + lib/eal/common/eal_log.h | 6 + lib/eal/common/eal_options.h | 2 + lib/eal/freebsd/eal.c | 55 ++------- lib/eal/linux/eal.c | 46 +------- lib/eal/linux/eal_log.c | 61 ---------- lib/eal/linux/meson.build | 1 - lib/eal/unix/eal_log.c | 111 ++++++++++++++++++ lib/eal/unix/meson.build | 1 + lib/eal/windows/eal.c | 36 +----- 18 files changed, 259 insertions(+), 181 deletions(-) delete mode 100644 lib/eal/linux/eal_log.c create mode 100644 lib/eal/unix/eal_log.c -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v6 1/6] eal: unify logging code 2023-06-29 15:58 ` [PATCH v6 0/6] Logging related patches Stephen Hemminger @ 2023-06-29 15:58 ` Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 2/6] eal: turn off getopt_long error message during eal_log_level Stephen Hemminger ` (4 subsequent siblings) 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-29 15:58 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Narcisa Ana Maria Vasile, Dmitry Malloy, Pallavi Kadam FreeBSD logging code was not using syslog and did not have the same options as Linux. Use a common set of functions for that. Pre-parsing for log level is common to all OS's. Now the pre-scan can return an error. A bad argument give to --log-level option was given the code would keep going. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> make log_parse common to windows --- .../freebsd_gsg/freebsd_eal_parameters.rst | 27 +++++++++ lib/eal/common/eal_common_log.c | 46 ++++++++++++++++ lib/eal/common/eal_log.h | 5 ++ lib/eal/freebsd/eal.c | 55 ++++--------------- lib/eal/linux/eal.c | 46 ++-------------- lib/eal/linux/meson.build | 1 - lib/eal/{linux => unix}/eal_log.c | 11 ++++ lib/eal/unix/meson.build | 1 + lib/eal/windows/eal.c | 35 ------------ 9 files changed, 108 insertions(+), 119 deletions(-) rename lib/eal/{linux => unix}/eal_log.c (76%) diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index fba467a2ce92..9270d9fa3bfc 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -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 diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c index bd7b188ceb4a..7e2f010fa371 100644 --- a/lib/eal/common/eal_common_log.c +++ b/lib/eal/common/eal_common_log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <getopt.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -16,6 +17,8 @@ #include <rte_per_lcore.h> #include "eal_log.h" +#include "eal_internal_cfg.h" +#include "eal_options.h" #include "eal_private.h" struct rte_log_dynamic_type { @@ -223,6 +226,49 @@ log_save_level(uint32_t priority, const char *regex, const char *pattern) return -1; } + +/* Parse the all arguments looking for --log-level */ +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; + char * const old_optarg = optarg; +#ifdef RTE_EXEC_ENV_FREEBSD + const int old_optreset = optreset; + optreset = 1; +#endif + + optind = 1; + + 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* restore getopt lib */ + optind = old_optind; + optopt = old_optopt; + optarg = old_optarg; +#ifdef RTE_EXEC_ENV_FREEBSD + optreset = old_optreset; +#endif + return 0; +} + int eal_log_save_regexp(const char *regex, uint32_t level) { diff --git a/lib/eal/common/eal_log.h b/lib/eal/common/eal_log.h index c784fa604389..31dc489350f6 100644 --- a/lib/eal/common/eal_log.h +++ b/lib/eal/common/eal_log.h @@ -13,6 +13,11 @@ */ int eal_log_init(const char *id, int facility); +/* + * Scan command line args for log settings. + */ +int eal_log_level_parse(int argc, char * const argv[]); + /* * Determine where log data is written when no call to rte_openlog_stream. */ diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7008303e112a..bb9a2b1653d9 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -52,6 +52,7 @@ #include "eal_hugepages.h" #include "eal_options.h" #include "eal_memcfg.h" +#include "eal_log.h" #include "eal_trace.h" #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL) @@ -363,48 +364,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) @@ -610,7 +569,11 @@ rte_eal_init(int argc, char **argv) eal_save_args(argc, argv); /* set log level as early as possible */ - eal_log_level_parse(argc, argv); + if (eal_log_level_parse(argc, argv) < 0) { + rte_eal_init_alert("invalid log option."); + rte_errno = EINVAL; + return -1; + } if (rte_eal_cpu_init() < 0) { rte_eal_init_alert("Cannot detect lcores."); @@ -759,6 +722,12 @@ rte_eal_init(int argc, char **argv) #endif } + if (eal_log_init(getprogname(), internal_conf->syslog_facility) < 0) { + rte_eal_init_alert("Cannot init logging."); + rte_errno = ENOMEM; + return -1; + } + /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 145afafde234..c9475560d986 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { @@ -993,7 +954,12 @@ 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); + if (eal_log_level_parse(argc, argv) < 0) { + rte_eal_init_alert("invalid log option."); + rte_errno = EINVAL; + __atomic_store_n(&run_once, 0, __ATOMIC_RELAXED); + return -1; + } /* clone argv to report out later in telemetry */ eal_save_args(argc, argv); diff --git a/lib/eal/linux/meson.build b/lib/eal/linux/meson.build index 5af456db9edb..e99ebed25692 100644 --- a/lib/eal/linux/meson.build +++ b/lib/eal/linux/meson.build @@ -11,7 +11,6 @@ sources += files( 'eal_hugepage_info.c', 'eal_interrupts.c', 'eal_lcore.c', - 'eal_log.c', 'eal_memalloc.c', 'eal_memory.c', 'eal_thread.c', diff --git a/lib/eal/linux/eal_log.c b/lib/eal/unix/eal_log.c similarity index 76% rename from lib/eal/linux/eal_log.c rename to lib/eal/unix/eal_log.c index d44416fd6570..85d817c2d31e 100644 --- a/lib/eal/linux/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -9,6 +9,8 @@ #include <rte_log.h> #include "eal_log.h" +#include "eal_internal_cfg.h" +#include "eal_private.h" /* * default log function @@ -25,6 +27,15 @@ console_log_write(__rte_unused void *c, const char *buf, size_t size) /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); +#ifdef RTE_EXEC_ENV_LINUX + /* Handle glibc quirk: write function should return the number of bytes + * copied from buf, or 0 on error. (The function must not return a negative value.) + * FreeBSD expects that write function behaves like write(2). + */ + if (ret < 0) + ret = 0; +#endif + return ret; } diff --git a/lib/eal/unix/meson.build b/lib/eal/unix/meson.build index cc7d67dd321d..37d07594df29 100644 --- a/lib/eal/unix/meson.build +++ b/lib/eal/unix/meson.build @@ -6,6 +6,7 @@ sources += files( 'eal_file.c', 'eal_filesystem.c', 'eal_firmware.c', + 'eal_log.c', 'eal_unix_memory.c', 'eal_unix_thread.c', 'eal_unix_timer.c', diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 2d7a0e9ab27e..240d5b8ad3e4 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v6 2/6] eal: turn off getopt_long error message during eal_log_level 2023-06-29 15:58 ` [PATCH v6 0/6] Logging related patches Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 1/6] eal: unify logging code Stephen Hemminger @ 2023-06-29 15:58 ` Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 3/6] eal: fix help message for syslog option Stephen Hemminger ` (3 subsequent siblings) 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-29 15:58 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Keith Wiles, Dmitry Kozlyuk, Narcisa Ana Maria Vasile, Dmitry Malloy, Pallavi Kadam If DPDK application is given a bogus option, the error message would get printed twice. Once during scan for log level and again during parsing of arguments. Example: # ./build/app/dpdk-testpmd --bogus ./build/app/dpdk-testpmd: unrecognized option '--bogus' EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 ./build/app/dpdk-testpmd: unrecognized option '--bogus' Usage: ./build/app/dpdk-testpmd [options] Fix by suppressing printing error message on first pass. Signed-off-by: Keith Wiles <keith.wiles@intel.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_log.c | 3 +++ lib/eal/windows/eal.c | 1 + 2 files changed, 4 insertions(+) diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c index 7e2f010fa371..ada3ed5ebec9 100644 --- a/lib/eal/common/eal_common_log.c +++ b/lib/eal/common/eal_common_log.c @@ -235,6 +235,7 @@ eal_log_level_parse(int argc, char *const argv[]) int option_index, opt; const int old_optind = optind; const int old_optopt = optopt; + const int old_opterr = opterr; char * const old_optarg = optarg; #ifdef RTE_EXEC_ENV_FREEBSD const int old_optreset = optreset; @@ -242,6 +243,7 @@ eal_log_level_parse(int argc, char *const argv[]) #endif optind = 1; + opterr = 0; while ((opt = getopt_long(argc, argv, eal_short_options, eal_long_options, &option_index)) != EOF) { @@ -263,6 +265,7 @@ eal_log_level_parse(int argc, char *const argv[]) optind = old_optind; optopt = old_optopt; optarg = old_optarg; + opterr = old_opterr; #ifdef RTE_EXEC_ENV_FREEBSD optreset = old_optreset; #endif diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 240d5b8ad3e4..c6006c48ddef 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -108,6 +108,7 @@ eal_parse_args(int argc, char **argv) eal_get_internal_configuration(); argvopt = argv; + opterr = 1; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v6 3/6] eal: fix help message for syslog option 2023-06-29 15:58 ` [PATCH v6 0/6] Logging related patches Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 1/6] eal: unify logging code Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 2/6] eal: turn off getopt_long error message during eal_log_level Stephen Hemminger @ 2023-06-29 15:58 ` Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 4/6] eal: skip stdio on console logging Stephen Hemminger ` (2 subsequent siblings) 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-29 15:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The --syslog flag takes facility argument. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 03059336987d..005da4d12001 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2193,7 +2193,7 @@ eal_common_usage(void) " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_SYSLOG"=<facility> Set syslog facility\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v6 4/6] eal: skip stdio on console logging 2023-06-29 15:58 ` [PATCH v6 0/6] Logging related patches Stephen Hemminger ` (2 preceding siblings ...) 2023-06-29 15:58 ` [PATCH v6 3/6] eal: fix help message for syslog option Stephen Hemminger @ 2023-06-29 15:58 ` Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 5/6] eal: allow user to set default log stream before init Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 6/6] eal: add option to put timestamp on console output Stephen Hemminger 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-29 15:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger There is no need to use stdio when logging to console. Using the write system call directly avoids unnecessary copy to stdio output buffer. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/unix/eal_log.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index 85d817c2d31e..151f30eb6071 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <sys/types.h> #include <syslog.h> +#include <unistd.h> #include <rte_log.h> @@ -21,8 +22,7 @@ console_log_write(__rte_unused void *c, const char *buf, size_t size) ssize_t ret; /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); + ret = write(STDERR_FILENO, buf, size); /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v6 5/6] eal: allow user to set default log stream before init 2023-06-29 15:58 ` [PATCH v6 0/6] Logging related patches Stephen Hemminger ` (3 preceding siblings ...) 2023-06-29 15:58 ` [PATCH v6 4/6] eal: skip stdio on console logging Stephen Hemminger @ 2023-06-29 15:58 ` Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 6/6] eal: add option to put timestamp on console output Stephen Hemminger 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-29 15:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Reshma Pattan, Maryam Tahhan It is useful for application to be able to set the default log stream before call rte_eal_init(). This makes all messages go to the new default. For example, to skip using syslog; just doing rte_openlog_stream(stderr); There is no reason for helper command line applications to clutter syslog with messages. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/dumpcap/main.c | 3 +++ app/pdump/main.c | 3 +++ app/proc-info/main.c | 3 +++ lib/eal/common/eal_common_log.c | 6 ++++++ lib/eal/common/eal_log.h | 1 + lib/eal/unix/eal_log.c | 4 ++++ 6 files changed, 20 insertions(+) diff --git a/app/dumpcap/main.c b/app/dumpcap/main.c index 64294bbfb3e6..bf31eef13cf4 100644 --- a/app/dumpcap/main.c +++ b/app/dumpcap/main.c @@ -639,6 +639,9 @@ static void dpdk_init(void) eal_argv[i++] = strdup(file_prefix); } + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + if (rte_eal_init(eal_argc, eal_argv) < 0) rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n"); } diff --git a/app/pdump/main.c b/app/pdump/main.c index c94606275b28..82c67350e4ab 100644 --- a/app/pdump/main.c +++ b/app/pdump/main.c @@ -989,6 +989,9 @@ main(int argc, char **argv) argc += 2; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + diag = rte_eal_init(argc, argp); if (diag < 0) rte_panic("Cannot init EAL\n"); diff --git a/app/proc-info/main.c b/app/proc-info/main.c index 53e852a07c14..371b1f382d66 100644 --- a/app/proc-info/main.c +++ b/app/proc-info/main.c @@ -1774,6 +1774,9 @@ main(int argc, char **argv) argc += 4; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + ret = rte_eal_init(argc, argp); if (ret < 0) rte_panic("Cannot init EAL\n"); diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c index ada3ed5ebec9..827830916eb7 100644 --- a/lib/eal/common/eal_common_log.c +++ b/lib/eal/common/eal_common_log.c @@ -584,6 +584,12 @@ eal_log_set_default(FILE *default_log) #endif } +FILE * +eal_log_get_default(void) +{ + return default_log_stream; +} + /* * Called by eal_cleanup */ diff --git a/lib/eal/common/eal_log.h b/lib/eal/common/eal_log.h index 31dc489350f6..268c2a264382 100644 --- a/lib/eal/common/eal_log.h +++ b/lib/eal/common/eal_log.h @@ -22,6 +22,7 @@ int eal_log_level_parse(int argc, char * const argv[]); * Determine where log data is written when no call to rte_openlog_stream. */ void eal_log_set_default(FILE *default_log); +FILE *eal_log_get_default(void); /* * Save a log option for later. diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index 151f30eb6071..98753cb52e09 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -60,6 +60,10 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; + /* has user has already setup a log stream */ + if (eal_log_get_default()) + return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v6 6/6] eal: add option to put timestamp on console output 2023-06-29 15:58 ` [PATCH v6 0/6] Logging related patches Stephen Hemminger ` (4 preceding siblings ...) 2023-06-29 15:58 ` [PATCH v6 5/6] eal: allow user to set default log stream before init Stephen Hemminger @ 2023-06-29 15:58 ` Stephen Hemminger 5 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-06-29 15:58 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Anatoly Burakov 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. The timestamp format is chosen to look like the default Linux dmesg timestamp. The first few lines are not timestamped because the flag is stored in internal configuration which is stored in shared memory which is not setup up until a little later in startup process. Example: $ dpdk-testpmd --log-timestamp -- -i EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 EAL: Detected static linkage of DPDK EAL: Multi-process socket /var/run/dpdk/rte/mp_socket EAL: Selected IOVA mode 'VA' [ 0.112264] testpmd: No probed ethernet devices Interactive-mode selected [ 0.184573] testpmd: create a new mbuf pool <mb_pool_0>: n=163456, size=2176, socket=0 [ 0.184612] testpmd: preferred mempool ops selected: ring_mp_mc Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 9 ++++ .../freebsd_gsg/freebsd_eal_parameters.rst | 5 +++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ lib/eal/common/eal_common_options.c | 6 +++ lib/eal/common/eal_internal_cfg.h | 3 ++ lib/eal/common/eal_options.h | 2 + lib/eal/unix/eal_log.c | 43 +++++++++++++++++-- 7 files changed, 69 insertions(+), 4 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index d2b91e20750e..57637728d811 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1055,6 +1055,10 @@ 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" }; + /* run all tests also applicable to FreeBSD first */ if (launch_proc(argv0) == 0) { @@ -1162,6 +1166,11 @@ 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; + } + rmdir(hugepath_dir3); rmdir(hugepath_dir2); diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index 9270d9fa3bfc..99cff10e963c 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -45,3 +45,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f38139119..719ca6851625 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -135,3 +135,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 005da4d12001..67fe6efb4526 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -76,6 +76,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, 0, 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 }, @@ -1835,6 +1836,10 @@ eal_parse_common_option(int opt, const char *optarg, } #ifndef RTE_EXEC_ENV_WINDOWS + case OPT_LOG_TIMESTAMP_NUM: + conf->log_timestamp = 1; + break; + case OPT_TRACE_NUM: { if (eal_trace_args_save(optarg) < 0) { RTE_LOG(ERR, EAL, "invalid parameters for --" @@ -2194,6 +2199,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"=<facility> Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa79..ca502d5dd365 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -84,7 +84,10 @@ struct internal_config { /**< true if storing all pages within single files (per-page-size, * per-node) non-legacy mode only. */ + uint8_t log_timestamp; /**< add timestamp to console output */ + struct timespec log_start_time; /**< monotonic clock when started */ 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 */ diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb641284..cc9723868e3c 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index 98753cb52e09..1ee94a5ee1e6 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -4,7 +4,9 @@ #include <stdio.h> #include <sys/types.h> +#include <sys/uio.h> #include <syslog.h> +#include <time.h> #include <unistd.h> #include <rte_log.h> @@ -17,12 +19,38 @@ * default log function */ static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) +console_log_write(void *c, const char *buf, size_t size) { + const struct internal_config *internal_conf = c; ssize_t ret; - /* write on stderr */ - ret = write(STDERR_FILENO, buf, size); + /* add optional timestamp for stderr */ + if (internal_conf->log_timestamp) { + struct iovec iov[2]; + struct timespec ts; + char tbuf[64]; + + /* format up monotonic timestamp */ + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec -= internal_conf->log_start_time.tv_sec; + ts.tv_nsec -= internal_conf->log_start_time.tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000ul; + } + + /* use writev to put timestamp and buf in single operation */ + iov[0].iov_base = tbuf; + iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "[%8lu.%06lu] ", + ts.tv_sec, ts.tv_nsec / 1000u); + + /* casts are to unconstify the buf */ + iov[1].iov_base = (void *)(uintptr_t)buf; + iov[1].iov_len = size; + ret = writev(STDERR_FILENO, iov, 2); + } else { + ret = write(STDERR_FILENO, buf, size); + } /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); @@ -58,13 +86,20 @@ static cookie_io_functions_t console_log_func = { int eal_log_init(const char *id, int facility) { + struct internal_config *internal_conf = eal_get_internal_configuration(); FILE *log_stream; /* has user has already setup a log stream */ if (eal_log_get_default()) return 0; - log_stream = fopencookie(NULL, "w+", console_log_func); + if (internal_conf->process_type == RTE_PROC_PRIMARY && + internal_conf->log_timestamp) { + if (clock_gettime(CLOCK_MONOTONIC, &internal_conf->log_start_time) < 0) + return -1; + } + + log_stream = fopencookie(internal_conf, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v7 0/5] Logging timetamp and related patches 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (5 preceding siblings ...) 2023-06-29 15:58 ` [PATCH v6 0/6] Logging related patches Stephen Hemminger @ 2023-07-05 22:48 ` Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 1/5] windows: make getopt functions have const properties Stephen Hemminger ` (4 more replies) 2024-03-18 18:30 ` [PATCH v8 0/5] Logging timestamp and related patches Stephen Hemminger ` (22 subsequent siblings) 29 siblings, 5 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-07-05 22:48 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Patchset that includes: - unified code for more of log argument handling - fix for duplicate option errors - timestamp option for logging v7 - consolidate patches - fix windows to have same getopt args as Linux and FreeBSD Stephen Hemminger (5): windows: make getopt functions have const properties eal: fix help message for syslog option eal: unify logging code eal: allow user to set default log stream before init eal: add option to put timestamp on console output app/dumpcap/main.c | 3 + app/pdump/main.c | 3 + app/proc-info/main.c | 3 + app/test/test_eal_flags.c | 9 ++ .../freebsd_gsg/freebsd_eal_parameters.rst | 32 +++++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 + lib/eal/common/eal_common_log.c | 55 +++++++++ lib/eal/common/eal_common_options.c | 8 +- lib/eal/common/eal_internal_cfg.h | 3 + lib/eal/common/eal_log.h | 6 + lib/eal/common/eal_options.h | 2 + lib/eal/freebsd/eal.c | 55 ++------- lib/eal/linux/eal.c | 46 +------- lib/eal/linux/eal_log.c | 61 ---------- lib/eal/linux/meson.build | 1 - lib/eal/unix/eal_log.c | 111 ++++++++++++++++++ lib/eal/unix/meson.build | 1 + lib/eal/windows/eal.c | 36 +----- lib/eal/windows/getopt.c | 23 ++-- lib/eal/windows/include/getopt.h | 8 +- 20 files changed, 275 insertions(+), 196 deletions(-) delete mode 100644 lib/eal/linux/eal_log.c create mode 100644 lib/eal/unix/eal_log.c -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v7 1/5] windows: make getopt functions have const properties 2023-07-05 22:48 ` [PATCH v7 0/5] Logging timetamp and related patches Stephen Hemminger @ 2023-07-05 22:48 ` Stephen Hemminger 2023-07-10 21:10 ` Tyler Retzlaff 2023-07-05 22:48 ` [PATCH v7 2/5] eal: fix help message for syslog option Stephen Hemminger ` (3 subsequent siblings) 4 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2023-07-05 22:48 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Dmitry Kozlyuk, Narcisa Ana Maria Vasile, Dmitry Malloy, Pallavi Kadam This aligns getopt, getopt_long, etc to have the same const attributes as Linux and FreeBSD. The changes are derived from the FreeBSD version of getopt_long. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c2318..50ff71b9300d 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b17..e4cf6873cb0c 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v7 1/5] windows: make getopt functions have const properties 2023-07-05 22:48 ` [PATCH v7 1/5] windows: make getopt functions have const properties Stephen Hemminger @ 2023-07-10 21:10 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2023-07-10 21:10 UTC (permalink / raw) To: Stephen Hemminger Cc: dev, Dmitry Kozlyuk, Narcisa Ana Maria Vasile, Dmitry Malloy, Pallavi Kadam On Wed, Jul 05, 2023 at 03:48:01PM -0700, Stephen Hemminger wrote: > This aligns getopt, getopt_long, etc to have the same const > attributes as Linux and FreeBSD. The changes are derived from > the FreeBSD version of getopt_long. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v7 2/5] eal: fix help message for syslog option 2023-07-05 22:48 ` [PATCH v7 0/5] Logging timetamp and related patches Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 1/5] windows: make getopt functions have const properties Stephen Hemminger @ 2023-07-05 22:48 ` Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 3/5] eal: unify logging code Stephen Hemminger ` (2 subsequent siblings) 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-07-05 22:48 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The --syslog flag takes facility argument. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 03059336987d..005da4d12001 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2193,7 +2193,7 @@ eal_common_usage(void) " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_SYSLOG"=<facility> Set syslog facility\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v7 3/5] eal: unify logging code 2023-07-05 22:48 ` [PATCH v7 0/5] Logging timetamp and related patches Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 1/5] windows: make getopt functions have const properties Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 2/5] eal: fix help message for syslog option Stephen Hemminger @ 2023-07-05 22:48 ` Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 4/5] eal: allow user to set default log stream before init Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 5/5] eal: add option to put timestamp on console output Stephen Hemminger 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-07-05 22:48 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Narcisa Ana Maria Vasile, Dmitry Malloy, Pallavi Kadam FreeBSD logging code was not using syslog and did not have the same options as Linux. Use a common set of functions for that. Pre-parsing for log level is common to all OS's. Now the pre-scan can return an error. A bad argument give to --log-level option was given the code would keep going. Use opterr to fix duplicate error message on bad option. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- .../freebsd_gsg/freebsd_eal_parameters.rst | 27 +++++++++ lib/eal/common/eal_common_log.c | 49 +++++++++++++++++ lib/eal/common/eal_log.h | 5 ++ lib/eal/freebsd/eal.c | 55 ++++--------------- lib/eal/linux/eal.c | 46 ++-------------- lib/eal/linux/meson.build | 1 - lib/eal/{linux => unix}/eal_log.c | 11 ++++ lib/eal/unix/meson.build | 1 + lib/eal/windows/eal.c | 36 +----------- 9 files changed, 112 insertions(+), 119 deletions(-) rename lib/eal/{linux => unix}/eal_log.c (76%) diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index fba467a2ce92..9270d9fa3bfc 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -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 diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c index bd7b188ceb4a..1b2080e8ef04 100644 --- a/lib/eal/common/eal_common_log.c +++ b/lib/eal/common/eal_common_log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <getopt.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -16,6 +17,8 @@ #include <rte_per_lcore.h> #include "eal_log.h" +#include "eal_internal_cfg.h" +#include "eal_options.h" #include "eal_private.h" struct rte_log_dynamic_type { @@ -223,6 +226,52 @@ log_save_level(uint32_t priority, const char *regex, const char *pattern) return -1; } + +/* Parse the all arguments looking for --log-level */ +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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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_log_save_regexp(const char *regex, uint32_t level) { diff --git a/lib/eal/common/eal_log.h b/lib/eal/common/eal_log.h index c784fa604389..31dc489350f6 100644 --- a/lib/eal/common/eal_log.h +++ b/lib/eal/common/eal_log.h @@ -13,6 +13,11 @@ */ int eal_log_init(const char *id, int facility); +/* + * Scan command line args for log settings. + */ +int eal_log_level_parse(int argc, char * const argv[]); + /* * Determine where log data is written when no call to rte_openlog_stream. */ diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7008303e112a..bb9a2b1653d9 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -52,6 +52,7 @@ #include "eal_hugepages.h" #include "eal_options.h" #include "eal_memcfg.h" +#include "eal_log.h" #include "eal_trace.h" #define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL) @@ -363,48 +364,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) @@ -610,7 +569,11 @@ rte_eal_init(int argc, char **argv) eal_save_args(argc, argv); /* set log level as early as possible */ - eal_log_level_parse(argc, argv); + if (eal_log_level_parse(argc, argv) < 0) { + rte_eal_init_alert("invalid log option."); + rte_errno = EINVAL; + return -1; + } if (rte_eal_cpu_init() < 0) { rte_eal_init_alert("Cannot detect lcores."); @@ -759,6 +722,12 @@ rte_eal_init(int argc, char **argv) #endif } + if (eal_log_init(getprogname(), internal_conf->syslog_facility) < 0) { + rte_eal_init_alert("Cannot init logging."); + rte_errno = ENOMEM; + return -1; + } + /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 145afafde234..c9475560d986 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { @@ -993,7 +954,12 @@ 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); + if (eal_log_level_parse(argc, argv) < 0) { + rte_eal_init_alert("invalid log option."); + rte_errno = EINVAL; + __atomic_store_n(&run_once, 0, __ATOMIC_RELAXED); + return -1; + } /* clone argv to report out later in telemetry */ eal_save_args(argc, argv); diff --git a/lib/eal/linux/meson.build b/lib/eal/linux/meson.build index 5af456db9edb..e99ebed25692 100644 --- a/lib/eal/linux/meson.build +++ b/lib/eal/linux/meson.build @@ -11,7 +11,6 @@ sources += files( 'eal_hugepage_info.c', 'eal_interrupts.c', 'eal_lcore.c', - 'eal_log.c', 'eal_memalloc.c', 'eal_memory.c', 'eal_thread.c', diff --git a/lib/eal/linux/eal_log.c b/lib/eal/unix/eal_log.c similarity index 76% rename from lib/eal/linux/eal_log.c rename to lib/eal/unix/eal_log.c index d44416fd6570..85d817c2d31e 100644 --- a/lib/eal/linux/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -9,6 +9,8 @@ #include <rte_log.h> #include "eal_log.h" +#include "eal_internal_cfg.h" +#include "eal_private.h" /* * default log function @@ -25,6 +27,15 @@ console_log_write(__rte_unused void *c, const char *buf, size_t size) /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); +#ifdef RTE_EXEC_ENV_LINUX + /* Handle glibc quirk: write function should return the number of bytes + * copied from buf, or 0 on error. (The function must not return a negative value.) + * FreeBSD expects that write function behaves like write(2). + */ + if (ret < 0) + ret = 0; +#endif + return ret; } diff --git a/lib/eal/unix/meson.build b/lib/eal/unix/meson.build index cc7d67dd321d..37d07594df29 100644 --- a/lib/eal/unix/meson.build +++ b/lib/eal/unix/meson.build @@ -6,6 +6,7 @@ sources += files( 'eal_file.c', 'eal_filesystem.c', 'eal_firmware.c', + 'eal_log.c', 'eal_unix_memory.c', 'eal_unix_thread.c', 'eal_unix_timer.c', diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 2d7a0e9ab27e..c6006c48ddef 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) @@ -143,6 +108,7 @@ eal_parse_args(int argc, char **argv) eal_get_internal_configuration(); argvopt = argv; + opterr = 1; while ((opt = getopt_long(argc, argvopt, eal_short_options, eal_long_options, &option_index)) != EOF) { -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v7 4/5] eal: allow user to set default log stream before init 2023-07-05 22:48 ` [PATCH v7 0/5] Logging timetamp and related patches Stephen Hemminger ` (2 preceding siblings ...) 2023-07-05 22:48 ` [PATCH v7 3/5] eal: unify logging code Stephen Hemminger @ 2023-07-05 22:48 ` Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 5/5] eal: add option to put timestamp on console output Stephen Hemminger 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-07-05 22:48 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Reshma Pattan, Maryam Tahhan It is useful for application to be able to set the default log stream before call rte_eal_init(). This makes all messages go to the new default. For example, to skip using syslog; just doing rte_openlog_stream(stderr); There is no reason for helper command line applications to clutter syslog with messages. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/dumpcap/main.c | 3 +++ app/pdump/main.c | 3 +++ app/proc-info/main.c | 3 +++ lib/eal/common/eal_common_log.c | 6 ++++++ lib/eal/common/eal_log.h | 1 + lib/eal/unix/eal_log.c | 4 ++++ 6 files changed, 20 insertions(+) diff --git a/app/dumpcap/main.c b/app/dumpcap/main.c index 64294bbfb3e6..bf31eef13cf4 100644 --- a/app/dumpcap/main.c +++ b/app/dumpcap/main.c @@ -639,6 +639,9 @@ static void dpdk_init(void) eal_argv[i++] = strdup(file_prefix); } + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + if (rte_eal_init(eal_argc, eal_argv) < 0) rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n"); } diff --git a/app/pdump/main.c b/app/pdump/main.c index c94606275b28..82c67350e4ab 100644 --- a/app/pdump/main.c +++ b/app/pdump/main.c @@ -989,6 +989,9 @@ main(int argc, char **argv) argc += 2; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + diag = rte_eal_init(argc, argp); if (diag < 0) rte_panic("Cannot init EAL\n"); diff --git a/app/proc-info/main.c b/app/proc-info/main.c index 53e852a07c14..371b1f382d66 100644 --- a/app/proc-info/main.c +++ b/app/proc-info/main.c @@ -1774,6 +1774,9 @@ main(int argc, char **argv) argc += 4; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + ret = rte_eal_init(argc, argp); if (ret < 0) rte_panic("Cannot init EAL\n"); diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c index 1b2080e8ef04..1533ee871f47 100644 --- a/lib/eal/common/eal_common_log.c +++ b/lib/eal/common/eal_common_log.c @@ -584,6 +584,12 @@ eal_log_set_default(FILE *default_log) #endif } +FILE * +eal_log_get_default(void) +{ + return default_log_stream; +} + /* * Called by eal_cleanup */ diff --git a/lib/eal/common/eal_log.h b/lib/eal/common/eal_log.h index 31dc489350f6..268c2a264382 100644 --- a/lib/eal/common/eal_log.h +++ b/lib/eal/common/eal_log.h @@ -22,6 +22,7 @@ int eal_log_level_parse(int argc, char * const argv[]); * Determine where log data is written when no call to rte_openlog_stream. */ void eal_log_set_default(FILE *default_log); +FILE *eal_log_get_default(void); /* * Save a log option for later. diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index 85d817c2d31e..e66bcc68d07f 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -60,6 +60,10 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; + /* has user has already setup a log stream */ + if (eal_log_get_default()) + return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v7 5/5] eal: add option to put timestamp on console output 2023-07-05 22:48 ` [PATCH v7 0/5] Logging timetamp and related patches Stephen Hemminger ` (3 preceding siblings ...) 2023-07-05 22:48 ` [PATCH v7 4/5] eal: allow user to set default log stream before init Stephen Hemminger @ 2023-07-05 22:48 ` Stephen Hemminger 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2023-07-05 22:48 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson, Anatoly Burakov 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. The timestamp format is chosen to look like the default Linux dmesg timestamp. The first few lines are not timestamped because the flag is stored in internal configuration which is stored in shared memory which is not setup up until a little later in startup process. This logging skips the unnecessary step of going through stdio, which makes it more robust against being called in interrupt handlers etc. Example: $ dpdk-testpmd --log-timestamp -- -i EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 EAL: Detected static linkage of DPDK EAL: Multi-process socket /var/run/dpdk/rte/mp_socket EAL: Selected IOVA mode 'VA' [ 0.112264] testpmd: No probed ethernet devices Interactive-mode selected [ 0.184573] testpmd: create a new mbuf pool <mb_pool_0>: n=163456, size=2176, socket=0 [ 0.184612] testpmd: preferred mempool ops selected: ring_mp_mc Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 9 ++++ .../freebsd_gsg/freebsd_eal_parameters.rst | 5 +++ doc/guides/linux_gsg/linux_eal_parameters.rst | 5 +++ lib/eal/common/eal_common_options.c | 6 +++ lib/eal/common/eal_internal_cfg.h | 3 ++ lib/eal/common/eal_options.h | 2 + lib/eal/unix/eal_log.c | 45 ++++++++++++++++--- 7 files changed, 70 insertions(+), 5 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index d2b91e20750e..57637728d811 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1055,6 +1055,10 @@ 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" }; + /* run all tests also applicable to FreeBSD first */ if (launch_proc(argv0) == 0) { @@ -1162,6 +1166,11 @@ 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; + } + rmdir(hugepath_dir3); rmdir(hugepath_dir2); diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index 9270d9fa3bfc..99cff10e963c 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -45,3 +45,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f38139119..719ca6851625 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -135,3 +135,8 @@ Other options local5 local6 local7 + +* ``--log-timestamp`` + + Add a timestamp of seconds and microseconds to each log message + written to standard output. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 005da4d12001..67fe6efb4526 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -76,6 +76,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, 0, 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 }, @@ -1835,6 +1836,10 @@ eal_parse_common_option(int opt, const char *optarg, } #ifndef RTE_EXEC_ENV_WINDOWS + case OPT_LOG_TIMESTAMP_NUM: + conf->log_timestamp = 1; + break; + case OPT_TRACE_NUM: { if (eal_trace_args_save(optarg) < 0) { RTE_LOG(ERR, EAL, "invalid parameters for --" @@ -2194,6 +2199,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"=<facility> Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa79..ca502d5dd365 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -84,7 +84,10 @@ struct internal_config { /**< true if storing all pages within single files (per-page-size, * per-node) non-legacy mode only. */ + uint8_t log_timestamp; /**< add timestamp to console output */ + struct timespec log_start_time; /**< monotonic clock when started */ 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 */ diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb641284..cc9723868e3c 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/unix/eal_log.c b/lib/eal/unix/eal_log.c index e66bcc68d07f..1ee94a5ee1e6 100644 --- a/lib/eal/unix/eal_log.c +++ b/lib/eal/unix/eal_log.c @@ -4,7 +4,10 @@ #include <stdio.h> #include <sys/types.h> +#include <sys/uio.h> #include <syslog.h> +#include <time.h> +#include <unistd.h> #include <rte_log.h> @@ -16,13 +19,38 @@ * default log function */ static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) +console_log_write(void *c, const char *buf, size_t size) { + const struct internal_config *internal_conf = c; ssize_t ret; - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); + /* add optional timestamp for stderr */ + if (internal_conf->log_timestamp) { + struct iovec iov[2]; + struct timespec ts; + char tbuf[64]; + + /* format up monotonic timestamp */ + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec -= internal_conf->log_start_time.tv_sec; + ts.tv_nsec -= internal_conf->log_start_time.tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000ul; + } + + /* use writev to put timestamp and buf in single operation */ + iov[0].iov_base = tbuf; + iov[0].iov_len = snprintf(tbuf, sizeof(tbuf), "[%8lu.%06lu] ", + ts.tv_sec, ts.tv_nsec / 1000u); + + /* casts are to unconstify the buf */ + iov[1].iov_base = (void *)(uintptr_t)buf; + iov[1].iov_len = size; + ret = writev(STDERR_FILENO, iov, 2); + } else { + ret = write(STDERR_FILENO, buf, size); + } /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); @@ -58,13 +86,20 @@ static cookie_io_functions_t console_log_func = { int eal_log_init(const char *id, int facility) { + struct internal_config *internal_conf = eal_get_internal_configuration(); FILE *log_stream; /* has user has already setup a log stream */ if (eal_log_get_default()) return 0; - log_stream = fopencookie(NULL, "w+", console_log_func); + if (internal_conf->process_type == RTE_PROC_PRIMARY && + internal_conf->log_timestamp) { + if (clock_gettime(CLOCK_MONOTONIC, &internal_conf->log_start_time) < 0) + return -1; + } + + log_stream = fopencookie(internal_conf, "w+", console_log_func); if (log_stream == NULL) return -1; -- 2.39.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v8 0/5] Logging timestamp and related patches 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (6 preceding siblings ...) 2023-07-05 22:48 ` [PATCH v7 0/5] Logging timetamp and related patches Stephen Hemminger @ 2024-03-18 18:30 ` Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 1/5] log: unify logging code Stephen Hemminger ` (4 more replies) 2024-03-18 22:02 ` [PATCH v9 0/5] Logging unification and timestamp Stephen Hemminger ` (21 subsequent siblings) 29 siblings, 5 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 18:30 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). This is update to earlier patch set. v8 - rebase to current code base where logging in in lib/log use stdio for log timestamp initialization changes (setup log earlier) Stephen Hemminger (5): log: unify logging code eal: make eal_log_level_parse common eal: allow user to set default log stream before init eal: add option to put timestamp on console output eal: initialize logging before plugins app/dumpcap/main.c | 3 + app/pdump/main.c | 3 + app/proc-info/main.c | 3 + app/test/test_eal_flags.c | 9 +++ doc/guides/linux_gsg/linux_eal_parameters.rst | 27 --------- doc/guides/prog_guide/log_lib.rst | 28 +++++++++- lib/eal/common/eal_common_options.c | 56 ++++++++++++++++++- lib/eal/common/eal_options.h | 3 + lib/eal/freebsd/eal.c | 50 +++-------------- lib/eal/linux/eal.c | 55 +++--------------- lib/eal/unix/eal_unix_log.c | 0 lib/eal/windows/eal.c | 35 ------------ lib/log/log.c | 6 ++ lib/log/log_freebsd.c | 12 ---- lib/log/log_internal.h | 11 ++++ lib/log/{log_linux.c => log_unix.c} | 36 +++++++++++- lib/log/log_windows.c | 6 ++ lib/log/meson.build | 12 ++-- lib/log/version.map | 2 + 19 files changed, 184 insertions(+), 173 deletions(-) create mode 100644 lib/eal/unix/eal_unix_log.c delete mode 100644 lib/log/log_freebsd.c rename lib/log/{log_linux.c => log_unix.c} (58%) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v8 1/5] log: unify logging code 2024-03-18 18:30 ` [PATCH v8 0/5] Logging timestamp and related patches Stephen Hemminger @ 2024-03-18 18:30 ` Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 2/5] eal: make eal_log_level_parse common Stephen Hemminger ` (3 subsequent siblings) 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 18:30 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger FreeBSD and Linux logging code can use common code. This also fixes FreeBSD not using syslog. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------------------- doc/guides/prog_guide/log_lib.rst | 18 +++++++++++-- lib/eal/freebsd/eal.c | 8 ++++++ lib/log/log_freebsd.c | 12 --------- lib/log/{log_linux.c => log_unix.c} | 0 lib/log/meson.build | 12 ++++++--- 6 files changed, 32 insertions(+), 45 deletions(-) delete mode 100644 lib/log/log_freebsd.c rename lib/log/{log_linux.c => log_unix.c} (100%) diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f38139119..d86f94d8a85d 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2c8..aacb36c36ce0 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -5,8 +5,8 @@ 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. +By default, in a Linux (or FreeBSD) application, logs are sent to syslog and also to the console. +In 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. Log Levels @@ -29,6 +29,7 @@ will be emitted by the application to the log output. That level can be configured either by the application calling the relevant APIs from the logging library, or by the user passing the ``--log-level`` parameter to the EAL via the application. + Setting Global Log Level ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -59,6 +60,19 @@ 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. + +Setting syslog facility +~~~~~~~~~~~~~~~~~~~~~~~ + +On Linux and FreeBSD, where syslog is used a ``facility`` argument can be +used to specify what type of program is logging. +The default facility is ``daemon`` but it can be overridden +by the ``--syslog`` EAL parameter. See ``syslog.3`` man page for full values. +For example:: + + /path/to/app --syslog local0 + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e967..004b8fad2db3 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -760,6 +760,14 @@ 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; + } + /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 698d3c542337..000000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -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; -} diff --git a/lib/log/log_linux.c b/lib/log/log_unix.c similarity index 100% rename from lib/log/log_linux.c rename to lib/log/log_unix.c diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f77..60516a0b2a2d 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,12 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') + +if is_windows + sources += files('log_windows.c') +else + sources += files('log_unix.c') +endif + headers = files('rte_log.h') -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v8 2/5] eal: make eal_log_level_parse common 2024-03-18 18:30 ` [PATCH v8 0/5] Logging timestamp and related patches Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 1/5] log: unify logging code Stephen Hemminger @ 2024-03-18 18:30 ` Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 3/5] eal: allow user to set default log stream before init Stephen Hemminger ` (2 subsequent siblings) 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 18:30 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f0793964..7310d10dfd78 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out) return -1; } +/* Parse the all arguments looking for --log-level */ +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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb641284..f3f2e104f6d7 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 004b8fad2db3..b4f8d68b0a65 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f6236..bffeb1f34eb9 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462dd8..85171b27687e 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v8 3/5] eal: allow user to set default log stream before init 2024-03-18 18:30 ` [PATCH v8 0/5] Logging timestamp and related patches Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 1/5] log: unify logging code Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 2/5] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-18 18:30 ` Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 4/5] eal: add option to put timestamp on console output Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 5/5] eal: initialize logging before plugins Stephen Hemminger 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 18:30 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger It is useful for application to be able to set the default log stream before call rte_eal_init(). This makes all messages go to the new default. For example, to skip using syslog; just doing rte_openlog_stream(stderr); There is no reason for helper command line applications to clutter syslog with messages. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/dumpcap/main.c | 3 +++ app/pdump/main.c | 3 +++ app/proc-info/main.c | 3 +++ lib/log/log.c | 6 ++++++ lib/log/log_internal.h | 2 ++ lib/log/log_unix.c | 4 ++++ lib/log/version.map | 1 + 7 files changed, 22 insertions(+) diff --git a/app/dumpcap/main.c b/app/dumpcap/main.c index cc0f66b2bc61..27934ca7e688 100644 --- a/app/dumpcap/main.c +++ b/app/dumpcap/main.c @@ -633,6 +633,9 @@ static void dpdk_init(void) rte_panic("No memory\n"); } + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + if (rte_eal_init(eal_argc, eal_argv) < 0) rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n"); } diff --git a/app/pdump/main.c b/app/pdump/main.c index a9205e130bb1..7b9ba68b1a14 100644 --- a/app/pdump/main.c +++ b/app/pdump/main.c @@ -995,6 +995,9 @@ main(int argc, char **argv) argc += 2; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + diag = rte_eal_init(argc, argp); if (diag < 0) rte_panic("Cannot init EAL\n"); diff --git a/app/proc-info/main.c b/app/proc-info/main.c index b672aaefbe99..24ee52c4ac7a 100644 --- a/app/proc-info/main.c +++ b/app/proc-info/main.c @@ -2149,6 +2149,9 @@ main(int argc, char **argv) argc += 4; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + ret = rte_eal_init(argc, argp); if (ret < 0) rte_panic("Cannot init EAL\n"); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94cc..4cc944305057 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -519,6 +519,12 @@ eal_log_set_default(FILE *default_log) #endif } +FILE * +eal_log_get_default(void) +{ + return default_log_stream; +} + /* * Called by eal_cleanup */ diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1ba..c77e687e28bc 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -21,6 +21,8 @@ int eal_log_init(const char *id, int facility); */ __rte_internal void eal_log_set_default(FILE *default_log); +__rte_internal +FILE *eal_log_get_default(void); /* * Save a log option for later. diff --git a/lib/log/log_unix.c b/lib/log/log_unix.c index 2dfb0c974b1d..a415bae5774d 100644 --- a/lib/log/log_unix.c +++ b/lib/log/log_unix.c @@ -49,6 +49,10 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; + /* skip if user has already setup a log stream */ + if (eal_log_get_default()) + return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831aff..6ecc656d1d65 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_get_default; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v8 4/5] eal: add option to put timestamp on console output 2024-03-18 18:30 ` [PATCH v8 0/5] Logging timestamp and related patches Stephen Hemminger ` (2 preceding siblings ...) 2024-03-18 18:30 ` [PATCH v8 3/5] eal: allow user to set default log stream before init Stephen Hemminger @ 2024-03-18 18:30 ` Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 5/5] eal: initialize logging before plugins Stephen Hemminger 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 18:30 UTC (permalink / raw) To: dev; +Cc: 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. The timestamp format is chosen to look like the default Linux dmesg timestamp. The first few lines are not timestamped because the flag is stored in internal configuration which is stored in shared memory which is not setup up until a little later in startup process. This logging skips the unnecessary step of going through stdio, which makes it more robust against being called in interrupt handlers etc. Example: $ dpdk-testpmd --log-timestamp -- -i EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 EAL: Detected static linkage of DPDK EAL: Multi-process socket /var/run/dpdk/rte/mp_socket EAL: Selected IOVA mode 'VA' [ 0.112264] testpmd: No probed ethernet devices Interactive-mode selected [ 0.184573] testpmd: create a new mbuf pool <mb_pool_0>: n=163456, size=2176, socket=0 [ 0.184612] testpmd: preferred mempool ops selected: ring_mp_mc Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 9 ++++++++ doc/guides/prog_guide/log_lib.rst | 10 +++++++++ lib/eal/common/eal_common_options.c | 10 +++++++-- lib/eal/common/eal_options.h | 2 ++ lib/log/log_internal.h | 9 ++++++++ lib/log/log_unix.c | 32 +++++++++++++++++++++++++++-- lib/log/log_windows.c | 6 ++++++ lib/log/version.map | 1 + 8 files changed, 75 insertions(+), 4 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b0675730..07a038fb6051 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1055,6 +1055,10 @@ 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" }; + /* run all tests also applicable to FreeBSD first */ if (launch_proc(argv0) == 0) { @@ -1162,6 +1166,11 @@ 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; + } + rmdir(hugepath_dir3); rmdir(hugepath_dir2); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index aacb36c36ce0..1d6b2e3cea5d 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -73,6 +73,16 @@ For example:: /path/to/app --syslog local0 +Console timestamp +~~~~~~~~~~~~~~~~~ + +On Linux and FreeBSD, 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 + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 7310d10dfd78..9bc95433d27c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -77,6 +77,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, 0, 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 }, @@ -1663,6 +1664,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1890,7 +1892,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 --" @@ -1898,7 +1900,10 @@ eal_parse_common_option(int opt, const char *optarg, return -1; } break; - } + + case OPT_LOG_TIMESTAMP_NUM: + eal_log_enable_timestamp(); + break; #ifndef RTE_EXEC_ENV_WINDOWS case OPT_TRACE_NUM: { @@ -2261,6 +2266,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6d7..e24c9eca53ca 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index c77e687e28bc..1af27fe8f9d3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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> @@ -44,4 +46,11 @@ const char *eal_log_level2str(uint32_t level); __rte_internal void rte_eal_log_cleanup(void); +/* + * Add timestamp to console logs + */ +__rte_internal +void eal_log_enable_timestamp(void); + + #endif /* LOG_INTERNAL_H */ diff --git a/lib/log/log_unix.c b/lib/log/log_unix.c index a415bae5774d..71ce366b6825 100644 --- a/lib/log/log_unix.c +++ b/lib/log/log_unix.c @@ -2,24 +2,52 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <sys/types.h> +#include <sys/uio.h> #include <syslog.h> +#include <time.h> +#include <unistd.h> #include <rte_log.h> #include "log_internal.h" +static bool timestamp_enabled; +static struct timespec log_started; + +void +eal_log_enable_timestamp(void) +{ + timestamp_enabled = true; + clock_gettime(CLOCK_MONOTONIC, &log_started); +} + /* * default log function */ static ssize_t console_log_write(__rte_unused void *c, const char *buf, size_t size) { + struct timespec ts; ssize_t ret; - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); + if (timestamp_enabled) { + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec -= log_started.tv_sec; + ts.tv_nsec -= log_started.tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000ul; + } + + ret = fprintf(stderr, "[%8lu.%06lu] %.*s", + ts.tv_sec, ts.tv_nsec / 1000u, + (int) size, buf); + } else { + ret = fwrite(buf, 1, size, stderr); + } fflush(stderr); /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a08895501e..0c471bfb15f6 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,6 +6,12 @@ #include <rte_log.h> #include "log_internal.h" +void +eal_log_enable_timestamp(void) +{ + /* not implemented */ +} + /* set the log to default function, called during eal init process. */ int eal_log_init(__rte_unused const char *id, __rte_unused int facility) diff --git a/lib/log/version.map b/lib/log/version.map index 6ecc656d1d65..32c555f29e79 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_enable_timestamp; eal_log_get_default; eal_log_init; eal_log_level2str; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v8 5/5] eal: initialize logging before plugins 2024-03-18 18:30 ` [PATCH v8 0/5] Logging timestamp and related patches Stephen Hemminger ` (3 preceding siblings ...) 2024-03-18 18:30 ` [PATCH v8 4/5] eal: add option to put timestamp on console output Stephen Hemminger @ 2024-03-18 18:30 ` Stephen Hemminger 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 18:30 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Want to make sure that as many log messages as possible get added with the real log stream. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 16 ++++++++-------- lib/eal/linux/eal.c | 16 ++++++++-------- lib/eal/unix/eal_unix_log.c | 0 3 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 lib/eal/unix/eal_unix_log.c diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index b4f8d68b0a65..e4f00f31fbdd 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -592,6 +592,14 @@ rte_eal_init(int argc, char **argv) internal_conf->in_memory = false; } + 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; + } + if (eal_plugins_init() < 0) { rte_eal_init_alert("Cannot init plugins"); rte_errno = EINVAL; @@ -718,14 +726,6 @@ 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; - } - /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34eb9..e24f24b1b0ce 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -973,6 +973,14 @@ rte_eal_init(int argc, char **argv) return -1; } + 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; + } + if (eal_plugins_init() < 0) { rte_eal_init_alert("Cannot init plugins"); rte_errno = EINVAL; @@ -1107,14 +1115,6 @@ 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; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/unix/eal_unix_log.c b/lib/eal/unix/eal_unix_log.c new file mode 100644 index 000000000000..e69de29bb2d1 -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v9 0/5] Logging unification and timestamp 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (7 preceding siblings ...) 2024-03-18 18:30 ` [PATCH v8 0/5] Logging timestamp and related patches Stephen Hemminger @ 2024-03-18 22:02 ` Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 1/5] log: unify logging code Stephen Hemminger ` (4 more replies) 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger ` (20 subsequent siblings) 29 siblings, 5 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 22:02 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). This is update to earlier patch set. v9 - reorder patches and fix FreeBSD build v8 - rebase to current code base where logging in in lib/log use stdio for log timestamp initialization changes (setup log earlier) Stephen Hemminger (5): log: unify logging code eal: make eal_log_level_parse common eal: initialize logging before plugins eal: allow user to set default log stream before init eal: add option to put timestamp on console output app/dumpcap/main.c | 3 + app/pdump/main.c | 3 + app/proc-info/main.c | 3 + app/test/test_eal_flags.c | 9 +++ doc/guides/linux_gsg/linux_eal_parameters.rst | 27 --------- doc/guides/prog_guide/log_lib.rst | 28 +++++++++- lib/eal/common/eal_common_options.c | 56 ++++++++++++++++++- lib/eal/common/eal_options.h | 3 + lib/eal/freebsd/eal.c | 50 +++-------------- lib/eal/linux/eal.c | 55 +++--------------- lib/eal/unix/eal_unix_log.c | 0 lib/eal/windows/eal.c | 35 ------------ lib/log/log.c | 6 ++ lib/log/log_freebsd.c | 12 ---- lib/log/log_internal.h | 11 ++++ lib/log/{log_linux.c => log_unix.c} | 36 +++++++++++- lib/log/log_windows.c | 6 ++ lib/log/meson.build | 12 ++-- lib/log/version.map | 2 + 19 files changed, 184 insertions(+), 173 deletions(-) create mode 100644 lib/eal/unix/eal_unix_log.c delete mode 100644 lib/log/log_freebsd.c rename lib/log/{log_linux.c => log_unix.c} (58%) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v9 1/5] log: unify logging code 2024-03-18 22:02 ` [PATCH v9 0/5] Logging unification and timestamp Stephen Hemminger @ 2024-03-18 22:02 ` Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 2/5] eal: make eal_log_level_parse common Stephen Hemminger ` (3 subsequent siblings) 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 22:02 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger FreeBSD and Linux logging code can use common code. This also fixes FreeBSD not using syslog. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------------------- doc/guides/prog_guide/log_lib.rst | 18 +++++++++++-- lib/eal/freebsd/eal.c | 8 ++++++ lib/log/log_freebsd.c | 12 --------- lib/log/{log_linux.c => log_unix.c} | 0 lib/log/meson.build | 12 ++++++--- 6 files changed, 32 insertions(+), 45 deletions(-) delete mode 100644 lib/log/log_freebsd.c rename lib/log/{log_linux.c => log_unix.c} (100%) diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f38139119..d86f94d8a85d 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2c8..aacb36c36ce0 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -5,8 +5,8 @@ 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. +By default, in a Linux (or FreeBSD) application, logs are sent to syslog and also to the console. +In 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. Log Levels @@ -29,6 +29,7 @@ will be emitted by the application to the log output. That level can be configured either by the application calling the relevant APIs from the logging library, or by the user passing the ``--log-level`` parameter to the EAL via the application. + Setting Global Log Level ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -59,6 +60,19 @@ 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. + +Setting syslog facility +~~~~~~~~~~~~~~~~~~~~~~~ + +On Linux and FreeBSD, where syslog is used a ``facility`` argument can be +used to specify what type of program is logging. +The default facility is ``daemon`` but it can be overridden +by the ``--syslog`` EAL parameter. See ``syslog.3`` man page for full values. +For example:: + + /path/to/app --syslog local0 + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e967..a57ee8406f0c 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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) @@ -760,6 +761,13 @@ rte_eal_init(int argc, char **argv) #endif } + if (eal_log_init(getprogname(), 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; + } + /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 698d3c542337..000000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -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; -} diff --git a/lib/log/log_linux.c b/lib/log/log_unix.c similarity index 100% rename from lib/log/log_linux.c rename to lib/log/log_unix.c diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f77..60516a0b2a2d 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,12 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') + +if is_windows + sources += files('log_windows.c') +else + sources += files('log_unix.c') +endif + headers = files('rte_log.h') -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v9 2/5] eal: make eal_log_level_parse common 2024-03-18 22:02 ` [PATCH v9 0/5] Logging unification and timestamp Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 1/5] log: unify logging code Stephen Hemminger @ 2024-03-18 22:02 ` Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 3/5] eal: initialize logging before plugins Stephen Hemminger ` (2 subsequent siblings) 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 22:02 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f0793964..7310d10dfd78 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out) return -1; } +/* Parse the all arguments looking for --log-level */ +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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb641284..f3f2e104f6d7 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a57ee8406f0c..94927472edfe 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -364,48 +364,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f6236..bffeb1f34eb9 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462dd8..85171b27687e 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v9 3/5] eal: initialize logging before plugins 2024-03-18 22:02 ` [PATCH v9 0/5] Logging unification and timestamp Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 1/5] log: unify logging code Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 2/5] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-18 22:02 ` Stephen Hemminger 2024-03-18 22:03 ` [PATCH v9 4/5] eal: allow user to set default log stream before init Stephen Hemminger 2024-03-18 22:03 ` [PATCH v9 5/5] eal: add option to put timestamp on console output Stephen Hemminger 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 22:02 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Want to make sure that as many log messages as possible get added with the real log stream. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 14 +++++++------- lib/eal/linux/eal.c | 16 ++++++++-------- lib/eal/unix/eal_unix_log.c | 0 3 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 lib/eal/unix/eal_unix_log.c diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 94927472edfe..6f0080c4d8c6 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -593,6 +593,13 @@ rte_eal_init(int argc, char **argv) internal_conf->in_memory = false; } + if (eal_log_init(getprogname(), 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; + } + if (eal_plugins_init() < 0) { rte_eal_init_alert("Cannot init plugins"); rte_errno = EINVAL; @@ -719,13 +726,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(getprogname(), 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; - } - /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34eb9..e24f24b1b0ce 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -973,6 +973,14 @@ rte_eal_init(int argc, char **argv) return -1; } + 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; + } + if (eal_plugins_init() < 0) { rte_eal_init_alert("Cannot init plugins"); rte_errno = EINVAL; @@ -1107,14 +1115,6 @@ 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; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/unix/eal_unix_log.c b/lib/eal/unix/eal_unix_log.c new file mode 100644 index 000000000000..e69de29bb2d1 -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v9 4/5] eal: allow user to set default log stream before init 2024-03-18 22:02 ` [PATCH v9 0/5] Logging unification and timestamp Stephen Hemminger ` (2 preceding siblings ...) 2024-03-18 22:02 ` [PATCH v9 3/5] eal: initialize logging before plugins Stephen Hemminger @ 2024-03-18 22:03 ` Stephen Hemminger 2024-03-18 22:03 ` [PATCH v9 5/5] eal: add option to put timestamp on console output Stephen Hemminger 4 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 22:03 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger It is useful for application to be able to set the default log stream before call rte_eal_init(). This makes all messages go to the new default. For example, to skip using syslog; just doing rte_openlog_stream(stderr); There is no reason for helper command line applications to clutter syslog with messages. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/dumpcap/main.c | 3 +++ app/pdump/main.c | 3 +++ app/proc-info/main.c | 3 +++ lib/log/log.c | 6 ++++++ lib/log/log_internal.h | 2 ++ lib/log/log_unix.c | 4 ++++ lib/log/version.map | 1 + 7 files changed, 22 insertions(+) diff --git a/app/dumpcap/main.c b/app/dumpcap/main.c index cc0f66b2bc61..27934ca7e688 100644 --- a/app/dumpcap/main.c +++ b/app/dumpcap/main.c @@ -633,6 +633,9 @@ static void dpdk_init(void) rte_panic("No memory\n"); } + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + if (rte_eal_init(eal_argc, eal_argv) < 0) rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n"); } diff --git a/app/pdump/main.c b/app/pdump/main.c index a9205e130bb1..7b9ba68b1a14 100644 --- a/app/pdump/main.c +++ b/app/pdump/main.c @@ -995,6 +995,9 @@ main(int argc, char **argv) argc += 2; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + diag = rte_eal_init(argc, argp); if (diag < 0) rte_panic("Cannot init EAL\n"); diff --git a/app/proc-info/main.c b/app/proc-info/main.c index b672aaefbe99..24ee52c4ac7a 100644 --- a/app/proc-info/main.c +++ b/app/proc-info/main.c @@ -2149,6 +2149,9 @@ main(int argc, char **argv) argc += 4; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + ret = rte_eal_init(argc, argp); if (ret < 0) rte_panic("Cannot init EAL\n"); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94cc..4cc944305057 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -519,6 +519,12 @@ eal_log_set_default(FILE *default_log) #endif } +FILE * +eal_log_get_default(void) +{ + return default_log_stream; +} + /* * Called by eal_cleanup */ diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1ba..c77e687e28bc 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -21,6 +21,8 @@ int eal_log_init(const char *id, int facility); */ __rte_internal void eal_log_set_default(FILE *default_log); +__rte_internal +FILE *eal_log_get_default(void); /* * Save a log option for later. diff --git a/lib/log/log_unix.c b/lib/log/log_unix.c index 2dfb0c974b1d..a415bae5774d 100644 --- a/lib/log/log_unix.c +++ b/lib/log/log_unix.c @@ -49,6 +49,10 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; + /* skip if user has already setup a log stream */ + if (eal_log_get_default()) + return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831aff..6ecc656d1d65 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_get_default; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v9 5/5] eal: add option to put timestamp on console output 2024-03-18 22:02 ` [PATCH v9 0/5] Logging unification and timestamp Stephen Hemminger ` (3 preceding siblings ...) 2024-03-18 22:03 ` [PATCH v9 4/5] eal: allow user to set default log stream before init Stephen Hemminger @ 2024-03-18 22:03 ` Stephen Hemminger 2024-03-19 7:37 ` Morten Brørup 4 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-18 22:03 UTC (permalink / raw) To: dev; +Cc: 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. The timestamp format is chosen to look like the default Linux dmesg timestamp. The first few lines are not timestamped because the flag is stored in internal configuration which is stored in shared memory which is not setup up until a little later in startup process. This logging skips the unnecessary step of going through stdio, which makes it more robust against being called in interrupt handlers etc. Example: $ dpdk-testpmd --log-timestamp -- -i EAL: Detected CPU lcores: 16 EAL: Detected NUMA nodes: 1 EAL: Detected static linkage of DPDK EAL: Multi-process socket /var/run/dpdk/rte/mp_socket EAL: Selected IOVA mode 'VA' [ 0.112264] testpmd: No probed ethernet devices Interactive-mode selected [ 0.184573] testpmd: create a new mbuf pool <mb_pool_0>: n=163456, size=2176, socket=0 [ 0.184612] testpmd: preferred mempool ops selected: ring_mp_mc Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 9 ++++++++ doc/guides/prog_guide/log_lib.rst | 10 +++++++++ lib/eal/common/eal_common_options.c | 10 +++++++-- lib/eal/common/eal_options.h | 2 ++ lib/log/log_internal.h | 9 ++++++++ lib/log/log_unix.c | 32 +++++++++++++++++++++++++++-- lib/log/log_windows.c | 6 ++++++ lib/log/version.map | 1 + 8 files changed, 75 insertions(+), 4 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b0675730..07a038fb6051 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1055,6 +1055,10 @@ 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" }; + /* run all tests also applicable to FreeBSD first */ if (launch_proc(argv0) == 0) { @@ -1162,6 +1166,11 @@ 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; + } + rmdir(hugepath_dir3); rmdir(hugepath_dir2); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index aacb36c36ce0..1d6b2e3cea5d 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -73,6 +73,16 @@ For example:: /path/to/app --syslog local0 +Console timestamp +~~~~~~~~~~~~~~~~~ + +On Linux and FreeBSD, 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 + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 7310d10dfd78..9bc95433d27c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -77,6 +77,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, 0, 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 }, @@ -1663,6 +1664,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1890,7 +1892,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 --" @@ -1898,7 +1900,10 @@ eal_parse_common_option(int opt, const char *optarg, return -1; } break; - } + + case OPT_LOG_TIMESTAMP_NUM: + eal_log_enable_timestamp(); + break; #ifndef RTE_EXEC_ENV_WINDOWS case OPT_TRACE_NUM: { @@ -2261,6 +2266,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6d7..e24c9eca53ca 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index c77e687e28bc..1af27fe8f9d3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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> @@ -44,4 +46,11 @@ const char *eal_log_level2str(uint32_t level); __rte_internal void rte_eal_log_cleanup(void); +/* + * Add timestamp to console logs + */ +__rte_internal +void eal_log_enable_timestamp(void); + + #endif /* LOG_INTERNAL_H */ diff --git a/lib/log/log_unix.c b/lib/log/log_unix.c index a415bae5774d..71ce366b6825 100644 --- a/lib/log/log_unix.c +++ b/lib/log/log_unix.c @@ -2,24 +2,52 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <sys/types.h> +#include <sys/uio.h> #include <syslog.h> +#include <time.h> +#include <unistd.h> #include <rte_log.h> #include "log_internal.h" +static bool timestamp_enabled; +static struct timespec log_started; + +void +eal_log_enable_timestamp(void) +{ + timestamp_enabled = true; + clock_gettime(CLOCK_MONOTONIC, &log_started); +} + /* * default log function */ static ssize_t console_log_write(__rte_unused void *c, const char *buf, size_t size) { + struct timespec ts; ssize_t ret; - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); + if (timestamp_enabled) { + clock_gettime(CLOCK_MONOTONIC, &ts); + ts.tv_sec -= log_started.tv_sec; + ts.tv_nsec -= log_started.tv_nsec; + if (ts.tv_nsec < 0) { + --ts.tv_sec; + ts.tv_nsec += 1000000000ul; + } + + ret = fprintf(stderr, "[%8lu.%06lu] %.*s", + ts.tv_sec, ts.tv_nsec / 1000u, + (int) size, buf); + } else { + ret = fwrite(buf, 1, size, stderr); + } fflush(stderr); /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a08895501e..0c471bfb15f6 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,6 +6,12 @@ #include <rte_log.h> #include "log_internal.h" +void +eal_log_enable_timestamp(void) +{ + /* not implemented */ +} + /* set the log to default function, called during eal init process. */ int eal_log_init(__rte_unused const char *id, __rte_unused int facility) diff --git a/lib/log/version.map b/lib/log/version.map index 6ecc656d1d65..32c555f29e79 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_enable_timestamp; eal_log_get_default; eal_log_init; eal_log_level2str; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v9 5/5] eal: add option to put timestamp on console output 2024-03-18 22:03 ` [PATCH v9 5/5] eal: add option to put timestamp on console output Stephen Hemminger @ 2024-03-19 7:37 ` Morten Brørup 2024-03-19 15:51 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Morten Brørup @ 2024-03-19 7:37 UTC (permalink / raw) To: Stephen Hemminger, dev > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > Sent: Monday, 18 March 2024 23.03 > > 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. The timestamp format is chosen to look > like the default Linux dmesg timestamp. > > The first few lines are not timestamped because the flag is stored > in internal configuration which is stored in shared memory > which is not setup up until a little later in startup process. > > This logging skips the unnecessary step of going through stdio, > which makes it more robust against being called in interrupt > handlers etc. > > Example: > $ dpdk-testpmd --log-timestamp -- -i > EAL: Detected CPU lcores: 16 > EAL: Detected NUMA nodes: 1 > EAL: Detected static linkage of DPDK > EAL: Multi-process socket /var/run/dpdk/rte/mp_socket > EAL: Selected IOVA mode 'VA' > [ 0.112264] testpmd: No probed ethernet devices > Interactive-mode selected > [ 0.184573] testpmd: create a new mbuf pool <mb_pool_0>: n=163456, > size=2176, socket=0 > [ 0.184612] testpmd: preferred mempool ops selected: ring_mp_mc > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- [...] > static ssize_t > console_log_write(__rte_unused void *c, const char *buf, size_t size) > { > + struct timespec ts; > ssize_t ret; > > - /* write on stderr */ > - ret = fwrite(buf, 1, size, stderr); > + if (timestamp_enabled) { > + clock_gettime(CLOCK_MONOTONIC, &ts); > + ts.tv_sec -= log_started.tv_sec; > + ts.tv_nsec -= log_started.tv_nsec; Please log the absolute CLOCK_MONOTONIC instead of subtracting log_started, so timestamps can be easily compared with timestamps from other processes. > + if (ts.tv_nsec < 0) { > + --ts.tv_sec; > + ts.tv_nsec += 1000000000ul; > + } > + > + ret = fprintf(stderr, "[%8lu.%06lu] %.*s", > + ts.tv_sec, ts.tv_nsec / 1000u, > + (int) size, buf); With the above change, For the series, Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v9 5/5] eal: add option to put timestamp on console output 2024-03-19 7:37 ` Morten Brørup @ 2024-03-19 15:51 ` Stephen Hemminger 2024-03-19 16:13 ` Morten Brørup 0 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-19 15:51 UTC (permalink / raw) To: Morten Brørup; +Cc: dev On Tue, 19 Mar 2024 08:37:30 +0100 Morten Brørup <mb@smartsharesystems.com> wrote: > > static ssize_t > > console_log_write(__rte_unused void *c, const char *buf, size_t size) > > { > > + struct timespec ts; > > ssize_t ret; > > > > - /* write on stderr */ > > - ret = fwrite(buf, 1, size, stderr); > > + if (timestamp_enabled) { > > + clock_gettime(CLOCK_MONOTONIC, &ts); > > + ts.tv_sec -= log_started.tv_sec; > > + ts.tv_nsec -= log_started.tv_nsec; > > Please log the absolute CLOCK_MONOTONIC instead of subtracting log_started, so timestamps can be easily compared with timestamps from other processes. No, was trying to do what kernel dmesg does. ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v9 5/5] eal: add option to put timestamp on console output 2024-03-19 15:51 ` Stephen Hemminger @ 2024-03-19 16:13 ` Morten Brørup 2024-03-20 3:33 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Morten Brørup @ 2024-03-19 16:13 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > Sent: Tuesday, 19 March 2024 16.52 > > On Tue, 19 Mar 2024 08:37:30 +0100 > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > static ssize_t > > > console_log_write(__rte_unused void *c, const char *buf, size_t > size) > > > { > > > + struct timespec ts; > > > ssize_t ret; > > > > > > - /* write on stderr */ > > > - ret = fwrite(buf, 1, size, stderr); > > > + if (timestamp_enabled) { > > > + clock_gettime(CLOCK_MONOTONIC, &ts); > > > + ts.tv_sec -= log_started.tv_sec; > > > + ts.tv_nsec -= log_started.tv_nsec; > > > > Please log the absolute CLOCK_MONOTONIC instead of subtracting > log_started, so timestamps can be easily compared with timestamps from > other processes. > > > No, was trying to do what kernel dmesg does. What do you mean? Doesn't the kernel output CLOCK_MONOTONIC timestamps (without offset)? And by "timestamps from other processes" I also mean timestamps in log messages from the kernel itself. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v9 5/5] eal: add option to put timestamp on console output 2024-03-19 16:13 ` Morten Brørup @ 2024-03-20 3:33 ` Stephen Hemminger 2024-03-20 8:34 ` Morten Brørup 0 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-20 3:33 UTC (permalink / raw) To: Morten Brørup; +Cc: dev On Tue, 19 Mar 2024 17:13:35 +0100 Morten Brørup <mb@smartsharesystems.com> wrote: > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > Sent: Tuesday, 19 March 2024 16.52 > > > > On Tue, 19 Mar 2024 08:37:30 +0100 > > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > > > static ssize_t > > > > console_log_write(__rte_unused void *c, const char *buf, size_t > > size) > > > > { > > > > + struct timespec ts; > > > > ssize_t ret; > > > > > > > > - /* write on stderr */ > > > > - ret = fwrite(buf, 1, size, stderr); > > > > + if (timestamp_enabled) { > > > > + clock_gettime(CLOCK_MONOTONIC, &ts); > > > > + ts.tv_sec -= log_started.tv_sec; > > > > + ts.tv_nsec -= log_started.tv_nsec; > > > > > > Please log the absolute CLOCK_MONOTONIC instead of subtracting > > log_started, so timestamps can be easily compared with timestamps from > > other processes. > > > > > > No, was trying to do what kernel dmesg does. > > What do you mean? Doesn't the kernel output CLOCK_MONOTONIC timestamps (without offset)? > > And by "timestamps from other processes" I also mean timestamps in log messages from the kernel itself. > If you look at dmesg command that formats the messages, it has lots of timestamp options. Next version will support more of these. --time-format format Print timestamps using the given format, which can be ctime, reltime, delta or iso. The first three formats are aliases of the time-format-specific options. The iso format is a dmesg implementation of the ISO-8601 timestamp format. The purpose of this format is to make the comparing of timestamps between two systems, and any other parsing, easy. The definition of the iso timestamp is: YYYY-MM-DD<T>HH:MM:SS,<microseconds>←+><timezone offset from UTC>. ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v9 5/5] eal: add option to put timestamp on console output 2024-03-20 3:33 ` Stephen Hemminger @ 2024-03-20 8:34 ` Morten Brørup 2024-03-20 14:38 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Morten Brørup @ 2024-03-20 8:34 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > Sent: Wednesday, 20 March 2024 04.34 > > On Tue, 19 Mar 2024 17:13:35 +0100 > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > > Sent: Tuesday, 19 March 2024 16.52 > > > > > > On Tue, 19 Mar 2024 08:37:30 +0100 > > > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > > > > > static ssize_t > > > > > console_log_write(__rte_unused void *c, const char *buf, size_t > > > size) > > > > > { > > > > > + struct timespec ts; > > > > > ssize_t ret; > > > > > > > > > > - /* write on stderr */ > > > > > - ret = fwrite(buf, 1, size, stderr); > > > > > + if (timestamp_enabled) { > > > > > + clock_gettime(CLOCK_MONOTONIC, &ts); > > > > > + ts.tv_sec -= log_started.tv_sec; > > > > > + ts.tv_nsec -= log_started.tv_nsec; > > > > > > > > Please log the absolute CLOCK_MONOTONIC instead of subtracting > > > log_started, so timestamps can be easily compared with timestamps from > > > other processes. > > > > > > > > > No, was trying to do what kernel dmesg does. > > > > What do you mean? Doesn't the kernel output CLOCK_MONOTONIC timestamps > (without offset)? > > > > And by "timestamps from other processes" I also mean timestamps in log > messages from the kernel itself. > > > > If you look at dmesg command that formats the messages, it has lots of > timestamp options. > Next version will support more of these. > > --time-format format > Print timestamps using the given format, which can be ctime, > reltime, delta or iso. The first three formats are aliases of > the time-format-specific options. The iso format is a dmesg > implementation of the ISO-8601 timestamp format. The purpose > of this format is to make the comparing of timestamps between > two systems, and any other parsing, easy. The definition of > the iso timestamp is: > YYYY-MM-DD<T>HH:MM:SS,<microseconds>←+><timezone offset from > UTC>. That's formatting. I'm talking about the initial offset. The kernel's "log start time" is set to system start timestamp. Your "log start time" is set to application start timestamp: +void +eal_log_enable_timestamp(void) +{ + timestamp_enabled = true; + clock_gettime(CLOCK_MONOTONIC, &log_started); +} So, different offset. I prefer using the same offset. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v9 5/5] eal: add option to put timestamp on console output 2024-03-20 8:34 ` Morten Brørup @ 2024-03-20 14:38 ` Stephen Hemminger 2024-03-20 17:38 ` Morten Brørup 0 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-20 14:38 UTC (permalink / raw) To: Morten Brørup; +Cc: dev On Wed, 20 Mar 2024 09:34:21 +0100 Morten Brørup <mb@smartsharesystems.com> wrote: > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > Sent: Wednesday, 20 March 2024 04.34 > > > > On Tue, 19 Mar 2024 17:13:35 +0100 > > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > > > Sent: Tuesday, 19 March 2024 16.52 > > > > > > > > On Tue, 19 Mar 2024 08:37:30 +0100 > > > > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > > > > > > > static ssize_t > > > > > > console_log_write(__rte_unused void *c, const char *buf, size_t > > > > size) > > > > > > { > > > > > > + struct timespec ts; > > > > > > ssize_t ret; > > > > > > > > > > > > - /* write on stderr */ > > > > > > - ret = fwrite(buf, 1, size, stderr); > > > > > > + if (timestamp_enabled) { > > > > > > + clock_gettime(CLOCK_MONOTONIC, &ts); > > > > > > + ts.tv_sec -= log_started.tv_sec; > > > > > > + ts.tv_nsec -= log_started.tv_nsec; > > > > > > > > > > Please log the absolute CLOCK_MONOTONIC instead of subtracting > > > > log_started, so timestamps can be easily compared with timestamps from > > > > other processes. > > > > > > > > > > > > No, was trying to do what kernel dmesg does. > > > > > > What do you mean? Doesn't the kernel output CLOCK_MONOTONIC timestamps > > (without offset)? > > > > > > And by "timestamps from other processes" I also mean timestamps in log > > messages from the kernel itself. > > > > > > > If you look at dmesg command that formats the messages, it has lots of > > timestamp options. > > Next version will support more of these. > > > > --time-format format > > Print timestamps using the given format, which can be ctime, > > reltime, delta or iso. The first three formats are aliases of > > the time-format-specific options. The iso format is a dmesg > > implementation of the ISO-8601 timestamp format. The purpose > > of this format is to make the comparing of timestamps between > > two systems, and any other parsing, easy. The definition of > > the iso timestamp is: > > YYYY-MM-DD<T>HH:MM:SS,<microseconds>←+><timezone offset from > > UTC>. > > That's formatting. > > I'm talking about the initial offset. > > The kernel's "log start time" is set to system start timestamp. > > Your "log start time" is set to application start timestamp: > > +void > +eal_log_enable_timestamp(void) > +{ > + timestamp_enabled = true; > + clock_gettime(CLOCK_MONOTONIC, &log_started); > +} > > So, different offset. I prefer using the same offset. Monotonic has no absolute zero time and can be quite large so offsetting seemed most logical. Also, the kernel does not make boot time monotonic clock value available. Other options are REALTIME or BOOTTIME. But both of these get quite large. ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v9 5/5] eal: add option to put timestamp on console output 2024-03-20 14:38 ` Stephen Hemminger @ 2024-03-20 17:38 ` Morten Brørup 0 siblings, 0 replies; 445+ messages in thread From: Morten Brørup @ 2024-03-20 17:38 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > Sent: Wednesday, 20 March 2024 15.39 > > On Wed, 20 Mar 2024 09:34:21 +0100 > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > > Sent: Wednesday, 20 March 2024 04.34 > > > > > > On Tue, 19 Mar 2024 17:13:35 +0100 > > > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > > > > > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > > > > > Sent: Tuesday, 19 March 2024 16.52 > > > > > > > > > > On Tue, 19 Mar 2024 08:37:30 +0100 > > > > > Morten Brørup <mb@smartsharesystems.com> wrote: > > > > > > > > > > > > static ssize_t > > > > > > > console_log_write(__rte_unused void *c, const char *buf, > size_t > > > > > size) > > > > > > > { > > > > > > > + struct timespec ts; > > > > > > > ssize_t ret; > > > > > > > > > > > > > > - /* write on stderr */ > > > > > > > - ret = fwrite(buf, 1, size, stderr); > > > > > > > + if (timestamp_enabled) { > > > > > > > + clock_gettime(CLOCK_MONOTONIC, &ts); > > > > > > > + ts.tv_sec -= log_started.tv_sec; > > > > > > > + ts.tv_nsec -= log_started.tv_nsec; > > > > > > > > > > > > Please log the absolute CLOCK_MONOTONIC instead of subtracting > > > > > log_started, so timestamps can be easily compared with > timestamps from > > > > > other processes. > > > > > > > > > > > > > > > No, was trying to do what kernel dmesg does. > > > > > > > > What do you mean? Doesn't the kernel output CLOCK_MONOTONIC > timestamps > > > (without offset)? > > > > > > > > And by "timestamps from other processes" I also mean timestamps in > log > > > messages from the kernel itself. > > > > > > > > > > If you look at dmesg command that formats the messages, it has lots > of > > > timestamp options. > > > Next version will support more of these. > > > > > > --time-format format > > > Print timestamps using the given format, which can be > ctime, > > > reltime, delta or iso. The first three formats are > aliases of > > > the time-format-specific options. The iso format is a > dmesg > > > implementation of the ISO-8601 timestamp format. The > purpose > > > of this format is to make the comparing of timestamps > between > > > two systems, and any other parsing, easy. The definition > of > > > the iso timestamp is: > > > YYYY-MM-DD<T>HH:MM:SS,<microseconds>←+><timezone offset > from > > > UTC>. > > > > That's formatting. > > > > I'm talking about the initial offset. > > > > The kernel's "log start time" is set to system start timestamp. > > > > Your "log start time" is set to application start timestamp: > > > > +void > > +eal_log_enable_timestamp(void) > > +{ > > + timestamp_enabled = true; > > + clock_gettime(CLOCK_MONOTONIC, &log_started); > > +} > > > > So, different offset. I prefer using the same offset. > > > Monotonic has no absolute zero time and can be quite large so offsetting > seemed most logical. Also, the kernel does not make boot time monotonic > clock value available. Other options are REALTIME or BOOTTIME. > But both of these get quite large. I don't think that having a large tv_sec is a problem. I think the ability to correlate log timestamps with other applications is more important. If we choose one of the standard clocks, applications might choose the same clock. If we subtract the start time of this specific application, it's not in sync with anything else. The question really is: Which clock is most popular for debug logging to the console? We should use that clock. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 00/10] Logging enhancements. 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (8 preceding siblings ...) 2024-03-18 22:02 ` [PATCH v9 0/5] Logging unification and timestamp Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 01/10] windows: make getopt functions have const properties Stephen Hemminger ` (9 more replies) 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger ` (19 subsequent siblings) 29 siblings, 10 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). This is update to earlier patch set. It adds two 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. The message going into syslog is already timestamped (by syslog) so no additional timestamp is needed. * 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. I find color helpful because 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. Note: neither of these are possible on Windows because the fopencookie() function is a GNU libc and not Posix feature. Will add a release note in next release (after this is merged). v10 - put windows getopt patch in series since otherwise windows build fails. - support multiple timestamp formats - support colorized output - fix up rte_init_alert() and rte_exit() to match format expected by the timestamp and color modes - initialize logging much earlier in startup - add documentation about logging options Stephen Hemminger (10): windows: make getopt functions have const properties log: unify logging code eal: make eal_log_level_parse common eal: initialize log earlier in startup eal: do not duplicate rte_init_alert() messages eal: change rte_exit() output to match rte_log() eal: allow user to set default log stream before init eal: add option to put timestamp on console output log: colorize log output doc: add documentation of logging options app/dumpcap/main.c | 3 + app/pdump/main.c | 3 + app/proc-info/main.c | 3 + app/test/test_eal_flags.c | 17 + doc/guides/linux_gsg/eal_args.include.rst | 54 ++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 -- doc/guides/prog_guide/log_lib.rst | 28 +- lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 70 +++- lib/eal/common/eal_options.h | 5 + lib/eal/freebsd/eal.c | 53 +-- lib/eal/linux/eal.c | 58 +--- lib/eal/unix/eal_unix_log.c | 0 lib/eal/windows/eal.c | 35 -- lib/eal/windows/getopt.c | 23 +- lib/eal/windows/include/getopt.h | 8 +- lib/log/log.c | 6 + lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 16 + lib/log/log_linux.c | 61 ---- lib/log/log_unix.c | 321 ++++++++++++++++++ lib/log/log_windows.c | 12 + lib/log/meson.build | 12 +- lib/log/version.map | 3 + 24 files changed, 577 insertions(+), 264 deletions(-) create mode 100644 lib/eal/unix/eal_unix_log.c delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c create mode 100644 lib/log/log_unix.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 01/10] windows: make getopt functions have const properties 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 02/10] log: unify logging code Stephen Hemminger ` (8 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c2318..50ff71b9300d 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b17..e4cf6873cb0c 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 02/10] log: unify logging code 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 01/10] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 03/10] eal: make eal_log_level_parse common Stephen Hemminger ` (7 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger FreeBSD and Linux logging code can use common code. This also fixes FreeBSD not using syslog. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------------------- doc/guides/prog_guide/log_lib.rst | 18 +++++++++++-- lib/eal/freebsd/eal.c | 8 ++++++ lib/log/log_freebsd.c | 12 --------- lib/log/{log_linux.c => log_unix.c} | 0 lib/log/meson.build | 12 ++++++--- 6 files changed, 32 insertions(+), 45 deletions(-) delete mode 100644 lib/log/log_freebsd.c rename lib/log/{log_linux.c => log_unix.c} (100%) diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f38139119..d86f94d8a85d 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2c8..aacb36c36ce0 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -5,8 +5,8 @@ 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. +By default, in a Linux (or FreeBSD) application, logs are sent to syslog and also to the console. +In 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. Log Levels @@ -29,6 +29,7 @@ will be emitted by the application to the log output. That level can be configured either by the application calling the relevant APIs from the logging library, or by the user passing the ``--log-level`` parameter to the EAL via the application. + Setting Global Log Level ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -59,6 +60,19 @@ 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. + +Setting syslog facility +~~~~~~~~~~~~~~~~~~~~~~~ + +On Linux and FreeBSD, where syslog is used a ``facility`` argument can be +used to specify what type of program is logging. +The default facility is ``daemon`` but it can be overridden +by the ``--syslog`` EAL parameter. See ``syslog.3`` man page for full values. +For example:: + + /path/to/app --syslog local0 + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e967..a57ee8406f0c 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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) @@ -760,6 +761,13 @@ rte_eal_init(int argc, char **argv) #endif } + if (eal_log_init(getprogname(), 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; + } + /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 698d3c542337..000000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -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; -} diff --git a/lib/log/log_linux.c b/lib/log/log_unix.c similarity index 100% rename from lib/log/log_linux.c rename to lib/log/log_unix.c diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f77..60516a0b2a2d 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,12 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') + +if is_windows + sources += files('log_windows.c') +else + sources += files('log_unix.c') +endif + headers = files('rte_log.h') -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 03/10] eal: make eal_log_level_parse common 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 01/10] windows: make getopt functions have const properties Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 02/10] log: unify logging code Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 17:00 ` Tyler Retzlaff 2024-03-21 16:00 ` [PATCH v10 04/10] eal: initialize log earlier in startup Stephen Hemminger ` (6 subsequent siblings) 9 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f0793964..7310d10dfd78 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out) return -1; } +/* Parse the all arguments looking for --log-level */ +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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb641284..f3f2e104f6d7 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a57ee8406f0c..94927472edfe 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -364,48 +364,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f6236..bffeb1f34eb9 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462dd8..85171b27687e 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v10 03/10] eal: make eal_log_level_parse common 2024-03-21 16:00 ` [PATCH v10 03/10] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-21 17:00 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-21 17:00 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Thu, Mar 21, 2024 at 09:00:19AM -0700, Stephen Hemminger wrote: > The code to parse for log-level option should be same on > all OS variants. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 04/10] eal: initialize log earlier in startup 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger ` (2 preceding siblings ...) 2024-03-21 16:00 ` [PATCH v10 03/10] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 05/10] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (5 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Want to make sure that as many log messages as possible get added with the real log stream. Despite the comment, there is no dependency on memzones in current code. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 14 +++++++------- lib/eal/linux/eal.c | 16 ++++++++-------- lib/eal/unix/eal_unix_log.c | 0 lib/log/log_unix.c | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 lib/eal/unix/eal_unix_log.c diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 94927472edfe..777770176339 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -571,6 +571,13 @@ rte_eal_init(int argc, char **argv) /* set log level as early as possible */ eal_log_level_parse(argc, argv); + if (eal_log_init(getprogname(), 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; + } + if (rte_eal_cpu_init() < 0) { rte_eal_init_alert("Cannot detect lcores."); rte_errno = ENOTSUP; @@ -719,13 +726,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(getprogname(), 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; - } - /* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first. diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34eb9..e515f3cbc8a8 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -959,6 +959,14 @@ rte_eal_init(int argc, char **argv) /* clone argv to report out later in telemetry */ eal_save_args(argc, argv); + 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; + } + if (rte_eal_cpu_init() < 0) { rte_eal_init_alert("Cannot detect lcores."); rte_errno = ENOTSUP; @@ -1107,14 +1115,6 @@ 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; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/unix/eal_unix_log.c b/lib/eal/unix/eal_unix_log.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/log/log_unix.c b/lib/log/log_unix.c index 2dfb0c974b1d..ae38b4bf3a59 100644 --- a/lib/log/log_unix.c +++ b/lib/log/log_unix.c @@ -41,8 +41,8 @@ static cookie_io_functions_t console_log_func = { }; /* - * set the log to default function, called during eal init process, - * once memzones are available. + * set the log to default function, called early in eal init process; + * before lcore's and memzones are setup. */ int eal_log_init(const char *id, int facility) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 05/10] eal: do not duplicate rte_init_alert() messages 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger ` (3 preceding siblings ...) 2024-03-21 16:00 ` [PATCH v10 04/10] eal: initialize log earlier in startup Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 06/10] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (4 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 777770176339..e3f25f619715 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index e515f3cbc8a8..461f0c093357 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 06/10] eal: change rte_exit() output to match rte_log() 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger ` (4 preceding siblings ...) 2024-03-21 16:00 ` [PATCH v10 05/10] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 17:04 ` Tyler Retzlaff 2024-03-21 16:00 ` [PATCH v10 07/10] eal: allow user to set default log stream before init Stephen Hemminger ` (3 subsequent siblings) 9 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: 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: Cause: Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896d5..568883830f20 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char *msg = NULL; 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); + vasprintf(&msg, format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause: %s", msg); + 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v10 06/10] eal: change rte_exit() output to match rte_log() 2024-03-21 16:00 ` [PATCH v10 06/10] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-21 17:04 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-21 17:04 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Thu, Mar 21, 2024 at 09:00:22AM -0700, Stephen Hemminger wrote: > 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: Cause: Cannot init EAL: Permission denied it is better but maybe : -> - for Cause? [ 0.006238] EAL: Error - exiting with code: 1 [ 0.006250] EAL: Cause - Cannot init EAL: Permission denied > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- ACked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > lib/eal/common/eal_common_debug.c | 11 ++++++----- > 1 file changed, 6 insertions(+), 5 deletions(-) > > diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c > index 3e77995896d5..568883830f20 100644 > --- a/lib/eal/common/eal_common_debug.c > +++ b/lib/eal/common/eal_common_debug.c > @@ -34,17 +34,18 @@ void > rte_exit(int exit_code, const char *format, ...) > { > va_list ap; > + char *msg = NULL; > > 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); > + vasprintf(&msg, format, ap); > va_end(ap); > > + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause: %s", msg); > + > 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); > } > -- > 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 07/10] eal: allow user to set default log stream before init 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger ` (5 preceding siblings ...) 2024-03-21 16:00 ` [PATCH v10 06/10] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 17:07 ` Tyler Retzlaff 2024-03-21 16:00 ` [PATCH v10 08/10] eal: add option to put timestamp on console output Stephen Hemminger ` (2 subsequent siblings) 9 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger It is useful for application to be able to set the default log stream before call rte_eal_init(). This makes all messages go to the new default. For example, to skip using syslog; just doing rte_openlog_stream(stderr); There is no reason for helper command line applications to clutter syslog with messages. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/dumpcap/main.c | 3 +++ app/pdump/main.c | 3 +++ app/proc-info/main.c | 3 +++ lib/log/log.c | 6 ++++++ lib/log/log_internal.h | 2 ++ lib/log/log_unix.c | 4 ++++ lib/log/version.map | 1 + 7 files changed, 22 insertions(+) diff --git a/app/dumpcap/main.c b/app/dumpcap/main.c index cc0f66b2bc61..27934ca7e688 100644 --- a/app/dumpcap/main.c +++ b/app/dumpcap/main.c @@ -633,6 +633,9 @@ static void dpdk_init(void) rte_panic("No memory\n"); } + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + if (rte_eal_init(eal_argc, eal_argv) < 0) rte_exit(EXIT_FAILURE, "EAL init failed: is primary process running?\n"); } diff --git a/app/pdump/main.c b/app/pdump/main.c index a9205e130bb1..7b9ba68b1a14 100644 --- a/app/pdump/main.c +++ b/app/pdump/main.c @@ -995,6 +995,9 @@ main(int argc, char **argv) argc += 2; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + diag = rte_eal_init(argc, argp); if (diag < 0) rte_panic("Cannot init EAL\n"); diff --git a/app/proc-info/main.c b/app/proc-info/main.c index b672aaefbe99..24ee52c4ac7a 100644 --- a/app/proc-info/main.c +++ b/app/proc-info/main.c @@ -2149,6 +2149,9 @@ main(int argc, char **argv) argc += 4; + /* keep any logging away from syslog. */ + rte_openlog_stream(stderr); + ret = rte_eal_init(argc, argp); if (ret < 0) rte_panic("Cannot init EAL\n"); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94cc..4cc944305057 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -519,6 +519,12 @@ eal_log_set_default(FILE *default_log) #endif } +FILE * +eal_log_get_default(void) +{ + return default_log_stream; +} + /* * Called by eal_cleanup */ diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1ba..c77e687e28bc 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -21,6 +21,8 @@ int eal_log_init(const char *id, int facility); */ __rte_internal void eal_log_set_default(FILE *default_log); +__rte_internal +FILE *eal_log_get_default(void); /* * Save a log option for later. diff --git a/lib/log/log_unix.c b/lib/log/log_unix.c index ae38b4bf3a59..c56f80ac6967 100644 --- a/lib/log/log_unix.c +++ b/lib/log/log_unix.c @@ -49,6 +49,10 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; + /* skip if user has already setup a log stream */ + if (eal_log_get_default()) + return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831aff..6ecc656d1d65 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_get_default; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v10 07/10] eal: allow user to set default log stream before init 2024-03-21 16:00 ` [PATCH v10 07/10] eal: allow user to set default log stream before init Stephen Hemminger @ 2024-03-21 17:07 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-21 17:07 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Thu, Mar 21, 2024 at 09:00:23AM -0700, Stephen Hemminger wrote: > It is useful for application to be able to set the default log > stream before call rte_eal_init(). This makes all messages go > to the new default. > > For example, to skip using syslog; just doing > rte_openlog_stream(stderr); > > There is no reason for helper command line applications to clutter > syslog with messages. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 08/10] eal: add option to put timestamp on console output 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger ` (6 preceding siblings ...) 2024-03-21 16:00 ` [PATCH v10 07/10] eal: allow user to set default log stream before init Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 17:11 ` Tyler Retzlaff 2024-03-21 16:00 ` [PATCH v10 09/10] log: colorize log output Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 10/10] doc: add documentation of logging options Stephen Hemminger 9 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: 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. Other alternatives are delta, ctime, reltime and iso formats. Example: $ dpdk-testpmd --log-timestamp -- -i EAL: Detected CPU lcores: 8 EAL: Detected NUMA nodes: 1 [ 0.000083] EAL: Detected static linkage of DPDK [ 0.002000] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket [ 0.003507] EAL: Selected IOVA mode 'VA' [ 0.006272] testpmd: No probed ethernet devices Interactive-mode selected [ 0.029567] testpmd: create a new mbuf pool <mb_pool_0>: n=203456, size=2176, socket=0 [ 0.029588] testpmd: preferred mempool ops selected: ring_mp_mc Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 17 ++++ doc/guides/prog_guide/log_lib.rst | 10 ++ lib/eal/common/eal_common_options.c | 14 ++- lib/eal/common/eal_options.h | 2 + lib/log/log_internal.h | 9 ++ lib/log/log_unix.c | 152 +++++++++++++++++++++++++++- lib/log/log_windows.c | 6 ++ lib/log/version.map | 1 + 8 files changed, 205 insertions(+), 6 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b0675730..eeb1799381d7 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1055,6 +1055,14 @@ 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" }; + /* run all tests also applicable to FreeBSD first */ if (launch_proc(argv0) == 0) { @@ -1162,6 +1170,15 @@ 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; + } + rmdir(hugepath_dir3); rmdir(hugepath_dir2); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index aacb36c36ce0..1d6b2e3cea5d 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -73,6 +73,16 @@ For example:: /path/to/app --syslog local0 +Console timestamp +~~~~~~~~~~~~~~~~~ + +On Linux and FreeBSD, 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 + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 7310d10dfd78..4e2c3d0f255c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -77,6 +77,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 }, @@ -1663,6 +1664,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1890,7 +1892,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 --" @@ -1898,9 +1900,16 @@ eal_parse_common_option(int opt, const char *optarg, return -1; } break; - } #ifndef RTE_EXEC_ENV_WINDOWS + case OPT_LOG_TIMESTAMP_NUM: + if (eal_log_timestamp(optarg) < 0) { + EAL_LOG(ERR, "invalid parameters for --" + OPT_LOG_TIMESTAMP); + return -1; + } + break; + case OPT_TRACE_NUM: { if (eal_trace_args_save(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" @@ -2261,6 +2270,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_LOG_TIMESTAMP" Timestamp log output\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6d7..e24c9eca53ca 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index c77e687e28bc..0e18d147cf98 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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> @@ -44,4 +46,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 */ diff --git a/lib/log/log_unix.c b/lib/log/log_unix.c index c56f80ac6967..cb8f17bc83ef 100644 --- a/lib/log/log_unix.c +++ b/lib/log/log_unix.c @@ -2,28 +2,169 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> +#include <string.h> #include <sys/types.h> +#include <sys/uio.h> #include <syslog.h> +#include <time.h> +#include <unistd.h> #include <rte_log.h> #include "log_internal.h" +enum eal_log_time_format { + EAL_LOG_TIMESTAMP_NONE = 0, + EAL_LOG_TIMESTAMP_TIME, /* time since start */ + EAL_LOG_TIMESTAMP_DELTA, /* time since last message */ + EAL_LOG_TIMESTAMP_RELTIME, + EAL_LOG_TIMESTAMP_CTIME, + EAL_LOG_TIMESTAMP_ISO, +}; + +static struct { + enum eal_log_time_format time_format; + struct timespec start_time; + struct timespec last_time; + struct tm last_tm; +} log = { + .time_format = EAL_LOG_TIMESTAMP_NONE, +}; + +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log.time_format = EAL_LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log.time_format = EAL_LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log.time_format = EAL_LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log.time_format = EAL_LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log.time_format = EAL_LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log.time_format = EAL_LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +static ssize_t +console_log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, ts; + struct tm *tm, cur; + + switch (log.time_format) { + case EAL_LOG_TIMESTAMP_NONE: + return 0; + + case EAL_LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + ts = timespec_sub(&now, &log.start_time); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + ts.tv_sec, ts.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + ts = timespec_sub(&now, &log.last_time); + log.last_time = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + ts.tv_sec, ts.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + tm = localtime_r(&now.tv_sec, &cur); + ts = timespec_sub(&now, &log.last_time); + log.last_time = now; + + /* if minute, day, hour hasn't changed then print delta */ + if (cur.tm_min != log.last_tm.tm_min || + cur.tm_hour != log.last_tm.tm_hour || + cur.tm_yday != log.last_tm.tm_yday) { + log.last_tm = cur; + return strftime(tsbuf, tsbuflen, "%b%e %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%4lu.%06lu", + ts.tv_sec, ts.tv_nsec / 1000u); + } + + case EAL_LOG_TIMESTAMP_CTIME: { + char cbuf[32]; /* "Wed Jun 30 21:49:08 1993\n" */ + + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* .24s is to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", + ctime_r(&now.tv_sec, cbuf)); + } + + case EAL_LOG_TIMESTAMP_ISO: { + char dbuf[64]; /* "2024-05-01T22:11:00" */ + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + tm = localtime_r(&now.tv_sec, &cur); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + return snprintf(tsbuf, tsbuflen, "%s,%06lu%+03ld:%02ld", dbuf, + now.tv_nsec / 1000u, + tm->tm_gmtoff / 3600, + (tm->tm_gmtoff / 60) % 60); + } + } + + return 0; +} + /* * default log function */ static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) +console_log_write(__rte_unused void *c, const char *msg, size_t size) { + char buf[128]; ssize_t ret; - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); + ret = console_log_timestamp(buf, sizeof(buf)); + if (ret == 0) + ret = fwrite(msg, 1, size, stderr); + else + ret = fprintf(stderr, "[%s] %.*s", buf, (int)size, msg); fflush(stderr); /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, msg); return ret; } @@ -49,6 +190,9 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; + clock_gettime(CLOCK_MONOTONIC, &log.start_time); + log.last_time = log.start_time; + /* skip if user has already setup a log stream */ if (eal_log_get_default()) return 0; diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a08895501e..8aa68a181bec 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,6 +6,12 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_timestamp(__rte_unused const char *fmt) +{ + return -1; /* not implemented */ +} + /* set the log to default function, called during eal init process. */ int eal_log_init(__rte_unused const char *id, __rte_unused int facility) diff --git a/lib/log/version.map b/lib/log/version.map index 6ecc656d1d65..697cdb3cb1b2 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -31,5 +31,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v10 08/10] eal: add option to put timestamp on console output 2024-03-21 16:00 ` [PATCH v10 08/10] eal: add option to put timestamp on console output Stephen Hemminger @ 2024-03-21 17:11 ` Tyler Retzlaff 2024-03-21 17:16 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-21 17:11 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Thu, Mar 21, 2024 at 09:00:24AM -0700, Stephen Hemminger wrote: > 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. Other alternatives > are delta, ctime, reltime and iso formats. > > Example: > $ dpdk-testpmd --log-timestamp -- -i > EAL: Detected CPU lcores: 8 > EAL: Detected NUMA nodes: 1 > [ 0.000083] EAL: Detected static linkage of DPDK > [ 0.002000] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket > [ 0.003507] EAL: Selected IOVA mode 'VA' > [ 0.006272] testpmd: No probed ethernet devices > Interactive-mode selected > [ 0.029567] testpmd: create a new mbuf pool <mb_pool_0>: n=203456, size=2176, socket=0 > [ 0.029588] testpmd: preferred mempool ops selected: ring_mp_mc > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- > app/test/test_eal_flags.c | 17 ++++ > doc/guides/prog_guide/log_lib.rst | 10 ++ > lib/eal/common/eal_common_options.c | 14 ++- > lib/eal/common/eal_options.h | 2 + > lib/log/log_internal.h | 9 ++ > lib/log/log_unix.c | 152 +++++++++++++++++++++++++++- > lib/log/log_windows.c | 6 ++ > lib/log/version.map | 1 + > 8 files changed, 205 insertions(+), 6 deletions(-) > > diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c > index 6cb4b0675730..eeb1799381d7 100644 > --- a/app/test/test_eal_flags.c > +++ b/app/test/test_eal_flags.c > @@ -1055,6 +1055,14 @@ 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" }; > + > /* run all tests also applicable to FreeBSD first */ > > if (launch_proc(argv0) == 0) { > @@ -1162,6 +1170,15 @@ 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; > + } > + > > rmdir(hugepath_dir3); > rmdir(hugepath_dir2); > diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst > index aacb36c36ce0..1d6b2e3cea5d 100644 > --- a/doc/guides/prog_guide/log_lib.rst > +++ b/doc/guides/prog_guide/log_lib.rst > @@ -73,6 +73,16 @@ For example:: > /path/to/app --syslog local0 > > > +Console timestamp > +~~~~~~~~~~~~~~~~~ > + > +On Linux and FreeBSD, an optional timestamp can be added before each > +message by adding the ``--log-timestamp`` option. i don't think Windows should be excluded from the feature, in general core libraries that get features should cover all platforms. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v10 08/10] eal: add option to put timestamp on console output 2024-03-21 17:11 ` Tyler Retzlaff @ 2024-03-21 17:16 ` Stephen Hemminger 2024-03-21 17:49 ` Tyler Retzlaff 0 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 17:16 UTC (permalink / raw) To: Tyler Retzlaff; +Cc: dev On Thu, 21 Mar 2024 10:11:31 -0700 Tyler Retzlaff <roretzla@linux.microsoft.com> wrote: > > > > > > +Console timestamp > > +~~~~~~~~~~~~~~~~~ > > + > > +On Linux and FreeBSD, an optional timestamp can be added before each > > +message by adding the ``--log-timestamp`` option. > > i don't think Windows should be excluded from the feature, in general > core libraries that get features should cover all platforms. The problem is that current Linux/FreeBSD log code depends on fopencookie() to work. I could not find a way to do that on Windows. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v10 08/10] eal: add option to put timestamp on console output 2024-03-21 17:16 ` Stephen Hemminger @ 2024-03-21 17:49 ` Tyler Retzlaff 2024-03-22 0:30 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-21 17:49 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Thu, Mar 21, 2024 at 10:16:36AM -0700, Stephen Hemminger wrote: > On Thu, 21 Mar 2024 10:11:31 -0700 > Tyler Retzlaff <roretzla@linux.microsoft.com> wrote: > > > > > > > > > > +Console timestamp > > > +~~~~~~~~~~~~~~~~~ > > > + > > > +On Linux and FreeBSD, an optional timestamp can be added before each > > > +message by adding the ``--log-timestamp`` option. > > > > i don't think Windows should be excluded from the feature, in general > > core libraries that get features should cover all platforms. > > The problem is that current Linux/FreeBSD log code depends on fopencookie() > to work. I could not find a way to do that on Windows. but that looks like it is part of general log initialization. surely when we are talking about logging a timestamp to a console we're just talking about a standard stream and a format string for Windows? i'll try to study more to gain a better understanding. thanks ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v10 08/10] eal: add option to put timestamp on console output 2024-03-21 17:49 ` Tyler Retzlaff @ 2024-03-22 0:30 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-22 0:30 UTC (permalink / raw) To: Tyler Retzlaff; +Cc: dev On Thu, 21 Mar 2024 10:49:06 -0700 Tyler Retzlaff <roretzla@linux.microsoft.com> wrote: > On Thu, Mar 21, 2024 at 10:16:36AM -0700, Stephen Hemminger wrote: > > On Thu, 21 Mar 2024 10:11:31 -0700 > > Tyler Retzlaff <roretzla@linux.microsoft.com> wrote: > > > > > > > > > > > > > > +Console timestamp > > > > +~~~~~~~~~~~~~~~~~ > > > > + > > > > +On Linux and FreeBSD, an optional timestamp can be added before each > > > > +message by adding the ``--log-timestamp`` option. > > > > > > i don't think Windows should be excluded from the feature, in general > > > core libraries that get features should cover all platforms. > > > > The problem is that current Linux/FreeBSD log code depends on fopencookie() > > to work. I could not find a way to do that on Windows. > > but that looks like it is part of general log initialization. surely > when we are talking about logging a timestamp to a console we're just > talking about a standard stream and a format string for Windows? > > i'll try to study more to gain a better understanding. > > thanks What the code does is take what rte_log created and add more data before actual printing it. The other option is doing this at rte_log() but that will break the syslog side. I am not sure that having log go directly to syslog makes sense anyway on a modern Linux system. If DPDK is being used by a daemon, that daemon will be a systemd service. And systemd has simple way to make stderr go to syslog. So if we drop the syslog support, then the whole thing gets more generic and simpler. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 09/10] log: colorize log output 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger ` (7 preceding siblings ...) 2024-03-21 16:00 ` [PATCH v10 08/10] eal: add option to put timestamp on console output Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 10/10] doc: add documentation of logging options Stephen Hemminger 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 10 +++ lib/eal/common/eal_options.h | 2 + lib/log/log_internal.h | 5 ++ lib/log/log_unix.c | 132 +++++++++++++++++++++++++--- lib/log/log_windows.c | 6 ++ lib/log/version.map | 1 + 6 files changed, 146 insertions(+), 10 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 4e2c3d0f255c..522634f1dcfa 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -78,6 +78,7 @@ eal_long_options[] = { {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_LOG_COLOR, 1, NULL, OPT_LOG_COLOR_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 }, @@ -1910,6 +1911,15 @@ 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; + case OPT_TRACE_NUM: { if (eal_trace_args_save(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53ca..5a63c1dd3a32 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -37,6 +37,8 @@ enum { OPT_LOG_LEVEL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_TRACE "trace" OPT_TRACE_NUM, #define OPT_TRACE_DIR "trace-dir" diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 0e18d147cf98..b90c668f4668 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -52,5 +52,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 */ diff --git a/lib/log/log_unix.c b/lib/log/log_unix.c index cb8f17bc83ef..1af93795fec5 100644 --- a/lib/log/log_unix.c +++ b/lib/log/log_unix.c @@ -11,6 +11,7 @@ #include <time.h> #include <unistd.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" @@ -24,15 +25,113 @@ enum eal_log_time_format { EAL_LOG_TIMESTAMP_ISO, }; +enum eal_log_color { + EAL_LOG_COLOR_AUTO = 0, /* default */ + EAL_LOG_COLOR_NEVER, + EAL_LOG_COLOR_ALWAYS, +}; + static struct { + enum eal_log_color color_mode; enum eal_log_time_format time_format; + bool show_color; struct timespec start_time; struct timespec last_time; struct tm last_tm; } log = { + .color_mode = EAL_LOG_COLOR_AUTO, .time_format = EAL_LOG_TIMESTAMP_NONE, }; +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR +}; + +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\e[31m", + [COLOR_GREEN] = "\e[32m", + [COLOR_YELLOW] = "\e[33m", + [COLOR_BLUE] = "\e[34m", + [COLOR_MAGENTA] = "\e[35m", + [COLOR_CYAN] = "\e[36m", + [COLOR_WHITE] = "\e[37m", + [COLOR_BOLD] = "\e[1m", + [COLOR_CLEAR] = "\e[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + + return ret; +} + +static ssize_t +color_log_write(FILE *f, int level, const char *msg, size_t size) +{ + size_t i; + ssize_t ret = 0; + + /* find first : delimiter in message */ + for (i = 0; i < size; i++) { + if (msg[i] == ':') { + ++i; /* put colon in the color */ + ret = color_fprintf(stderr, COLOR_YELLOW, "%.*s", (int)i, msg); + msg += i; + size -= i; + break; + } + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%.*s", (int)size, msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%.*s", (int)size, msg); + else + ret += color_fprintf(f, COLOR_RED, "%.*s", (int)size, msg); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log.color_mode = EAL_LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log.color_mode = EAL_LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log.color_mode = EAL_LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + int eal_log_timestamp(const char *str) { @@ -153,18 +252,28 @@ console_log_timestamp(char *tsbuf, size_t tsbuflen) static ssize_t console_log_write(__rte_unused void *c, const char *msg, size_t size) { - char buf[128]; + int level = rte_log_cur_msg_loglevel(); + char tsbuf[128] = ""; ssize_t ret; - ret = console_log_timestamp(buf, sizeof(buf)); - if (ret == 0) - ret = fwrite(msg, 1, size, stderr); - else - ret = fprintf(stderr, "[%s] %.*s", buf, (int)size, msg); + ret = console_log_timestamp(tsbuf, sizeof(tsbuf)); + if (ret == 0) { + if (log.show_color) + ret = color_log_write(stderr, level, msg, size); + else + ret = fwrite(msg, 1, size, stderr); + } else { + if (log.show_color) { + color_fprintf(stderr, COLOR_GREEN, "[%s] ", tsbuf); + ret = color_log_write(stderr, level, msg, size); + } else { + ret = fprintf(stderr, "[%s] %.*s", tsbuf, (int)size, msg); + } + } fflush(stderr); /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, msg); + syslog(level - 1, "%.*s", (int)size, msg); return ret; } @@ -190,13 +299,16 @@ eal_log_init(const char *id, int facility) { FILE *log_stream; - clock_gettime(CLOCK_MONOTONIC, &log.start_time); - log.last_time = log.start_time; - /* skip if user has already setup a log stream */ if (eal_log_get_default()) return 0; + log.show_color = (log.color_mode == EAL_LOG_COLOR_ALWAYS) || + (log.color_mode == EAL_LOG_COLOR_AUTO && isatty(STDERR_FILENO)); + + clock_gettime(CLOCK_MONOTONIC, &log.start_time); + log.last_time = log.start_time; + log_stream = fopencookie(NULL, "w+", console_log_func); if (log_stream == NULL) return -1; diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index 8aa68a181bec..1cb72f519a91 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -12,6 +12,12 @@ eal_log_timestamp(__rte_unused const char *fmt) return -1; /* not implemented */ } +int +eal_log_color(__rte_unused const char *mode) +{ + return -1; /* not implemented */ +} + /* set the log to default function, called during eal init process. */ int eal_log_init(__rte_unused const char *id, __rte_unused int facility) diff --git a/lib/log/version.map b/lib/log/version.map index 697cdb3cb1b2..1fe6955427b7 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_get_default; eal_log_init; eal_log_level2str; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v10 10/10] doc: add documentation of logging options 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger ` (8 preceding siblings ...) 2024-03-21 16:00 ` [PATCH v10 09/10] log: colorize log output Stephen Hemminger @ 2024-03-21 16:00 ` Stephen Hemminger 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-21 16:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Add documentation of new log-timestamp and log-color options. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/linux_gsg/eal_args.include.rst | 54 +++++++++++++++++++---- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/doc/guides/linux_gsg/eal_args.include.rst b/doc/guides/linux_gsg/eal_args.include.rst index 9cfbf7de8456..8ba54a62c0f9 100644 --- a/doc/guides/linux_gsg/eal_args.include.rst +++ b/doc/guides/linux_gsg/eal_args.include.rst @@ -122,6 +122,52 @@ Memory-related options to system pthread stack size unless the optional size (in kbytes) is specified. +Logging options +~~~~~~~~~~~~~~~ + +* ``--log-level <type:val>`` + + Specify log level for a specific component. For example:: + + --log-level lib.eal:debug + + Can be specified multiple times. + +* ``--log-facility=facility`` + + Specifies the ``syslog`` facility passed to ``openlog``. + The facility can be: ``auth``, ``cron``, ``daemon``, ``ftp``, + ``lpr``, ``mail``, ``news``, ``user``, ``uucp``, + ``local0``, ``local1``, ``local2``, ``local3``, ``local4``, + ``local5``, ``local6``, or ``local7``. The default if + no facility is specified is ``daemon``. + +* ``--log-timestamp[=format]`` + + Add a time stamp to log messages that are sent to the console (stderr). + When format argument is omitted the time stamp is elapsed + seconds since the start of the DPDK application. + Other formats are: + +.. 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]``" + +* ``--log-color[=when]`` + + Colorize the console output. + The optional argument ``when`` can be ``auto``, ``never`` or ``always``. + If the when argument is omitted, it defaults to ``auto``. + To disable use of color:: + + --log-color=none + + Debugging options ~~~~~~~~~~~~~~~~~ @@ -134,14 +180,6 @@ Debugging options Use anonymous memory instead of hugepages (implies no secondary process support). -* ``--log-level <type:val>`` - - Specify log level for a specific component. For example:: - - --log-level lib.eal:debug - - Can be specified multiple times. - * ``--trace=<regex-match>`` Enable trace based on regular expression trace name. By default, the trace is -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 0/9] Logging unification and enhancements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (9 preceding siblings ...) 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 1/9] windows: make getopt functions have const properties Stephen Hemminger ` (9 more replies) 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (18 subsequent siblings) 29 siblings, 10 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). 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. I find color helpful because 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. * Use of syslog on Linux is replaced by using journal API (over unix domain socket). This replaces legacy syslog; (almost) all Linux distros have switched to journal. Will add a release note in next release (after this is merged) v11 - rework to be portable to Windows drop syslog support and support journal instead Stephen Hemminger (9): windows: make getopt functions have const properties 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: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add support for systemd journal log: colorize log output app/test/test_eal_flags.c | 38 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 - .../prog_guide/env_abstraction_layer.rst | 5 +- doc/guides/prog_guide/log_lib.rst | 41 +- lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 123 ++--- lib/eal/common/eal_internal_cfg.h | 2 +- lib/eal/common/eal_options.h | 7 +- lib/eal/freebsd/eal.c | 54 +- lib/eal/linux/eal.c | 52 +- lib/eal/unix/eal_debug.c | 3 +- lib/eal/windows/eal.c | 39 +- lib/eal/windows/getopt.c | 23 +- lib/eal/windows/include/getopt.h | 8 +- lib/log/log.c | 513 ++++++++++++++++-- lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 16 +- lib/log/log_linux.c | 61 --- lib/log/log_windows.c | 18 - lib/log/meson.build | 5 +- lib/log/version.map | 2 + 21 files changed, 656 insertions(+), 404 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 1/9] windows: make getopt functions have const properties 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 2/9] eal: make eal_log_level_parse common Stephen Hemminger ` (8 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 2/9] eal: make eal_log_level_parse common 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 1/9] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 3/9] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (7 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..85171b2768 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 3/9] eal: do not duplicate rte_init_alert() messages 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 1/9] windows: make getopt functions have const properties Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 2/9] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 4/9] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (6 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 4/9] eal: change rte_exit() output to match rte_log() 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger ` (2 preceding siblings ...) 2024-03-24 2:33 ` [PATCH v11 3/9] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 5/9] log: drop syslog support, and make code common Stephen Hemminger ` (5 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev; +Cc: 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..3f37879144 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char *msg = NULL; 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); + vasprintf(&msg, format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 5/9] log: drop syslog support, and make code common 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger ` (3 preceding siblings ...) 2024-03-24 2:33 ` [PATCH v11 4/9] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 6/9] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Anatoly Burakov, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam This patch removes syslog support from logging. Which allows the logging code to all be common across Linux, Windows and FreeBSD. It also initializes log subsystem much earlier in the init process so that all messages get processed. It drops syslog was only used on Linux. Modern Linux systems have systemd and journal support. A later patch will add direct native journal support. Removing syslog means lots of other parts of the log system can be simplified and made portable. Remove the syslog tests and documentation as well. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 21 +------ doc/guides/linux_gsg/linux_eal_parameters.rst | 27 -------- .../prog_guide/env_abstraction_layer.rst | 5 +- doc/guides/prog_guide/log_lib.rst | 3 +- lib/eal/common/eal_common_options.c | 62 ------------------- lib/eal/common/eal_internal_cfg.h | 2 +- lib/eal/common/eal_options.h | 2 - lib/eal/freebsd/eal.c | 9 +-- lib/eal/linux/eal.c | 10 +-- lib/eal/unix/eal_debug.c | 3 +- lib/eal/windows/eal.c | 4 +- lib/log/log.c | 46 +++++--------- lib/log/log_freebsd.c | 12 ---- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 61 ------------------ lib/log/log_windows.c | 18 ------ lib/log/meson.build | 5 +- 17 files changed, 34 insertions(+), 258 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..bea5465168 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,17 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* 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 *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; - /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + /* 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}; - /* With --huge-dir */ const char *argv7[] = {prgname, "-m", DEFAULT_MEM_SIZE, "--file-prefix=hugedir", "--huge-dir", hugepath}; @@ -1079,18 +1072,6 @@ test_misc_flags(void) return 0; #endif - if (launch_proc(argv3) != 0) { - printf("Error - process did not run ok with --syslog flag\n"); - goto fail; - } - if (launch_proc(argv4) == 0) { - printf("Error - process run ok with empty --syslog flag\n"); - goto fail; - } - if (launch_proc(argv5) == 0) { - printf("Error - process run ok with invalid --syslog flag\n"); - goto fail; - } if (launch_proc(argv7) != 0) { printf("Error - process did not run ok with --huge-dir flag\n"); goto fail; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/env_abstraction_layer.rst b/doc/guides/prog_guide/env_abstraction_layer.rst index 9559c12a98..9a73628907 100644 --- a/doc/guides/prog_guide/env_abstraction_layer.rst +++ b/doc/guides/prog_guide/env_abstraction_layer.rst @@ -855,9 +855,8 @@ 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()`` calls library functions + that are not all signal safe. `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 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..17ed8426b2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -5,8 +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. +By default, log messages are sent to the stderr. However, the log function can be overridden by the user to use a different logging mechanism. Log Levels diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..73167d4603 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -93,7 +90,6 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -349,10 +345,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1289,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1880,16 +1831,6 @@ eal_parse_common_option(int opt, const char *optarg, } break; -#ifndef RTE_EXEC_ENV_WINDOWS - case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { - EAL_LOG(ERR, "invalid parameters for --" - OPT_SYSLOG); - return -1; - } - break; -#endif - case OPT_LOG_LEVEL_NUM: { if (eal_parse_log_level(optarg) < 0) { EAL_LOG(ERR, @@ -2259,9 +2200,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa..ed56a58b8b 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -84,7 +84,7 @@ 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 */ diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..6b204d6698 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -63,8 +63,6 @@ enum { OPT_SOCKET_MEM_NUM, #define OPT_SOCKET_LIMIT "socket-limit" OPT_SOCKET_LIMIT_NUM, -#define OPT_SYSLOG "syslog" - OPT_SYSLOG_NUM, #define OPT_VDEV "vdev" OPT_VDEV_NUM, #define OPT_VFIO_INTR "vfio-intr" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..d8628ba632 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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> @@ -563,12 +562,14 @@ rte_eal_init(int argc, char **argv) eal_reset_internal_config(internal_conf); - /* 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); + eal_log_init(getprogname()); + + /* clone argv to report out later in telemetry */ + eal_save_args(argc, argv); + if (rte_eal_cpu_init() < 0) { rte_eal_init_alert("Cannot detect lcores."); rte_errno = ENOTSUP; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..913ee62fc6 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -955,6 +955,8 @@ rte_eal_init(int argc, char **argv) /* set log level as early as possible */ eal_log_level_parse(argc, argv); + eal_log_init(program_invocation_short_name); + /* clone argv to report out later in telemetry */ eal_save_args(argc, argv); @@ -1106,14 +1108,6 @@ 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; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/unix/eal_debug.c b/lib/eal/unix/eal_debug.c index 69ba3758c2..c830cf7f05 100644 --- a/lib/eal/unix/eal_debug.c +++ b/lib/eal/unix/eal_debug.c @@ -43,8 +43,7 @@ static char *safe_itoa(long val, char *buf, size_t len, unsigned int radix) * used in this code since may be called from inside libc or * when malloc poll is corrupt. * - * Most of libc is therefore not safe, include RTE_LOG (calls syslog); - * backtrace_symbols (calls malloc), etc. + * Most of libc is therefore not safe including backtrace_symbols (calls malloc), etc. */ void rte_dump_stack(void) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 85171b2768..10f7cb840a 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,10 +250,10 @@ 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_level_parse(argc, argv); + eal_log_init(NULL); + if (eal_create_cpu_map() < 0) { rte_eal_init_alert("Cannot discover CPU and NUMA."); /* rte_errno is set */ diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..4c8666ac93 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -55,9 +55,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -76,6 +73,9 @@ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); int rte_openlog_stream(FILE *f) { + if (rte_logs.file != NULL) + fclose(rte_logs.file); + rte_logs.file = f; return 0; } @@ -85,17 +85,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -506,27 +496,25 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) } /* - * Called by environment-specific initialization functions. + * Called by eal_cleanup */ void -eal_log_set_default(FILE *default_log) +rte_eal_log_cleanup(void) { - default_log_stream = default_log; + FILE *f = rte_logs.file; -#if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG - RTE_LOG(NOTICE, EAL, - "Debug dataplane logs available - lower performance\n"); -#endif + if (f != NULL) { + fclose(f); + rte_logs.file = NULL; + } } -/* - * Called by eal_cleanup - */ +/* initialize logging */ void -rte_eal_log_cleanup(void) +eal_log_init(const char *id __rte_unused) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } +#if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG + RTE_LOG(NOTICE, EAL, + "Debug dataplane logs available - lower performance\n"); +#endif } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 698d3c5423..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -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; -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..4f1ffe999e 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 2dfb0c974b..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_log.h> - -#include "log_internal.h" - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -int -eal_log_init(const char *id, int facility) -{ - FILE *log_stream; - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - - openlog(id, LOG_NDELAY | LOG_PID, facility); - - eal_log_set_default(log_stream); - - return 0; -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index a6a0889550..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -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; -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 6/9] log: add hook for printing log messages 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger ` (4 preceding siblings ...) 2024-03-24 2:33 ` [PATCH v11 5/9] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 7/9] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. No functional changes in this patch, just infrastructure addition. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/log/log.c b/lib/log/log.c index 4c8666ac93..4cc871911c 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -26,16 +26,21 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); +static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ + 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 = log_print, }; struct rte_eal_opt_loglevel { @@ -67,8 +72,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -77,6 +80,7 @@ rte_openlog_stream(FILE *f) fclose(rte_logs.file); rte_logs.file = f; + rte_logs.print_func = log_print; return 0; } @@ -473,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, level, format, ap); fflush(f); return ret; } @@ -509,6 +513,15 @@ rte_eal_log_cleanup(void) } } +/* default log print function */ +__rte_format_printf(3, 0) +static int +log_print(FILE *f, uint32_t level __rte_unused, + const char *format, va_list ap) +{ + return vfprintf(f, format, ap); +} + /* initialize logging */ void eal_log_init(const char *id __rte_unused) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 7/9] log: add timestamp option 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger ` (5 preceding siblings ...) 2024-03-24 2:33 ` [PATCH v11 6/9] log: add hook for printing log messages Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 8/9] log: add support for systemd journal Stephen Hemminger ` (2 subsequent siblings) 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev; +Cc: 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 17 +++ doc/guides/prog_guide/log_lib.rst | 26 +++++ lib/eal/common/eal_common_options.c | 14 ++- lib/eal/common/eal_options.h | 2 + lib/log/log.c | 168 +++++++++++++++++++++++++++- lib/log/log_internal.h | 9 ++ lib/log/version.map | 1 + 7 files changed, 234 insertions(+), 3 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index bea5465168..def74e34d5 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1048,6 +1048,14 @@ 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" }; + /* run all tests also applicable to FreeBSD first */ if (launch_proc(argv0) == 0) { @@ -1143,6 +1151,15 @@ 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; + } + rmdir(hugepath_dir3); rmdir(hugepath_dir2); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 17ed8426b2..83949cce35 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -58,6 +58,32 @@ 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. +Console timestamp +~~~~~~~~~~~~~~~~~ + +An optional timestamp can be added before each message when printing on the console +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 73167d4603..bc6d87266d 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1614,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1831,7 +1833,7 @@ eal_parse_common_option(int opt, const char *optarg, } break; - case OPT_LOG_LEVEL_NUM: { + case OPT_LOG_LEVEL_NUM: if (eal_parse_log_level(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" @@ -1839,7 +1841,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: { @@ -2204,6 +2213,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" Timestamp log output\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_TRACE"=<regex-match>\n" " Enable trace based on regular expression trace name.\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 6b204d6698..197b7b25ef 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/log/log.c b/lib/log/log.c index 4cc871911c..bd488dff1b 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -11,6 +11,7 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -18,7 +19,7 @@ #include "log_internal.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -26,6 +27,15 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +enum eal_log_time_format { + EAL_LOG_TIMESTAMP_NONE = 0, + EAL_LOG_TIMESTAMP_TIME, /* time since start */ + EAL_LOG_TIMESTAMP_DELTA, /* time since last message */ + EAL_LOG_TIMESTAMP_RELTIME, + EAL_LOG_TIMESTAMP_CTIME, + EAL_LOG_TIMESTAMP_ISO, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -35,6 +45,12 @@ static struct rte_logs { uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ log_print_t print_func; + + enum eal_log_time_format time_format; + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ + struct tm last_tm; /* in local time format */ + size_t dynamic_types_len; struct rte_log_dynamic_type *dynamic_types; } rte_logs = { @@ -362,6 +378,9 @@ RTE_INIT_PRIO(log_init, LOG) { uint32_t i; + clock_gettime(CLOCK_MONOTONIC, &rte_logs.started); + rte_logs.previous = rte_logs.started; + rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -513,6 +532,132 @@ rte_eal_log_cleanup(void) } } +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + rte_logs.time_format = EAL_LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* Format up a timestamp based on current format */ +static ssize_t +format_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + struct tm *tm; + + switch (rte_logs.time_format) { + case EAL_LOG_TIMESTAMP_NONE: + return 0; + + case EAL_LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.previous); + rte_logs.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + tm = localtime(&now.tv_sec); + delta = timespec_sub(&now, &rte_logs.previous); + rte_logs.previous = now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != rte_logs +.last_tm.tm_min || + tm->tm_hour != rte_logs.last_tm.tm_hour || + tm->tm_yday != rte_logs.last_tm.tm_yday) { + rte_logs.last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%4lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } + + case EAL_LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case EAL_LOG_TIMESTAMP_ISO: { + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16]; /* "+0800" */ + + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + tm = localtime(&now.tv_sec); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +HH:MM */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + /* insert : required in ISO */ + memmove(zbuf + 3, zbuf + 4, 2); + zbuf[3] = ':'; + zbuf[6] = '\0'; + + return snprintf(tsbuf, tsbuflen, "%s,%06lu%s", + dbuf, now.tv_nsec / 1000u, zbuf); + } + } + + return 0; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -522,10 +667,31 @@ log_print(FILE *f, uint32_t level __rte_unused, return vfprintf(f, format, ap); } +/* print timestamp before message */ +__rte_format_printf(3, 0) +static int +log_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + fprintf(f, "[%s] ", tsbuf); + + return log_print(f, level, format, ap); +} + /* initialize logging */ void eal_log_init(const char *id __rte_unused) { + /* skip if user has already setup a log stream */ + if (rte_logs.file != NULL) + return; + + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print_with_timestamp; + #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 4f1ffe999e..3544ae49ac 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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> @@ -42,4 +44,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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..7fd5b39e3a 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 8/9] log: add support for systemd journal 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger ` (6 preceding siblings ...) 2024-03-24 2:33 ` [PATCH v11 7/9] log: add timestamp option Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 9/9] log: colorize log output Stephen Hemminger 2024-03-24 11:18 ` [PATCH v11 0/9] Logging unification and enhancements Mattias Rönnblom 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev; +Cc: 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/ The journal protocol supports more information that could be added later. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 5 deletions(-) diff --git a/lib/log/log.c b/lib/log/log.c index bd488dff1b..4cfa160e3b 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -13,15 +13,20 @@ #include <sys/queue.h> #include <unistd.h> +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#else +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> +#endif + #include <rte_log.h> #include <rte_per_lcore.h> #include "log_internal.h" -#ifdef RTE_EXEC_ENV_WINDOWS -#include <rte_os_shim.h> -#endif - struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -39,11 +44,13 @@ enum eal_log_time_format { typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ + int journal_fd; /**< Journal file descriptor if using */ log_print_t print_func; enum eal_log_time_format time_format; @@ -681,6 +688,116 @@ log_print_with_timestamp(FILE *f, uint32_t level, return log_print(f, level, format, ap); } +#ifdef RTE_EXEC_ENV_LINUX +/* + * send message using journal protocol to journald + */ +__rte_format_printf(3, 0) +static int +journal_print(FILE *f __rte_unused, uint32_t level, const char *format, va_list ap) +{ + struct iovec iov[3]; + char *buf = NULL; + size_t len; + char msg[] = "MESSAGE="; + char *prio; + + iov[0].iov_base = msg; + iov[0].iov_len = strlen(msg); + + len = vasprintf(&buf, format, ap); + if (len == 0) + return 0; + + /* check that message ends with newline */ + if (buf[len - 1] != '\n') { + char *clone = alloca(len + 1); + if (clone == NULL) + return 0; + memcpy(clone, buf, len); + clone[len++] = '\n'; + buf = clone; + } + + iov[1].iov_base = buf; + iov[1].iov_len = len; + + /* priority value between 0 ("emerg") and 7 ("debug") */ + len = asprintf(&prio, "PRIORITY=%i\n", level - 1); + iov[2].iov_base = prio; + iov[2].iov_len = len; + + return writev(rte_logs.journal_fd, iov, 3); +} + +static void +journal_send_id(int fd, const char *id) +{ + char *syslog_id = NULL; + size_t len; + + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\n", id); + if (len > 0) + write(fd, syslog_id, len); + +} + +/* + * Check if stderr is going to system journal. + * This is the documented way to handle systemd journal + * + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +using_journal(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; +} + +/* + * If we are being run as systemd service and stderr is going to journal + * then upgrade to use journal protocol. + */ +static int +open_journal(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) + return -1; + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + close(s); + return -1; + } + return s; +} +#endif + /* initialize logging */ void eal_log_init(const char *id __rte_unused) @@ -689,8 +806,22 @@ eal_log_init(const char *id __rte_unused) if (rte_logs.file != NULL) return; - if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) +#ifdef RTE_EXEC_ENV_LINUX + if (using_journal()) { + int jfd = open_journal(); + + if (jfd < 0) { + RTE_LOG_LINE(NOTICE, EAL, "Cannot connect to journal"); + } else { + rte_logs.journal_fd = jfd; + rte_logs.print_func = journal_print; + journal_send_id(jfd, id); + } + } else +#endif + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) { rte_logs.print_func = log_print_with_timestamp; + } #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v11 9/9] log: colorize log output 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger ` (7 preceding siblings ...) 2024-03-24 2:33 ` [PATCH v11 8/9] log: add support for systemd journal Stephen Hemminger @ 2024-03-24 2:33 ` Stephen Hemminger 2024-03-24 11:18 ` [PATCH v11 0/9] Logging unification and enhancements Mattias Rönnblom 9 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-24 2:33 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/prog_guide/log_lib.rst | 14 ++- lib/eal/common/eal_common_options.c | 1 + lib/eal/common/eal_options.h | 2 + lib/log/log.c | 153 +++++++++++++++++++++++++++- lib/log/log_internal.h | 5 + lib/log/version.map | 1 + 6 files changed, 173 insertions(+), 3 deletions(-) diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 83949cce35..e0cb9bb9ed 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -58,6 +58,19 @@ 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. +Color output +~~~~~~~~~~~~ + +It is useful ot be able see important messages highlighted. This is controlled by the +``--log-color`` option. The optional argument ``when`` can be ``auto``, ``never``, +or ``always``.The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Console timestamp ~~~~~~~~~~~~~~~~~ @@ -83,7 +96,6 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso - Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index bc6d87266d..0da6729c64 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -75,6 +75,7 @@ eal_long_options[] = { {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_LOG_COLOR, 1, NULL, OPT_LOG_COLOR_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 }, diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 197b7b25ef..c1696d75e5 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -37,6 +37,8 @@ enum { OPT_LOG_LEVEL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_TRACE "trace" OPT_TRACE_NUM, #define OPT_TRACE_DIR "trace-dir" diff --git a/lib/log/log.c b/lib/log/log.c index 4cfa160e3b..e75ed804ec 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -22,6 +22,7 @@ #include <sys/un.h> #endif +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -41,6 +42,12 @@ enum eal_log_time_format { EAL_LOG_TIMESTAMP_ISO, }; +enum eal_log_color { + EAL_LOG_COLOR_AUTO = 0, /* default */ + EAL_LOG_COLOR_NEVER, + EAL_LOG_COLOR_ALWAYS, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -53,6 +60,7 @@ static struct rte_logs { int journal_fd; /**< Journal file descriptor if using */ log_print_t print_func; + enum eal_log_color color_mode; enum eal_log_time_format time_format; struct timespec started; /* when log was initialized */ struct timespec previous; /* when last msg was printed */ @@ -665,6 +673,74 @@ format_timestamp(char *tsbuf, size_t tsbuflen) return 0; } +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR +}; + +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\e[31m", + [COLOR_GREEN] = "\e[32m", + [COLOR_YELLOW] = "\e[33m", + [COLOR_BLUE] = "\e[34m", + [COLOR_MAGENTA] = "\e[35m", + [COLOR_CYAN] = "\e[36m", + [COLOR_WHITE] = "\e[37m", + [COLOR_BOLD] = "\e[1m", + [COLOR_CLEAR] = "\e[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + + return ret; +} + +static ssize_t +color_log_write(FILE *f, int level, char *msg) +{ + char *cp; + ssize_t ret = 0; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(stderr, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -688,6 +764,70 @@ log_print_with_timestamp(FILE *f, uint32_t level, return log_print(f, level, format, ap); } +__rte_format_printf(3, 0) +static int +color_print(FILE *f, uint32_t level, const char *format, va_list ap) +{ + char *buf = NULL; + + /* need to make temporary buffer for color scan */ + if (vasprintf(&buf, format, ap) > 0) + return color_log_write(f, level, buf); + + /* if vasprintf fails, print without color */ + return log_print(f, level, format, ap); +} + +__rte_format_printf(3, 0) +static int +color_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, level, format, ap); +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +static bool +use_color(int out_fd) +{ + switch (rte_logs.color_mode) { + default: + case EAL_LOG_COLOR_NEVER: + return false; + case EAL_LOG_COLOR_ALWAYS: + return true; + case EAL_LOG_COLOR_AUTO: + return !!isatty(out_fd); + } + +} + #ifdef RTE_EXEC_ENV_LINUX /* * send message using journal protocol to journald @@ -817,10 +957,19 @@ eal_log_init(const char *id __rte_unused) rte_logs.print_func = journal_print; journal_send_id(jfd, id); } + } else #endif - if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) { - rte_logs.print_func = log_print_with_timestamp; + if (use_color(STDERR_FILENO)) { + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = color_print_with_timestamp; + else + rte_logs.print_func = color_print; + } else { + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print_with_timestamp; + else + rte_logs.print_func = log_print; } #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3544ae49ac..5b8bb6ffc9 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 7fd5b39e3a..9ca561b05b 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v11 0/9] Logging unification and enhancements 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger ` (8 preceding siblings ...) 2024-03-24 2:33 ` [PATCH v11 9/9] log: colorize log output Stephen Hemminger @ 2024-03-24 11:18 ` Mattias Rönnblom 9 siblings, 0 replies; 445+ messages in thread From: Mattias Rönnblom @ 2024-03-24 11:18 UTC (permalink / raw) To: Stephen Hemminger, dev On 2024-03-24 03:33, Stephen Hemminger wrote: > Improvements and unification of logging library (for 24.07 release). > 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. > > I find color helpful because 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. > > * Use of syslog on Linux is replaced by using journal > API (over unix domain socket). This replaces legacy syslog; > (almost) all Linux distros have switched to journal. > Is "switched to journal" the same as "switched to systemd", or are there non-systemd journal API implementations? I'm guessing there are quite a few Linux-based embedded systems that doesn't use systemd. Ideally, you would like to have journal as the Linux default, and then syslog as a build-time option. > Will add a release note in next release (after this is merged) > > v11 - rework to be portable to Windows > drop syslog support and support journal instead > > Stephen Hemminger (9): > windows: make getopt functions have const properties > 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: drop syslog support, and make code common > log: add hook for printing log messages > log: add timestamp option > log: add support for systemd journal > log: colorize log output > > app/test/test_eal_flags.c | 38 +- > doc/guides/linux_gsg/linux_eal_parameters.rst | 27 - > .../prog_guide/env_abstraction_layer.rst | 5 +- > doc/guides/prog_guide/log_lib.rst | 41 +- > lib/eal/common/eal_common_debug.c | 11 +- > lib/eal/common/eal_common_options.c | 123 ++--- > lib/eal/common/eal_internal_cfg.h | 2 +- > lib/eal/common/eal_options.h | 7 +- > lib/eal/freebsd/eal.c | 54 +- > lib/eal/linux/eal.c | 52 +- > lib/eal/unix/eal_debug.c | 3 +- > lib/eal/windows/eal.c | 39 +- > lib/eal/windows/getopt.c | 23 +- > lib/eal/windows/include/getopt.h | 8 +- > lib/log/log.c | 513 ++++++++++++++++-- > lib/log/log_freebsd.c | 12 - > lib/log/log_internal.h | 16 +- > lib/log/log_linux.c | 61 --- > lib/log/log_windows.c | 18 - > lib/log/meson.build | 5 +- > lib/log/version.map | 2 + > 21 files changed, 656 insertions(+), 404 deletions(-) > delete mode 100644 lib/log/log_freebsd.c > delete mode 100644 lib/log/log_linux.c > delete mode 100644 lib/log/log_windows.c > ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 00/14] Logging unification and enhancements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (10 preceding siblings ...) 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger @ 2024-03-25 20:46 ` Stephen Hemminger 2024-03-25 20:46 ` [PATCH v12 01/14] windows: make getopt functions have const properties Stephen Hemminger ` (13 more replies) 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger ` (17 subsequent siblings) 29 siblings, 14 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:46 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). 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. I find color helpful because 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 syslog. Add myself as maintainer for log because by now have added more than previous authors... Will add a release note in next release (after this is merged) v12 - add back syslog but make it optional. better shims for windows (thread safe) split out more of the eal core bits fix build warnings on FreeBSD and Ubuntu Stephen Hemminger (14): windows: make getopt functions have const properties windows: add os shim for localtime_r 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog log: add support for systemd journal log: colorize log output maintainers: add for log library MAINTAINERS | 1 + app/test/test_eal_flags.c | 17 + doc/guides/linux_gsg/linux_eal_parameters.rst | 27 - doc/guides/prog_guide/log_lib.rst | 57 ++ lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 114 ++-- lib/eal/common/eal_options.h | 5 + lib/eal/freebsd/eal.c | 60 +- lib/eal/linux/eal.c | 64 +- lib/eal/windows/eal.c | 44 +- 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 | 594 +++++++++++++++++- lib/log/log_freebsd.c | 5 +- lib/log/log_internal.h | 25 +- lib/log/log_linux.c | 61 -- lib/log/log_windows.c | 18 - lib/log/meson.build | 5 +- lib/log/version.map | 4 +- 20 files changed, 803 insertions(+), 350 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 01/14] windows: make getopt functions have const properties 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger @ 2024-03-25 20:46 ` Stephen Hemminger 2024-03-25 20:46 ` [PATCH v12 02/14] windows: add os shim for localtime_r Stephen Hemminger ` (12 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:46 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 02/14] windows: add os shim for localtime_r 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger 2024-03-25 20:46 ` [PATCH v12 01/14] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-25 20:46 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 03/14] eal: make eal_log_level_parse common Stephen Hemminger ` (11 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:46 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 03/14] eal: make eal_log_level_parse common 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger 2024-03-25 20:46 ` [PATCH v12 01/14] windows: make getopt functions have const properties Stephen Hemminger 2024-03-25 20:46 ` [PATCH v12 02/14] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 04/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (10 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..85171b2768 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 04/14] eal: do not duplicate rte_init_alert() messages 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (2 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 03/14] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 05/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (9 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 05/14] eal: change rte_exit() output to match rte_log() 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (3 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 04/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-27 7:17 ` Tyler Retzlaff 2024-03-25 20:47 ` [PATCH v12 06/14] log: move handling of syslog facility out of eal Stephen Hemminger ` (8 subsequent siblings) 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev; +Cc: 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..3f37879144 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char *msg = NULL; 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); + vasprintf(&msg, format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v12 05/14] eal: change rte_exit() output to match rte_log() 2024-03-25 20:47 ` [PATCH v12 05/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-27 7:17 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-27 7:17 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Mon, Mar 25, 2024 at 01:47:02PM -0700, Stephen Hemminger wrote: > 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: Cause - Cannot init EAL: Permission denied > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 06/14] log: move handling of syslog facility out of eal 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (4 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 05/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 07/14] eal: initialize log before everything else Stephen Hemminger ` (7 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 9 files changed, 68 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..661b2db211 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 85171b2768..2519a30017 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 07/14] eal: initialize log before everything else 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (5 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 06/14] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 08/14] log: drop syslog support, and make code common Stephen Hemminger ` (6 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 8 +++++--- lib/eal/linux/eal.c | 15 +++++---------- lib/eal/windows/eal.c | 3 +-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 20 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..ec3a0c3244 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,10 @@ rte_eal_init(int argc, char **argv) bool has_phys_addr; enum rte_iova_mode iova_mode; + /* setup log as early as possible */ + eal_log_level_parse(argc, argv); + eal_log_init(getprogname()); + /* checks if the machine is adequate */ if (!rte_cpu_is_supported()) { rte_eal_init_alert("unsupported cpu type."); @@ -565,9 +570,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..0a488ee567 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,11 @@ rte_eal_init(int argc, char **argv) struct internal_config *internal_conf = eal_get_internal_configuration(); + + /* setup log as early as possible */ + eal_log_level_parse(argc, argv); + 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."); @@ -952,9 +957,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); @@ -1106,13 +1108,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 2519a30017..fb2920e1b8 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,8 @@ 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); - 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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 08/14] log: drop syslog support, and make code common 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (6 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 07/14] eal: initialize log before everything else Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 09/14] log: add hook for printing log messages Stephen Hemminger ` (5 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 29 ++++++++---- lib/log/log_internal.h | 6 --- lib/log/log_linux.c | 102 ----------------------------------------- lib/log/log_windows.c | 22 --------- lib/log/meson.build | 5 +- lib/log/version.map | 1 - 6 files changed, 21 insertions(+), 144 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..f597da2e39 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -70,12 +70,13 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) { + if (rte_logs.file != NULL) + fclose(rte_logs.file); + rte_logs.file = f; return 0; } @@ -505,13 +506,20 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -525,8 +533,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_log_get_stream(); + + /* don't close stderr on the application */ + if (log_stream != stderr) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 09/14] log: add hook for printing log messages 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (7 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 08/14] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 10/14] log: add timestamp option Stephen Hemminger ` (4 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index f597da2e39..acd4c320b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -26,16 +26,21 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); +static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ + 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 = log_print, }; struct rte_eal_opt_loglevel { @@ -78,6 +83,7 @@ rte_openlog_stream(FILE *f) fclose(rte_logs.file); rte_logs.file = f; + rte_logs.print_func = log_print; return 0; } @@ -484,7 +490,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, level, format, ap); fflush(f); return ret; } @@ -513,6 +519,15 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* default log print function */ +__rte_format_printf(3, 0) +static int +log_print(FILE *f, uint32_t level __rte_unused, + const char *format, va_list ap) +{ + return vfprintf(f, format, ap); +} + /* * Called by rte_eal_init */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 10/14] log: add timestamp option 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (8 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 09/14] log: add hook for printing log messages Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 11/14] log: add optional support of syslog Stephen Hemminger ` (3 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 17 +++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 183 +++++++++++++++++++++++++++- lib/log/log_internal.h | 9 ++ lib/log/version.map | 1 + 10 files changed, 259 insertions(+), 7 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..eeb1799381 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1055,6 +1055,14 @@ 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" }; + /* run all tests also applicable to FreeBSD first */ if (launch_proc(argv0) == 0) { @@ -1162,6 +1170,15 @@ 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; + } + rmdir(hugepath_dir3); rmdir(hugepath_dir2); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 661b2db211..aa1faad45c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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: { @@ -2219,6 +2228,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" Timestamp log output\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_TRACE"=<regex-match>\n" " Enable trace based on regular expression trace name.\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index ec3a0c3244..8f41c47f47 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 0a488ee567..16aaefe355 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index fb2920e1b8..bff1316e0b 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index acd4c320b6..2dca91306e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -11,6 +11,7 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -18,7 +19,7 @@ #include "log_internal.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -26,6 +27,15 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +enum eal_log_time_format { + EAL_LOG_TIMESTAMP_NONE = 0, + EAL_LOG_TIMESTAMP_TIME, /* time since start */ + EAL_LOG_TIMESTAMP_DELTA, /* time since last message */ + EAL_LOG_TIMESTAMP_RELTIME, + EAL_LOG_TIMESTAMP_CTIME, + EAL_LOG_TIMESTAMP_ISO, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -35,6 +45,11 @@ static struct rte_logs { uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ log_print_t print_func; + + enum eal_log_time_format time_format; + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ + size_t dynamic_types_len; struct rte_log_dynamic_type *dynamic_types; } rte_logs = { @@ -375,6 +390,9 @@ RTE_INIT_PRIO(log_init, LOG) { uint32_t i; + clock_gettime(CLOCK_MONOTONIC, &rte_logs.started); + rte_logs.previous = rte_logs.started; + rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -519,6 +537,152 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + rte_logs.time_format = EAL_LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + + +/* Format current timespec into ISO8601 format */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &rte_logs.previous); + rte_logs.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +static ssize_t +format_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (rte_logs.time_format) { + case EAL_LOG_TIMESTAMP_NONE: + return 0; + + case EAL_LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.previous); + rte_logs.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case EAL_LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case EAL_LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -528,12 +692,29 @@ log_print(FILE *f, uint32_t level __rte_unused, return vfprintf(f, format, ap); } +/* print timestamp before message */ +__rte_format_printf(3, 0) +static int +log_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + fprintf(f, "[%s] ", tsbuf); + + return log_print(f, level, format, ap); +} + /* * Called by rte_eal_init */ void eal_log_init(const char *id __rte_unused) { + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print_with_timestamp; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 11/14] log: add optional support of syslog 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (9 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 10/14] log: add timestamp option Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 12/14] log: add support for systemd journal Stephen Hemminger ` (2 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ----- doc/guides/prog_guide/log_lib.rst | 17 +++ lib/eal/common/eal_common_options.c | 2 +- lib/log/log.c | 101 ++++++++++++++++-- 4 files changed, 111 insertions(+), 36 deletions(-) diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index aa1faad45c..6f0fd151c1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, diff --git a/lib/log/log.c b/lib/log/log.c index 2dca91306e..d8974c66db 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -13,15 +13,17 @@ #include <sys/queue.h> #include <unistd.h> +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#else +#include <syslog.h> +#endif + #include <rte_log.h> #include <rte_per_lcore.h> #include "log_internal.h" -#ifdef RTE_EXEC_ENV_WINDOWS -#include <rte_os_shim.h> -#endif - struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -36,14 +38,25 @@ enum eal_log_time_format { EAL_LOG_TIMESTAMP_ISO, }; +enum eal_log_syslog { + EAL_LOG_SYSLOG_NONE = 0, /* do not use syslog */ + EAL_LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + EAL_LOG_SYSLOG_ALWAYS, /* always use syslog */ + EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ +#ifndef RTE_EXEC_ENV_WINDOWS + enum eal_log_syslog syslog_opt; +#endif log_print_t print_func; enum eal_log_time_format time_format; @@ -532,9 +545,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) /* Placeholder */ int -eal_log_syslog(const char *mode __rte_unused) +eal_log_syslog(const char *str) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(str); return -1; +#else + if (str == NULL || strcmp(str, "auto") == 0) + /* log to syslog only if stderr is not a terminal */ + rte_logs.syslog_opt = EAL_LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +#endif } /* Set the log timestamp format */ @@ -706,17 +733,75 @@ log_print_with_timestamp(FILE *f, uint32_t level, return log_print(f, level, format, ap); } +#ifndef RTE_EXEC_ENV_WINDOWS /* - * Called by rte_eal_init + * wrapper for log stream to put messages into syslog + * useful for cases like: + * rte_hex_dump(rte_get_log_stream(), ...) */ -void -eal_log_init(const char *id __rte_unused) +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) { + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; +#endif + + +/* Choose how log output is directed */ +static void +log_output_selection(const char *id) +{ + RTE_SET_USED(id); + +#ifndef RTE_EXEC_ENV_WINDOWS + bool is_terminal = isatty(STDERR_FILENO); + + if (!(rte_logs.syslog_opt == EAL_LOG_SYSLOG_NONE || + (rte_logs.syslog_opt == EAL_LOG_SYSLOG_AUTO && is_terminal))) { + int flags = LOG_NDELAY | LOG_PID; + +#ifdef LOG_PERROR + if (rte_logs.syslog_opt == EAL_LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; +#endif + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; + return; + } +#endif if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) rte_logs.print_func = log_print_with_timestamp; +} +/* + * Called by rte_eal_init + */ +void +eal_log_init(const char *id) +{ + rte_logs.print_func = log_print; default_log_stream = stderr; + log_output_selection(id); + #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 12/14] log: add support for systemd journal 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (10 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 11/14] log: add optional support of syslog Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 13/14] log: colorize log output Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 14/14] maintainers: add for log library Stephen Hemminger 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev; +Cc: 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/lib/log/log.c b/lib/log/log.c index d8974c66db..0f7bdb3f25 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -17,6 +17,10 @@ #include <rte_os_shim.h> #else #include <syslog.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> #endif #include <rte_log.h> @@ -56,6 +60,7 @@ static struct rte_logs { FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ #ifndef RTE_EXEC_ENV_WINDOWS enum eal_log_syslog syslog_opt; + int journal_fd; #endif log_print_t print_func; @@ -758,6 +763,112 @@ static cookie_io_functions_t syslog_log_func = { .write = syslog_log_write, .close = syslog_log_close, }; + + +/* + * send message using journal protocol to journald + */ +__rte_format_printf(3, 0) +static int +journal_print(FILE *f __rte_unused, uint32_t level, const char *format, va_list ap) +{ + struct iovec iov[3]; + char *buf = NULL; + size_t len; + char msg[] = "MESSAGE="; + char *prio; + + iov[0].iov_base = msg; + iov[0].iov_len = strlen(msg); + + len = vasprintf(&buf, format, ap); + if (len == 0) + return 0; + + /* check that message ends with newline, if not add one */ + if (buf[len - 1] != '\n') { + char *clone = alloca(len + 1); + if (clone == NULL) + return 0; + memcpy(clone, buf, len); + clone[len++] = '\n'; + buf = clone; + } + + iov[1].iov_base = buf; + iov[1].iov_len = len; + + /* priority value between 0 ("emerg") and 7 ("debug") */ + len = asprintf(&prio, "PRIORITY=%i\n", level - 1); + iov[2].iov_base = prio; + iov[2].iov_len = len; + + return writev(rte_logs.journal_fd, iov, 3); +} + +/* + * Check if stderr is going to system journal. + * This is the documented way to handle systemd journal + * + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +using_journal(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 */ +static int +open_journal(const char *id) +{ + char *syslog_id = NULL; + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + ssize_t len; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) + return -1; + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) + goto error; + + /* Send syslog identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\n", id); + if (len == 0) + goto error; + + if (write(s, syslog_id, len) != len) + goto error; + + return s; +error: + close(s); + return -1; +} #endif @@ -765,11 +876,24 @@ static cookie_io_functions_t syslog_log_func = { static void log_output_selection(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); - -#ifndef RTE_EXEC_ENV_WINDOWS +#else bool is_terminal = isatty(STDERR_FILENO); + /* If stderr is redirected to systemd journal then upgrade */ + if (using_journal()) { + int jfd = open_journal(id); + + if (jfd < 0) { + RTE_LOG_LINE(NOTICE, EAL, "Cannot connect to journal: %s", + strerror(errno)); + } else { + rte_logs.print_func = journal_print; + return; + } + } + if (!(rte_logs.syslog_opt == EAL_LOG_SYSLOG_NONE || (rte_logs.syslog_opt == EAL_LOG_SYSLOG_AUTO && is_terminal))) { int flags = LOG_NDELAY | LOG_PID; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 13/14] log: colorize log output 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (11 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 12/14] log: add support for systemd journal Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 14/14] maintainers: add for log library Stephen Hemminger 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/prog_guide/log_lib.rst | 16 ++- lib/eal/common/eal_common_options.c | 1 + lib/eal/common/eal_options.h | 2 + lib/log/log.c | 158 +++++++++++++++++++++++++++- lib/log/log_internal.h | 5 + lib/log/version.map | 1 + 6 files changed, 178 insertions(+), 5 deletions(-) diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..40727ebaae 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ @@ -101,7 +116,6 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. - Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 6f0fd151c1..23b536b7a0 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -75,6 +75,7 @@ eal_long_options[] = { {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_LOG_COLOR, 1, NULL, OPT_LOG_COLOR_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 }, diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..5a63c1dd3a 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -37,6 +37,8 @@ enum { OPT_LOG_LEVEL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_TRACE "trace" OPT_TRACE_NUM, #define OPT_TRACE_DIR "trace-dir" diff --git a/lib/log/log.c b/lib/log/log.c index 0f7bdb3f25..26a63024be 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -23,6 +23,7 @@ #include <sys/un.h> #endif +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -49,6 +50,12 @@ enum eal_log_syslog { EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ }; +enum eal_log_color { + EAL_LOG_COLOR_AUTO = 0, /* default */ + EAL_LOG_COLOR_NEVER, + EAL_LOG_COLOR_ALWAYS, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -64,6 +71,7 @@ static struct rte_logs { #endif log_print_t print_func; + enum eal_log_color color_mode; enum eal_log_time_format time_format; struct timespec started; /* when log was initialized */ struct timespec previous; /* when last msg was printed */ @@ -715,6 +723,74 @@ format_timestamp(char *tsbuf, size_t tsbuflen) return 0; } +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR +}; + +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\e[31m", + [COLOR_GREEN] = "\e[32m", + [COLOR_YELLOW] = "\e[33m", + [COLOR_BLUE] = "\e[34m", + [COLOR_MAGENTA] = "\e[35m", + [COLOR_CYAN] = "\e[36m", + [COLOR_WHITE] = "\e[37m", + [COLOR_BOLD] = "\e[1m", + [COLOR_CLEAR] = "\e[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + + return ret; +} + +static ssize_t +color_log_write(FILE *f, int level, char *msg) +{ + char *cp; + ssize_t ret = 0; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(stderr, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -871,16 +947,79 @@ open_journal(const char *id) } #endif +__rte_format_printf(3, 0) +static int +color_print(FILE *f, uint32_t level, const char *format, va_list ap) +{ + char *buf = NULL; + + /* need to make temporary buffer for color scan */ + if (vasprintf(&buf, format, ap) > 0) + return color_log_write(f, level, buf); + + /* if vasprintf fails, print without color */ + return log_print(f, level, format, ap); +} + +__rte_format_printf(3, 0) +static int +color_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, level, format, ap); +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +static inline bool +use_color(bool is_terminal) +{ + switch (rte_logs.color_mode) { + default: + case EAL_LOG_COLOR_NEVER: + return false; + case EAL_LOG_COLOR_ALWAYS: + return true; + case EAL_LOG_COLOR_AUTO: + return is_terminal; + } + +} /* Choose how log output is directed */ static void log_output_selection(const char *id) { + bool is_terminal = isatty(STDERR_FILENO); + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); #else - bool is_terminal = isatty(STDERR_FILENO); - /* If stderr is redirected to systemd journal then upgrade */ if (using_journal()) { int jfd = open_journal(id); @@ -911,8 +1050,19 @@ log_output_selection(const char *id) return; } #endif - if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) - rte_logs.print_func = log_print_with_timestamp; + + if (use_color(is_terminal)) { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = color_print; + else + rte_logs.print_func = color_print_with_timestamp; + } else { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print; + else + rte_logs.print_func = log_print_with_timestamp; + } + } /* diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..525e1397fd 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -47,5 +47,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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 14d6681a5f..7fa79b20ff 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v12 14/14] maintainers: add for log library 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger ` (12 preceding siblings ...) 2024-03-25 20:47 ` [PATCH v12 13/14] log: colorize log output Stephen Hemminger @ 2024-03-25 20:47 ` Stephen Hemminger 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-25 20:47 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7abb3aee49..54c28a601d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 00/11] Logging unification and improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (11 preceding siblings ...) 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger @ 2024-03-26 1:56 ` Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 01/11] windows: make getopt functions have const properties Stephen Hemminger ` (10 more replies) 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (16 subsequent siblings) 29 siblings, 11 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). 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. I find color helpful because 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 syslog. Add myself as maintainer for log because by now have added more than previous authors... Will add a release note in next release (after this is merged) v13 - fix functional tests and warnings about unused result v12 - add back syslog but make it optional. better shims for windows (thread safe) split out more of the eal core bits fix build warnings on FreeBSD and Ubuntu Stephen Hemminger (11): windows: make getopt functions have const properties windows: add os shim for localtime_r 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog app/test/test_eal_flags.c | 40 ++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 -- doc/guides/prog_guide/log_lib.rst | 43 +++ lib/eal/common/eal_common_debug.c | 10 +- lib/eal/common/eal_common_options.c | 116 ++++--- lib/eal/common/eal_options.h | 3 + lib/eal/freebsd/eal.c | 64 +--- lib/eal/linux/eal.c | 68 +--- lib/eal/windows/eal.c | 49 +-- 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 | 320 +++++++++++++++++- lib/log/log_freebsd.c | 5 +- lib/log/log_internal.h | 20 +- lib/log/log_linux.c | 61 ---- lib/log/log_windows.c | 18 - lib/log/meson.build | 5 +- lib/log/version.map | 3 +- 19 files changed, 533 insertions(+), 360 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 01/11] windows: make getopt functions have const properties 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger @ 2024-03-26 1:56 ` Stephen Hemminger 2024-03-26 9:35 ` Morten Brørup 2024-03-26 1:56 ` [PATCH v13 02/11] windows: add os shim for localtime_r Stephen Hemminger ` (9 subsequent siblings) 10 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v13 01/11] windows: make getopt functions have const properties 2024-03-26 1:56 ` [PATCH v13 01/11] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-26 9:35 ` Morten Brørup 0 siblings, 0 replies; 445+ messages in thread From: Morten Brørup @ 2024-03-26 9:35 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > Sent: Tuesday, 26 March 2024 02.57 > > 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. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> > --- For the series, Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 02/11] windows: add os shim for localtime_r 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 01/11] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-26 1:56 ` Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 03/11] eal: make eal_log_level_parse common Stephen Hemminger ` (8 subsequent siblings) 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 03/11] eal: make eal_log_level_parse common 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 01/11] windows: make getopt functions have const properties Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 02/11] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-26 1:56 ` Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 04/11] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (7 subsequent siblings) 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:56 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..85171b2768 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 04/11] eal: do not duplicate rte_init_alert() messages 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-03-26 1:56 ` [PATCH v13 03/11] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-26 1:56 ` Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 05/11] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (6 subsequent siblings) 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 05/11] eal: change rte_exit() output to match rte_log() 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-03-26 1:56 ` [PATCH v13 04/11] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-26 1:57 ` Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 06/11] log: move handling of syslog facility out of eal Stephen Hemminger ` (5 subsequent siblings) 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:57 UTC (permalink / raw) To: dev; +Cc: 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_debug.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..71bb5a7d34 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,17 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char *msg = NULL; 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); + if (vasprintf(&msg, format, ap) > 0) + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 06/11] log: move handling of syslog facility out of eal 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-03-26 1:57 ` [PATCH v13 05/11] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-26 1:57 ` Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 07/11] eal: initialize log before everything else Stephen Hemminger ` (4 subsequent siblings) 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:57 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 9 files changed, 68 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..661b2db211 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 85171b2768..2519a30017 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 07/11] eal: initialize log before everything else 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-03-26 1:57 ` [PATCH v13 06/11] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-03-26 1:57 ` Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 08/11] log: drop syslog support, and make code common Stephen Hemminger ` (3 subsequent siblings) 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:57 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..55ff27a4da 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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."); @@ -565,9 +574,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..b9a0fb1742 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -952,9 +961,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); @@ -1106,13 +1112,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 2519a30017..74b3ece30c 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 08/11] log: drop syslog support, and make code common 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-03-26 1:57 ` [PATCH v13 07/11] eal: initialize log before everything else Stephen Hemminger @ 2024-03-26 1:57 ` Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 09/11] log: add hook for printing log messages Stephen Hemminger ` (2 subsequent siblings) 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:57 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 29 +++++--- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 8 files changed, 26 insertions(+), 153 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..36e3185a10 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 661b2db211..9ab512e8a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2212,9 +2212,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..f597da2e39 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -70,12 +70,13 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) { + if (rte_logs.file != NULL) + fclose(rte_logs.file); + rte_logs.file = f; return 0; } @@ -505,13 +506,20 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -525,8 +533,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_log_get_stream(); + + /* don't close stderr on the application */ + if (log_stream != stderr) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 09/11] log: add hook for printing log messages 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-03-26 1:57 ` [PATCH v13 08/11] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-26 1:57 ` Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 10/11] log: add timestamp option Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 11/11] log: add optional support of syslog Stephen Hemminger 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:57 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index f597da2e39..acd4c320b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -26,16 +26,21 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); +static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ + 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 = log_print, }; struct rte_eal_opt_loglevel { @@ -78,6 +83,7 @@ rte_openlog_stream(FILE *f) fclose(rte_logs.file); rte_logs.file = f; + rte_logs.print_func = log_print; return 0; } @@ -484,7 +490,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, level, format, ap); fflush(f); return ret; } @@ -513,6 +519,15 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* default log print function */ +__rte_format_printf(3, 0) +static int +log_print(FILE *f, uint32_t level __rte_unused, + const char *format, va_list ap) +{ + return vfprintf(f, format, ap); +} + /* * Called by rte_eal_init */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 10/11] log: add timestamp option 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-03-26 1:57 ` [PATCH v13 09/11] log: add hook for printing log messages Stephen Hemminger @ 2024-03-26 1:57 ` Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 11/11] log: add optional support of syslog Stephen Hemminger 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:57 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 183 +++++++++++++++++++++++++++- lib/log/log_internal.h | 9 ++ lib/log/version.map | 1 + 10 files changed, 268 insertions(+), 7 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 36e3185a10..e54f6e8b7f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ab512e8a1..5173835c2c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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: { @@ -2216,6 +2225,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 55ff27a4da..662a829ce8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b9a0fb1742..8cbea480e0 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 74b3ece30c..4283c920c8 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index acd4c320b6..2dca91306e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -11,6 +11,7 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -18,7 +19,7 @@ #include "log_internal.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -26,6 +27,15 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +enum eal_log_time_format { + EAL_LOG_TIMESTAMP_NONE = 0, + EAL_LOG_TIMESTAMP_TIME, /* time since start */ + EAL_LOG_TIMESTAMP_DELTA, /* time since last message */ + EAL_LOG_TIMESTAMP_RELTIME, + EAL_LOG_TIMESTAMP_CTIME, + EAL_LOG_TIMESTAMP_ISO, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -35,6 +45,11 @@ static struct rte_logs { uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ log_print_t print_func; + + enum eal_log_time_format time_format; + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ + size_t dynamic_types_len; struct rte_log_dynamic_type *dynamic_types; } rte_logs = { @@ -375,6 +390,9 @@ RTE_INIT_PRIO(log_init, LOG) { uint32_t i; + clock_gettime(CLOCK_MONOTONIC, &rte_logs.started); + rte_logs.previous = rte_logs.started; + rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -519,6 +537,152 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + rte_logs.time_format = EAL_LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + + +/* Format current timespec into ISO8601 format */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &rte_logs.previous); + rte_logs.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +static ssize_t +format_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (rte_logs.time_format) { + case EAL_LOG_TIMESTAMP_NONE: + return 0; + + case EAL_LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.previous); + rte_logs.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case EAL_LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case EAL_LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -528,12 +692,29 @@ log_print(FILE *f, uint32_t level __rte_unused, return vfprintf(f, format, ap); } +/* print timestamp before message */ +__rte_format_printf(3, 0) +static int +log_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + fprintf(f, "[%s] ", tsbuf); + + return log_print(f, level, format, ap); +} + /* * Called by rte_eal_init */ void eal_log_init(const char *id __rte_unused) { + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print_with_timestamp; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v13 11/11] log: add optional support of syslog 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-03-26 1:57 ` [PATCH v13 10/11] log: add timestamp option Stephen Hemminger @ 2024-03-26 1:57 ` Stephen Hemminger 10 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 1:57 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ----- doc/guides/prog_guide/log_lib.rst | 17 +++ lib/eal/common/eal_common_options.c | 2 +- lib/log/log.c | 101 ++++++++++++++++-- 5 files changed, 114 insertions(+), 38 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e54f6e8b7f..08f4866461 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5173835c2c..16884c5aa3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, diff --git a/lib/log/log.c b/lib/log/log.c index 2dca91306e..d8974c66db 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -13,15 +13,17 @@ #include <sys/queue.h> #include <unistd.h> +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#else +#include <syslog.h> +#endif + #include <rte_log.h> #include <rte_per_lcore.h> #include "log_internal.h" -#ifdef RTE_EXEC_ENV_WINDOWS -#include <rte_os_shim.h> -#endif - struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -36,14 +38,25 @@ enum eal_log_time_format { EAL_LOG_TIMESTAMP_ISO, }; +enum eal_log_syslog { + EAL_LOG_SYSLOG_NONE = 0, /* do not use syslog */ + EAL_LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + EAL_LOG_SYSLOG_ALWAYS, /* always use syslog */ + EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ +#ifndef RTE_EXEC_ENV_WINDOWS + enum eal_log_syslog syslog_opt; +#endif log_print_t print_func; enum eal_log_time_format time_format; @@ -532,9 +545,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) /* Placeholder */ int -eal_log_syslog(const char *mode __rte_unused) +eal_log_syslog(const char *str) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(str); return -1; +#else + if (str == NULL || strcmp(str, "auto") == 0) + /* log to syslog only if stderr is not a terminal */ + rte_logs.syslog_opt = EAL_LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +#endif } /* Set the log timestamp format */ @@ -706,17 +733,75 @@ log_print_with_timestamp(FILE *f, uint32_t level, return log_print(f, level, format, ap); } +#ifndef RTE_EXEC_ENV_WINDOWS /* - * Called by rte_eal_init + * wrapper for log stream to put messages into syslog + * useful for cases like: + * rte_hex_dump(rte_get_log_stream(), ...) */ -void -eal_log_init(const char *id __rte_unused) +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) { + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; +#endif + + +/* Choose how log output is directed */ +static void +log_output_selection(const char *id) +{ + RTE_SET_USED(id); + +#ifndef RTE_EXEC_ENV_WINDOWS + bool is_terminal = isatty(STDERR_FILENO); + + if (!(rte_logs.syslog_opt == EAL_LOG_SYSLOG_NONE || + (rte_logs.syslog_opt == EAL_LOG_SYSLOG_AUTO && is_terminal))) { + int flags = LOG_NDELAY | LOG_PID; + +#ifdef LOG_PERROR + if (rte_logs.syslog_opt == EAL_LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; +#endif + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; + return; + } +#endif if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) rte_logs.print_func = log_print_with_timestamp; +} +/* + * Called by rte_eal_init + */ +void +eal_log_init(const char *id) +{ + rte_logs.print_func = log_print; default_log_stream = stderr; + log_output_selection(id); + #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 00/15] Logging unification and improvments 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (12 preceding siblings ...) 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 01/15] maintainers: add for log library Stephen Hemminger ` (14 more replies) 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (15 subsequent siblings) 29 siblings, 15 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). 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. I find color helpful because 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 syslog. Add myself as maintainer for log because by now have added more than previous authors... Will add a release note in next release (after this is merged) v14 - fix Windows build, by having common asprintf shim fix asprintf memory leaks add log stream when using journal Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r windows: common wrapper for vasprintf and asprintf 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog log: add support for systemd journal log: colorize log output MAINTAINERS | 1 + app/test/test_eal_flags.c | 64 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 - doc/guides/prog_guide/log_lib.rst | 57 ++ drivers/bus/pci/pci_common.c | 32 - lib/eal/common/eal_common_debug.c | 10 +- lib/eal/common/eal_common_options.c | 117 ++-- lib/eal/common/eal_options.h | 5 + lib/eal/common/eal_private.h | 10 - lib/eal/freebsd/eal.c | 64 +- lib/eal/linux/eal.c | 68 +- lib/eal/windows/eal.c | 77 +-- lib/eal/windows/getopt.c | 23 +- lib/eal/windows/include/getopt.h | 8 +- lib/eal/windows/include/rte_os_shim.h | 56 ++ lib/log/log.c | 633 +++++++++++++++++- lib/log/log_freebsd.c | 5 +- lib/log/log_internal.h | 25 +- lib/log/log_linux.c | 61 -- lib/log/log_windows.c | 18 - lib/log/meson.build | 5 +- lib/log/version.map | 4 +- 22 files changed, 942 insertions(+), 428 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 01/15] maintainers: add for log library 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (13 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7abb3aee49..54c28a601d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 02/15] windows: make getopt functions have const properties 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 01/15] maintainers: add for log library Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (12 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 03/15] windows: add os shim for localtime_r 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 01/15] maintainers: add for log library Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger ` (11 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 04/15] windows: common wrapper for vasprintf and asprintf 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (2 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 05/15] eal: make eal_log_level_parse common Stephen Hemminger ` (10 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Chenbo Xia, Nipun Gupta, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam, David Marchand, Bruce Richardson, Nick Connolly, Khoa To, Ranjit Menon Replace the windows version of asprintf() that was only usable in eal. With a more generic one that supports both vasprintf() and asprintf(). This also eliminates duplicate code. Fixes: 8f4de2dba9b9 ("bus/pci: fill bus specific information") Fixes: 9ec521006db0 ("eal/windows: hide asprintf shim") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- drivers/bus/pci/pci_common.c | 32 ------------------- lib/eal/common/eal_private.h | 10 ------ lib/eal/windows/eal.c | 28 ---------------- lib/eal/windows/include/rte_os_shim.h | 46 +++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 70 deletions(-) diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c index 889a48d2af..80691c75a3 100644 --- a/drivers/bus/pci/pci_common.c +++ b/drivers/bus/pci/pci_common.c @@ -45,38 +45,6 @@ const char *rte_pci_get_sysfs_path(void) return path; } -#ifdef RTE_EXEC_ENV_WINDOWS -#define asprintf pci_asprintf - -static int -__rte_format_printf(2, 3) -pci_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} -#endif /* RTE_EXEC_ENV_WINDOWS */ - static struct rte_devargs * pci_devargs_lookup(const struct rte_pci_addr *pci_addr) { diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h index 71523cfdb8..da8d77a134 100644 --- a/lib/eal/common/eal_private.h +++ b/lib/eal/common/eal_private.h @@ -737,16 +737,6 @@ void __rte_thread_init(unsigned int lcore_id, rte_cpuset_t *cpuset); */ void __rte_thread_uninit(void); -/** - * asprintf(3) replacement for Windows. - */ -#ifdef RTE_EXEC_ENV_WINDOWS -__rte_format_printf(2, 3) -int eal_asprintf(char **buffer, const char *format, ...); - -#define asprintf(buffer, format, ...) \ - eal_asprintf(buffer, format, ##__VA_ARGS__) -#endif #define EAL_LOG(level, ...) \ RTE_LOG_LINE(level, EAL, "" __VA_ARGS__) diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..8ca00c0f95 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -503,34 +503,6 @@ rte_eal_init(int argc, char **argv) return fctret; } -/* Don't use MinGW asprintf() to have identical code with all toolchains. */ -int -eal_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} - int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr, diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index e9741a9df2..b941476fe0 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -3,6 +3,7 @@ #ifndef _RTE_OS_SHIM_ #define _RTE_OS_SHIM_ +#include <stdio.h> #include <time.h> #include <rte_os.h> @@ -120,4 +121,49 @@ rte_localtime_r(const time_t *timer, struct tm *buf) } #define localtime_r(timer, buf) rte_localtime_r(timer, buf) +/* print to allocated string */ +static inline int +rte_vasprintf(char **strp, const char *fmt, va_list ap) +{ + char *str; + int len, ret; + + *strp = NULL; + + /* determine size of buffer needed */ + len = _vscprintf(fmt, ap); + if (len < 0) + return -1; + + len += 1; /* for nul termination */ + str = malloc(len); + if (str == NULL) + return -1; + + ret = vsnprintf(str, len, fmt, ap); + if (ret < 0) { + free(str); + return -1; + } else { + *strp = str; + return ret; + } +} +#define vasprintf(strp, fmt, ap) rte_vasprintf(strp, fmt, ap) + +static inline int +rte_asprintf(char **strp, const char *fmt, ...) +{ + int ret; + + va_list ap; + + va_start(ap, fmt); + ret = rte_vasprintf(strp, fmt, ap); + va_end(ap); + + return ret; +} + +#define asprintf(strp, fmt, ...) rte_asprintf(strp, fmt, __VA_ARGS__) #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 05/15] eal: make eal_log_level_parse common 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (3 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (9 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 8ca00c0f95..44e20643f2 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 06/15] eal: do not duplicate rte_init_alert() messages 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (4 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 05/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (8 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 07/15] eal: change rte_exit() output to match rte_log() 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (5 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 08/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (7 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_debug.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..71bb5a7d34 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,17 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char *msg = NULL; 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); + if (vasprintf(&msg, format, ap) > 0) + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 08/15] log: move handling of syslog facility out of eal 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (6 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 09/15] eal: initialize log before everything else Stephen Hemminger ` (6 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 9 files changed, 68 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..661b2db211 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 44e20643f2..14e498a643 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 09/15] eal: initialize log before everything else 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (7 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 08/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 10/15] log: drop syslog support, and make code common Stephen Hemminger ` (5 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..55ff27a4da 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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."); @@ -565,9 +574,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..b9a0fb1742 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -952,9 +961,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); @@ -1106,13 +1112,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 14e498a643..e59aba954e 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 10/15] log: drop syslog support, and make code common 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (8 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 09/15] eal: initialize log before everything else Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 11/15] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 29 +++++--- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 8 files changed, 26 insertions(+), 153 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..36e3185a10 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 661b2db211..9ab512e8a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2212,9 +2212,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..f597da2e39 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -70,12 +70,13 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) { + if (rte_logs.file != NULL) + fclose(rte_logs.file); + rte_logs.file = f; return 0; } @@ -505,13 +506,20 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -525,8 +533,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_log_get_stream(); + + /* don't close stderr on the application */ + if (log_stream != stderr) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 11/15] log: add hook for printing log messages 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (9 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 10/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 12/15] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index f597da2e39..acd4c320b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -26,16 +26,21 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); +static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ + 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 = log_print, }; struct rte_eal_opt_loglevel { @@ -78,6 +83,7 @@ rte_openlog_stream(FILE *f) fclose(rte_logs.file); rte_logs.file = f; + rte_logs.print_func = log_print; return 0; } @@ -484,7 +490,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, level, format, ap); fflush(f); return ret; } @@ -513,6 +519,15 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* default log print function */ +__rte_format_printf(3, 0) +static int +log_print(FILE *f, uint32_t level __rte_unused, + const char *format, va_list ap) +{ + return vfprintf(f, format, ap); +} + /* * Called by rte_eal_init */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 12/15] log: add timestamp option 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (10 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 11/15] log: add hook for printing log messages Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 13/15] log: add optional support of syslog Stephen Hemminger ` (2 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 183 +++++++++++++++++++++++++++- lib/log/log_internal.h | 9 ++ lib/log/version.map | 1 + 10 files changed, 268 insertions(+), 7 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 36e3185a10..e54f6e8b7f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ab512e8a1..5173835c2c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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: { @@ -2216,6 +2225,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 55ff27a4da..662a829ce8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b9a0fb1742..8cbea480e0 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index e59aba954e..b251dc3e1b 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index acd4c320b6..2dca91306e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -11,6 +11,7 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -18,7 +19,7 @@ #include "log_internal.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -26,6 +27,15 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +enum eal_log_time_format { + EAL_LOG_TIMESTAMP_NONE = 0, + EAL_LOG_TIMESTAMP_TIME, /* time since start */ + EAL_LOG_TIMESTAMP_DELTA, /* time since last message */ + EAL_LOG_TIMESTAMP_RELTIME, + EAL_LOG_TIMESTAMP_CTIME, + EAL_LOG_TIMESTAMP_ISO, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -35,6 +45,11 @@ static struct rte_logs { uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ log_print_t print_func; + + enum eal_log_time_format time_format; + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ + size_t dynamic_types_len; struct rte_log_dynamic_type *dynamic_types; } rte_logs = { @@ -375,6 +390,9 @@ RTE_INIT_PRIO(log_init, LOG) { uint32_t i; + clock_gettime(CLOCK_MONOTONIC, &rte_logs.started); + rte_logs.previous = rte_logs.started; + rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -519,6 +537,152 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + rte_logs.time_format = EAL_LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + + +/* Format current timespec into ISO8601 format */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &rte_logs.previous); + rte_logs.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +static ssize_t +format_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (rte_logs.time_format) { + case EAL_LOG_TIMESTAMP_NONE: + return 0; + + case EAL_LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.previous); + rte_logs.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case EAL_LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case EAL_LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -528,12 +692,29 @@ log_print(FILE *f, uint32_t level __rte_unused, return vfprintf(f, format, ap); } +/* print timestamp before message */ +__rte_format_printf(3, 0) +static int +log_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + fprintf(f, "[%s] ", tsbuf); + + return log_print(f, level, format, ap); +} + /* * Called by rte_eal_init */ void eal_log_init(const char *id __rte_unused) { + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print_with_timestamp; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 13/15] log: add optional support of syslog 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (11 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 12/15] log: add timestamp option Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ----- doc/guides/prog_guide/log_lib.rst | 17 +++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 101 ++++++++++++++++-- 5 files changed, 117 insertions(+), 38 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e54f6e8b7f..08f4866461 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5173835c2c..9ca7db04aa 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2221,6 +2221,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 2dca91306e..d8974c66db 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -13,15 +13,17 @@ #include <sys/queue.h> #include <unistd.h> +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#else +#include <syslog.h> +#endif + #include <rte_log.h> #include <rte_per_lcore.h> #include "log_internal.h" -#ifdef RTE_EXEC_ENV_WINDOWS -#include <rte_os_shim.h> -#endif - struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -36,14 +38,25 @@ enum eal_log_time_format { EAL_LOG_TIMESTAMP_ISO, }; +enum eal_log_syslog { + EAL_LOG_SYSLOG_NONE = 0, /* do not use syslog */ + EAL_LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + EAL_LOG_SYSLOG_ALWAYS, /* always use syslog */ + EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ +#ifndef RTE_EXEC_ENV_WINDOWS + enum eal_log_syslog syslog_opt; +#endif log_print_t print_func; enum eal_log_time_format time_format; @@ -532,9 +545,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) /* Placeholder */ int -eal_log_syslog(const char *mode __rte_unused) +eal_log_syslog(const char *str) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(str); return -1; +#else + if (str == NULL || strcmp(str, "auto") == 0) + /* log to syslog only if stderr is not a terminal */ + rte_logs.syslog_opt = EAL_LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +#endif } /* Set the log timestamp format */ @@ -706,17 +733,75 @@ log_print_with_timestamp(FILE *f, uint32_t level, return log_print(f, level, format, ap); } +#ifndef RTE_EXEC_ENV_WINDOWS /* - * Called by rte_eal_init + * wrapper for log stream to put messages into syslog + * useful for cases like: + * rte_hex_dump(rte_get_log_stream(), ...) */ -void -eal_log_init(const char *id __rte_unused) +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) { + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; +#endif + + +/* Choose how log output is directed */ +static void +log_output_selection(const char *id) +{ + RTE_SET_USED(id); + +#ifndef RTE_EXEC_ENV_WINDOWS + bool is_terminal = isatty(STDERR_FILENO); + + if (!(rte_logs.syslog_opt == EAL_LOG_SYSLOG_NONE || + (rte_logs.syslog_opt == EAL_LOG_SYSLOG_AUTO && is_terminal))) { + int flags = LOG_NDELAY | LOG_PID; + +#ifdef LOG_PERROR + if (rte_logs.syslog_opt == EAL_LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; +#endif + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; + return; + } +#endif if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) rte_logs.print_func = log_print_with_timestamp; +} +/* + * Called by rte_eal_init + */ +void +eal_log_init(const char *id) +{ + rte_logs.print_func = log_print; default_log_stream = stderr; + log_output_selection(id); + #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 14/15] log: add support for systemd journal 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (12 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 13/15] log: add optional support of syslog Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 2 deletions(-) diff --git a/lib/log/log.c b/lib/log/log.c index d8974c66db..8e2319b3f0 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -17,6 +17,10 @@ #include <rte_os_shim.h> #else #include <syslog.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> #endif #include <rte_log.h> @@ -56,6 +60,7 @@ static struct rte_logs { FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ #ifndef RTE_EXEC_ENV_WINDOWS enum eal_log_syslog syslog_opt; + int journal_fd; #endif log_print_t print_func; @@ -758,6 +763,146 @@ static cookie_io_functions_t syslog_log_func = { .write = syslog_log_write, .close = syslog_log_close, }; + +/* + * send message using journal protocol to journald + */ +static int +journal_send(uint32_t level, const char *buf, size_t len) +{ + struct iovec iov[3]; + char msg[] = "MESSAGE="; + char prio[32]; + int ret; + + iov[0].iov_base = msg; + iov[0].iov_len = strlen(msg); + + iov[1].iov_base = (char *)(uintptr_t)buf; + iov[1].iov_len = len; + + /* priority value between 0 ("emerg") and 7 ("debug") */ + iov[2].iov_base = prio; + iov[2].iov_len = snprintf(prio, sizeof(prio), + "PRIORITY=%i\n", level - 1); + + ret = writev(rte_logs.journal_fd, iov, 3); + return ret; +} + +__rte_format_printf(3, 0) +static int +journal_print(FILE *f __rte_unused, uint32_t level, const char *format, va_list ap) +{ + char *buf = NULL; + int ret, len; + + len = vasprintf(&buf, format, ap); + if (len == 0) + return 0; + + /* check that message ends with newline, if not add one */ + if (buf[len - 1] != '\n') { + char *clone = malloc(len + 1); + if (clone == NULL) { + free(buf); + return 0; + } + + memcpy(clone, buf, len); + clone[len++] = '\n'; + free(buf); + buf = clone; + } + + ret = journal_send(level, buf, len); + free(buf); + return ret; +} + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(rte_log_cur_msg_loglevel(), buf, size); +} + +static cookie_io_functions_t journal_log_func = { + .write = journal_log_write, +}; + +/* + * Check if stderr is going to system journal. + * This is the documented way to handle systemd journal + * + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +using_journal(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 */ +static int +open_journal(const char *id) +{ + char *syslog_id = NULL; + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + ssize_t len; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) + return -1; + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) + goto error; + + /* Send syslog identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\n", id); + if (len == 0) + goto error; + + if (write(s, syslog_id, len) != len) + goto error; + + free(syslog_id); + + /* redirect other log messages to journal */ + FILE *log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; + + return s; + +error: + free(syslog_id); + close(s); + return -1; +} #endif @@ -765,11 +910,24 @@ static cookie_io_functions_t syslog_log_func = { static void log_output_selection(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); - -#ifndef RTE_EXEC_ENV_WINDOWS +#else bool is_terminal = isatty(STDERR_FILENO); + /* If stderr is redirected to systemd journal then upgrade */ + if (using_journal()) { + int jfd = open_journal(id); + + if (jfd < 0) { + RTE_LOG_LINE(NOTICE, EAL, "Cannot connect to journal: %s", + strerror(errno)); + } else { + rte_logs.print_func = journal_print; + return; + } + } + if (!(rte_logs.syslog_opt == EAL_LOG_SYSLOG_NONE || (rte_logs.syslog_opt == EAL_LOG_SYSLOG_AUTO && is_terminal))) { int flags = LOG_NDELAY | LOG_PID; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v14 15/15] log: colorize log output 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger ` (13 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 14/15] log: add support for systemd journal Stephen Hemminger @ 2024-03-26 17:34 ` Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-26 17:34 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 24 ++++ doc/guides/prog_guide/log_lib.rst | 16 ++- lib/eal/common/eal_common_options.c | 2 + lib/eal/common/eal_options.h | 2 + lib/log/log.c | 163 +++++++++++++++++++++++++++- lib/log/log_internal.h | 5 + lib/log/version.map | 1 + 7 files changed, 208 insertions(+), 5 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 08f4866461..c6c05e2e1d 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..40727ebaae 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ @@ -101,7 +116,6 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. - Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ca7db04aa..709605e722 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -75,6 +75,7 @@ eal_long_options[] = { {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_LOG_COLOR, 1, NULL, OPT_LOG_COLOR_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 }, @@ -2229,6 +2230,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..5a63c1dd3a 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -37,6 +37,8 @@ enum { OPT_LOG_LEVEL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_TRACE "trace" OPT_TRACE_NUM, #define OPT_TRACE_DIR "trace-dir" diff --git a/lib/log/log.c b/lib/log/log.c index 8e2319b3f0..768116a7bb 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -23,6 +23,7 @@ #include <sys/un.h> #endif +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -49,6 +50,12 @@ enum eal_log_syslog { EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ }; +enum eal_log_color { + EAL_LOG_COLOR_AUTO = 0, /* default */ + EAL_LOG_COLOR_NEVER, + EAL_LOG_COLOR_ALWAYS, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -64,6 +71,7 @@ static struct rte_logs { #endif log_print_t print_func; + enum eal_log_color color_mode; enum eal_log_time_format time_format; struct timespec started; /* when log was initialized */ struct timespec previous; /* when last msg was printed */ @@ -715,6 +723,74 @@ format_timestamp(char *tsbuf, size_t tsbuflen) return 0; } +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR +}; + +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\e[31m", + [COLOR_GREEN] = "\e[32m", + [COLOR_YELLOW] = "\e[33m", + [COLOR_BLUE] = "\e[34m", + [COLOR_MAGENTA] = "\e[35m", + [COLOR_CYAN] = "\e[36m", + [COLOR_WHITE] = "\e[37m", + [COLOR_BOLD] = "\e[1m", + [COLOR_CLEAR] = "\e[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + + return ret; +} + +static ssize_t +color_log_write(FILE *f, int level, char *msg) +{ + char *cp; + ssize_t ret = 0; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(stderr, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -905,16 +981,84 @@ open_journal(const char *id) } #endif +__rte_format_printf(3, 0) +static int +color_print(FILE *f, uint32_t level, const char *format, va_list ap) +{ + char *buf = NULL; + int ret; + + /* need to make temporary buffer for color scan */ + ret = vasprintf(&buf, format, ap); + if (ret > 0) { + ret = color_log_write(f, level, buf); + free(buf); + return ret; + } + + /* if vasprintf fails, print without color */ + return log_print(f, level, format, ap); +} + +__rte_format_printf(3, 0) +static int +color_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, level, format, ap); +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +static inline bool +use_color(bool is_terminal) +{ + switch (rte_logs.color_mode) { + default: + case EAL_LOG_COLOR_NEVER: + return false; + case EAL_LOG_COLOR_ALWAYS: + return true; + case EAL_LOG_COLOR_AUTO: + return is_terminal; + } + +} /* Choose how log output is directed */ static void log_output_selection(const char *id) { + bool is_terminal = isatty(STDERR_FILENO); + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); #else - bool is_terminal = isatty(STDERR_FILENO); - /* If stderr is redirected to systemd journal then upgrade */ if (using_journal()) { int jfd = open_journal(id); @@ -945,8 +1089,19 @@ log_output_selection(const char *id) return; } #endif - if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) - rte_logs.print_func = log_print_with_timestamp; + + if (use_color(is_terminal)) { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = color_print; + else + rte_logs.print_func = color_print_with_timestamp; + } else { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print; + else + rte_logs.print_func = log_print_with_timestamp; + } + } /* diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..525e1397fd 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -47,5 +47,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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 14d6681a5f..7fa79b20ff 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 00/15] Logging unification and improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (13 preceding siblings ...) 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger @ 2024-03-27 0:26 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 01/15] maintainers: add for log library Stephen Hemminger ` (14 more replies) 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (14 subsequent siblings) 29 siblings, 15 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:26 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). 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. I find color helpful because 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 syslog. Add myself as maintainer for log because by now have added more than previous authors... Will add a release note in next release (after this is merged) v15 - fix log test cases avoid use of malloc (ie vasprintf) in log path because malloc pool maybe corrupted. Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r windows: common wrapper for vasprintf and asprintf 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog log: add support for systemd journal log: colorize log output MAINTAINERS | 1 + app/test/test_eal_flags.c | 64 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 - doc/guides/prog_guide/log_lib.rst | 57 ++ drivers/bus/pci/pci_common.c | 32 - lib/eal/common/eal_common_debug.c | 10 +- lib/eal/common/eal_common_options.c | 126 ++-- lib/eal/common/eal_options.h | 5 + lib/eal/common/eal_private.h | 10 - lib/eal/freebsd/eal.c | 64 +- lib/eal/linux/eal.c | 68 +- lib/eal/windows/eal.c | 77 +-- lib/eal/windows/getopt.c | 23 +- lib/eal/windows/include/getopt.h | 8 +- lib/eal/windows/include/rte_os_shim.h | 56 ++ lib/log/log.c | 646 +++++++++++++++++- lib/log/log_freebsd.c | 5 +- lib/log/log_internal.h | 25 +- lib/log/log_linux.c | 61 -- lib/log/log_windows.c | 18 - lib/log/meson.build | 5 +- lib/log/version.map | 4 +- 22 files changed, 964 insertions(+), 428 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 01/15] maintainers: add for log library 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (13 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7abb3aee49..54c28a601d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 02/15] windows: make getopt functions have const properties 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 01/15] maintainers: add for log library Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (12 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 03/15] windows: add os shim for localtime_r 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 01/15] maintainers: add for log library Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger ` (11 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 04/15] windows: common wrapper for vasprintf and asprintf 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 05/15] eal: make eal_log_level_parse common Stephen Hemminger ` (10 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Chenbo Xia, Nipun Gupta, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam, David Marchand, Bruce Richardson, Khoa To, Nick Connolly, Ranjit Menon Replace the windows version of asprintf() that was only usable in eal. With a more generic one that supports both vasprintf() and asprintf(). This also eliminates duplicate code. Fixes: 8f4de2dba9b9 ("bus/pci: fill bus specific information") Fixes: 9ec521006db0 ("eal/windows: hide asprintf shim") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- drivers/bus/pci/pci_common.c | 32 ------------------- lib/eal/common/eal_private.h | 10 ------ lib/eal/windows/eal.c | 28 ---------------- lib/eal/windows/include/rte_os_shim.h | 46 +++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 70 deletions(-) diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c index 889a48d2af..80691c75a3 100644 --- a/drivers/bus/pci/pci_common.c +++ b/drivers/bus/pci/pci_common.c @@ -45,38 +45,6 @@ const char *rte_pci_get_sysfs_path(void) return path; } -#ifdef RTE_EXEC_ENV_WINDOWS -#define asprintf pci_asprintf - -static int -__rte_format_printf(2, 3) -pci_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} -#endif /* RTE_EXEC_ENV_WINDOWS */ - static struct rte_devargs * pci_devargs_lookup(const struct rte_pci_addr *pci_addr) { diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h index 71523cfdb8..da8d77a134 100644 --- a/lib/eal/common/eal_private.h +++ b/lib/eal/common/eal_private.h @@ -737,16 +737,6 @@ void __rte_thread_init(unsigned int lcore_id, rte_cpuset_t *cpuset); */ void __rte_thread_uninit(void); -/** - * asprintf(3) replacement for Windows. - */ -#ifdef RTE_EXEC_ENV_WINDOWS -__rte_format_printf(2, 3) -int eal_asprintf(char **buffer, const char *format, ...); - -#define asprintf(buffer, format, ...) \ - eal_asprintf(buffer, format, ##__VA_ARGS__) -#endif #define EAL_LOG(level, ...) \ RTE_LOG_LINE(level, EAL, "" __VA_ARGS__) diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..8ca00c0f95 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -503,34 +503,6 @@ rte_eal_init(int argc, char **argv) return fctret; } -/* Don't use MinGW asprintf() to have identical code with all toolchains. */ -int -eal_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} - int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr, diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index e9741a9df2..b941476fe0 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -3,6 +3,7 @@ #ifndef _RTE_OS_SHIM_ #define _RTE_OS_SHIM_ +#include <stdio.h> #include <time.h> #include <rte_os.h> @@ -120,4 +121,49 @@ rte_localtime_r(const time_t *timer, struct tm *buf) } #define localtime_r(timer, buf) rte_localtime_r(timer, buf) +/* print to allocated string */ +static inline int +rte_vasprintf(char **strp, const char *fmt, va_list ap) +{ + char *str; + int len, ret; + + *strp = NULL; + + /* determine size of buffer needed */ + len = _vscprintf(fmt, ap); + if (len < 0) + return -1; + + len += 1; /* for nul termination */ + str = malloc(len); + if (str == NULL) + return -1; + + ret = vsnprintf(str, len, fmt, ap); + if (ret < 0) { + free(str); + return -1; + } else { + *strp = str; + return ret; + } +} +#define vasprintf(strp, fmt, ap) rte_vasprintf(strp, fmt, ap) + +static inline int +rte_asprintf(char **strp, const char *fmt, ...) +{ + int ret; + + va_list ap; + + va_start(ap, fmt); + ret = rte_vasprintf(strp, fmt, ap); + va_end(ap); + + return ret; +} + +#define asprintf(strp, fmt, ...) rte_asprintf(strp, fmt, __VA_ARGS__) #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 05/15] eal: make eal_log_level_parse common 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (9 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 8ca00c0f95..44e20643f2 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 06/15] eal: do not duplicate rte_init_alert() messages 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 05/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (8 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 07/15] eal: change rte_exit() output to match rte_log() 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 08/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (7 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_debug.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..71bb5a7d34 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,17 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char *msg = NULL; 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); + if (vasprintf(&msg, format, ap) > 0) + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 08/15] log: move handling of syslog facility out of eal 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 09/15] eal: initialize log before everything else Stephen Hemminger ` (6 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 9 files changed, 68 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..661b2db211 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 44e20643f2..14e498a643 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 09/15] eal: initialize log before everything else 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 08/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 10/15] log: drop syslog support, and make code common Stephen Hemminger ` (5 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..55ff27a4da 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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."); @@ -565,9 +574,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..b9a0fb1742 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -952,9 +961,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); @@ -1106,13 +1112,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 14e498a643..e59aba954e 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 10/15] log: drop syslog support, and make code common 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 09/15] eal: initialize log before everything else Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 11/15] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 29 +++++--- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 8 files changed, 26 insertions(+), 153 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..36e3185a10 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 661b2db211..9ab512e8a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2212,9 +2212,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..f597da2e39 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -70,12 +70,13 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) { + if (rte_logs.file != NULL) + fclose(rte_logs.file); + rte_logs.file = f; return 0; } @@ -505,13 +506,20 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -525,8 +533,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_log_get_stream(); + + /* don't close stderr on the application */ + if (log_stream != stderr) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 11/15] log: add hook for printing log messages 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 10/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 12/15] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index f597da2e39..acd4c320b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -26,16 +26,21 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); +static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ + 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 = log_print, }; struct rte_eal_opt_loglevel { @@ -78,6 +83,7 @@ rte_openlog_stream(FILE *f) fclose(rte_logs.file); rte_logs.file = f; + rte_logs.print_func = log_print; return 0; } @@ -484,7 +490,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, level, format, ap); fflush(f); return ret; } @@ -513,6 +519,15 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* default log print function */ +__rte_format_printf(3, 0) +static int +log_print(FILE *f, uint32_t level __rte_unused, + const char *format, va_list ap) +{ + return vfprintf(f, format, ap); +} + /* * Called by rte_eal_init */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 12/15] log: add timestamp option 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 11/15] log: add hook for printing log messages Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 13/15] log: add optional support of syslog Stephen Hemminger ` (2 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 183 +++++++++++++++++++++++++++- lib/log/log_internal.h | 9 ++ lib/log/version.map | 1 + 10 files changed, 268 insertions(+), 7 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 36e3185a10..e54f6e8b7f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ab512e8a1..5173835c2c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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: { @@ -2216,6 +2225,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 55ff27a4da..662a829ce8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b9a0fb1742..8cbea480e0 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index e59aba954e..b251dc3e1b 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index acd4c320b6..2dca91306e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -11,6 +11,7 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -18,7 +19,7 @@ #include "log_internal.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -26,6 +27,15 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +enum eal_log_time_format { + EAL_LOG_TIMESTAMP_NONE = 0, + EAL_LOG_TIMESTAMP_TIME, /* time since start */ + EAL_LOG_TIMESTAMP_DELTA, /* time since last message */ + EAL_LOG_TIMESTAMP_RELTIME, + EAL_LOG_TIMESTAMP_CTIME, + EAL_LOG_TIMESTAMP_ISO, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -35,6 +45,11 @@ static struct rte_logs { uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ log_print_t print_func; + + enum eal_log_time_format time_format; + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ + size_t dynamic_types_len; struct rte_log_dynamic_type *dynamic_types; } rte_logs = { @@ -375,6 +390,9 @@ RTE_INIT_PRIO(log_init, LOG) { uint32_t i; + clock_gettime(CLOCK_MONOTONIC, &rte_logs.started); + rte_logs.previous = rte_logs.started; + rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -519,6 +537,152 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + rte_logs.time_format = EAL_LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + + +/* Format current timespec into ISO8601 format */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &rte_logs.previous); + rte_logs.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +static ssize_t +format_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (rte_logs.time_format) { + case EAL_LOG_TIMESTAMP_NONE: + return 0; + + case EAL_LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.previous); + rte_logs.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case EAL_LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case EAL_LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -528,12 +692,29 @@ log_print(FILE *f, uint32_t level __rte_unused, return vfprintf(f, format, ap); } +/* print timestamp before message */ +__rte_format_printf(3, 0) +static int +log_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + fprintf(f, "[%s] ", tsbuf); + + return log_print(f, level, format, ap); +} + /* * Called by rte_eal_init */ void eal_log_init(const char *id __rte_unused) { + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print_with_timestamp; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 13/15] log: add optional support of syslog 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 12/15] log: add timestamp option Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ---- doc/guides/prog_guide/log_lib.rst | 17 +++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 121 ++++++++++++++++-- 5 files changed, 137 insertions(+), 38 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e54f6e8b7f..08f4866461 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5173835c2c..9ca7db04aa 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2221,6 +2221,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 2dca91306e..ec0d55273e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -13,15 +13,17 @@ #include <sys/queue.h> #include <unistd.h> +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#else +#include <syslog.h> +#endif + #include <rte_log.h> #include <rte_per_lcore.h> #include "log_internal.h" -#ifdef RTE_EXEC_ENV_WINDOWS -#include <rte_os_shim.h> -#endif - struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -36,14 +38,25 @@ enum eal_log_time_format { EAL_LOG_TIMESTAMP_ISO, }; +enum eal_log_syslog { + EAL_LOG_SYSLOG_NONE = 0, /* do not use syslog */ + EAL_LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + EAL_LOG_SYSLOG_ALWAYS, /* always use syslog */ + EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ +#ifndef RTE_EXEC_ENV_WINDOWS + enum eal_log_syslog syslog_opt; +#endif log_print_t print_func; enum eal_log_time_format time_format; @@ -532,9 +545,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) /* Placeholder */ int -eal_log_syslog(const char *mode __rte_unused) +eal_log_syslog(const char *str) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(str); return -1; +#else + if (str == NULL || strcmp(str, "auto") == 0) + /* log to syslog only if stderr is not a terminal */ + rte_logs.syslog_opt = EAL_LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +#endif } /* Set the log timestamp format */ @@ -706,17 +733,95 @@ log_print_with_timestamp(FILE *f, uint32_t level, return log_print(f, level, format, ap); } +#ifndef RTE_EXEC_ENV_WINDOWS +static bool +using_syslog(bool is_terminal) +{ + switch (rte_logs.syslog_opt) { + default: + return false; + + case EAL_LOG_SYSLOG_ALWAYS: + case EAL_LOG_SYSLOG_BOTH: + return true; + + case EAL_LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + /* - * Called by rte_eal_init + * wrapper for log stream to put messages into syslog + * useful for cases like: + * rte_hex_dump(rte_get_log_stream(), ...) */ -void -eal_log_init(const char *id __rte_unused) +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) { + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +static void +log_open_syslog(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + +#ifdef LOG_PERROR + if (rte_logs.syslog_opt == EAL_LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; +#endif + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; +} +#endif + +/* Choose how log output is directed */ +static void +log_output_selection(const char *id) +{ + RTE_SET_USED(id); + +#ifndef RTE_EXEC_ENV_WINDOWS + bool is_terminal = isatty(STDERR_FILENO); + + if (using_syslog(is_terminal)) { + log_open_syslog(id, is_terminal); + return; + } +#endif if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) rte_logs.print_func = log_print_with_timestamp; +} +/* + * Called by rte_eal_init + */ +void +eal_log_init(const char *id) +{ + rte_logs.print_func = log_print; default_log_stream = stderr; + log_output_selection(id); + #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 14/15] log: add support for systemd journal 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (12 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 13/15] log: add optional support of syslog Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/lib/log/log.c b/lib/log/log.c index ec0d55273e..650d294120 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -17,6 +17,10 @@ #include <rte_os_shim.h> #else #include <syslog.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> #endif #include <rte_log.h> @@ -56,6 +60,7 @@ static struct rte_logs { FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ #ifndef RTE_EXEC_ENV_WINDOWS enum eal_log_syslog syslog_opt; + int journal_fd; #endif log_print_t print_func; @@ -775,6 +780,138 @@ static cookie_io_functions_t syslog_log_func = { .close = syslog_log_close, }; +/* + * send message using journal protocol to journald + */ +static int +journal_send(uint32_t level, const char *buf, size_t len) +{ + struct iovec iov[3]; + char msg[] = "MESSAGE="; + char prio[32]; + int ret; + + iov[0].iov_base = msg; + iov[0].iov_len = strlen(msg); + + iov[1].iov_base = (char *)(uintptr_t)buf; + iov[1].iov_len = len; + + /* priority value between 0 ("emerg") and 7 ("debug") */ + iov[2].iov_base = prio; + iov[2].iov_len = snprintf(prio, sizeof(prio), + "PRIORITY=%i\n", level - 1); + + ret = writev(rte_logs.journal_fd, iov, 3); + return ret; +} + +__rte_format_printf(3, 0) +static int +journal_print(FILE *f __rte_unused, uint32_t level, const char *format, va_list ap) +{ + char buf[BUFSIZ]; + size_t len; + + len = vsnprintf(buf, sizeof(buf), format, ap); + if (len == 0) + return 0; + + /* check for truncation */ + if (len >= sizeof(buf) - 1) + len = sizeof(buf) - 1; + + /* check that message ends with newline, if not add one */ + if (buf[len - 1] != '\n') + buf[len++] = '\n'; + + return journal_send(level, buf, len); +} + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(rte_log_cur_msg_loglevel(), buf, size); +} + +static cookie_io_functions_t journal_log_func = { + .write = journal_log_write, +}; + +/* + * Check if stderr is going to system journal. + * This is the documented way to handle systemd journal + * + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(const char *id) +{ + char *syslog_id = NULL; + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + ssize_t len; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) + return -1; + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) + goto error; + + /* Send syslog identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\n", id); + if (len == 0) + goto error; + + if (write(s, syslog_id, len) != len) + goto error; + + free(syslog_id); + + /* redirect other log messages to journal */ + FILE *log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; + + return s; + +error: + free(syslog_id); + close(s); + return -1; +} + static void log_open_syslog(const char *id, bool is_terminal) { @@ -797,11 +934,24 @@ log_open_syslog(const char *id, bool is_terminal) static void log_output_selection(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); - -#ifndef RTE_EXEC_ENV_WINDOWS +#else bool is_terminal = isatty(STDERR_FILENO); + /* If stderr is redirected to systemd journal then upgrade */ + if (!is_terminal && is_journal(STDERR_FILENO)) { + int jfd = open_journal(id); + + if (jfd < 0) { + RTE_LOG_LINE(NOTICE, EAL, "Cannot connect to journal: %s", + strerror(errno)); + } else { + rte_logs.print_func = journal_print; + return; + } + } + if (using_syslog(is_terminal)) { log_open_syslog(id, is_terminal); return; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v15 15/15] log: colorize log output 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger ` (13 preceding siblings ...) 2024-03-27 0:27 ` [PATCH v15 14/15] log: add support for systemd journal Stephen Hemminger @ 2024-03-27 0:27 ` Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 0:27 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 24 ++++ doc/guides/prog_guide/log_lib.rst | 16 ++- lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 164 +++++++++++++++++++++++++++- lib/log/log_internal.h | 5 + lib/log/version.map | 1 + 7 files changed, 218 insertions(+), 5 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 08f4866461..c6c05e2e1d 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..40727ebaae 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ @@ -101,7 +116,6 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. - Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ca7db04aa..5e7ab29ae3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -75,6 +75,7 @@ eal_long_options[] = { {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_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_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[]) 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; @@ -1862,6 +1864,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) { @@ -2229,6 +2239,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..5a63c1dd3a 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -37,6 +37,8 @@ enum { OPT_LOG_LEVEL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_TRACE "trace" OPT_TRACE_NUM, #define OPT_TRACE_DIR "trace-dir" diff --git a/lib/log/log.c b/lib/log/log.c index 650d294120..b19a418686 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -23,6 +23,7 @@ #include <sys/un.h> #endif +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -49,6 +50,12 @@ enum eal_log_syslog { EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ }; +enum eal_log_color { + EAL_LOG_COLOR_AUTO = 0, /* default */ + EAL_LOG_COLOR_NEVER, + EAL_LOG_COLOR_ALWAYS, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -64,6 +71,7 @@ static struct rte_logs { #endif log_print_t print_func; + enum eal_log_color color_mode; enum eal_log_time_format time_format; struct timespec started; /* when log was initialized */ struct timespec previous; /* when last msg was printed */ @@ -715,6 +723,74 @@ format_timestamp(char *tsbuf, size_t tsbuflen) return 0; } +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR +}; + +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\e[31m", + [COLOR_GREEN] = "\e[32m", + [COLOR_YELLOW] = "\e[33m", + [COLOR_BLUE] = "\e[34m", + [COLOR_MAGENTA] = "\e[35m", + [COLOR_CYAN] = "\e[36m", + [COLOR_WHITE] = "\e[37m", + [COLOR_BOLD] = "\e[1m", + [COLOR_CLEAR] = "\e[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + + return ret; +} + +static ssize_t +color_log_write(FILE *f, int level, char *msg) +{ + char *cp; + ssize_t ret = 0; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(stderr, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -930,15 +1006,84 @@ log_open_syslog(const char *id, bool is_terminal) } #endif +__rte_format_printf(3, 0) +static int +color_print(FILE *f, uint32_t level, const char *format, va_list ap) +{ + char *buf = NULL; + int ret; + + /* need to make temporary buffer for color scan */ + ret = vasprintf(&buf, format, ap); + if (ret > 0) { + ret = color_log_write(f, level, buf); + free(buf); + return ret; + } + + /* if vasprintf fails, print without color */ + return log_print(f, level, format, ap); +} + +__rte_format_printf(3, 0) +static int +color_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, level, format, ap); +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +static inline bool +use_color(bool is_terminal) +{ + switch (rte_logs.color_mode) { + default: + case EAL_LOG_COLOR_NEVER: + return false; + case EAL_LOG_COLOR_ALWAYS: + return true; + case EAL_LOG_COLOR_AUTO: + return is_terminal; + } + +} + /* Choose how log output is directed */ static void log_output_selection(const char *id) { + bool is_terminal = isatty(STDERR_FILENO); + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); #else - bool is_terminal = isatty(STDERR_FILENO); - /* If stderr is redirected to systemd journal then upgrade */ if (!is_terminal && is_journal(STDERR_FILENO)) { int jfd = open_journal(id); @@ -957,8 +1102,19 @@ log_output_selection(const char *id) return; } #endif - if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) - rte_logs.print_func = log_print_with_timestamp; + + if (use_color(is_terminal)) { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = color_print; + else + rte_logs.print_func = color_print_with_timestamp; + } else { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print; + else + rte_logs.print_func = log_print_with_timestamp; + } + } /* diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..525e1397fd 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -47,5 +47,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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 14d6681a5f..7fa79b20ff 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 00/15] Logging unification and improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (14 preceding siblings ...) 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 01/15] maintainers: add for log library Stephen Hemminger ` (14 more replies) 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (13 subsequent siblings) 29 siblings, 15 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). 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. I find color helpful because 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 syslog. Add myself as maintainer for log because by now have added more than previous authors... Will add a release note in next release (after this is merged) v16 - add printf attribute to Windows shim add missing va_end in color_fprintf avoid allocation in rte_exit Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r windows: common wrapper for vasprintf and asprintf 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog log: add support for systemd journal log: colorize log output MAINTAINERS | 1 + app/test/test_eal_flags.c | 64 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 - doc/guides/prog_guide/log_lib.rst | 57 ++ drivers/bus/pci/pci_common.c | 32 - lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 126 ++-- lib/eal/common/eal_options.h | 5 + lib/eal/common/eal_private.h | 10 - lib/eal/freebsd/eal.c | 64 +- lib/eal/linux/eal.c | 68 +- lib/eal/windows/eal.c | 77 +-- lib/eal/windows/getopt.c | 23 +- lib/eal/windows/include/getopt.h | 8 +- lib/eal/windows/include/rte_os_shim.h | 58 ++ lib/log/log.c | 647 +++++++++++++++++- lib/log/log_freebsd.c | 5 +- lib/log/log_internal.h | 25 +- lib/log/log_linux.c | 61 -- lib/log/log_windows.c | 18 - lib/log/meson.build | 5 +- lib/log/version.map | 4 +- 22 files changed, 968 insertions(+), 428 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 01/15] maintainers: add for log library 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:52 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (13 subsequent siblings) 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7abb3aee49..54c28a601d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v16 01/15] maintainers: add for log library 2024-03-27 16:45 ` [PATCH v16 01/15] maintainers: add for log library Stephen Hemminger @ 2024-03-27 16:52 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-27 16:52 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Thomas Monjalon On Wed, Mar 27, 2024 at 09:45:19AM -0700, Stephen Hemminger wrote: > "You touch it you own it" > Add myself as maintainer for log library. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 02/15] windows: make getopt functions have const properties 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 01/15] maintainers: add for log library Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (12 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 03/15] windows: add os shim for localtime_r 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 01/15] maintainers: add for log library Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:56 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger ` (11 subsequent siblings) 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v16 03/15] windows: add os shim for localtime_r 2024-03-27 16:45 ` [PATCH v16 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-27 16:56 ` Tyler Retzlaff 2024-03-27 17:30 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-27 16:56 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Dmitry Kozlyuk, Pallavi Kadam On Wed, Mar 27, 2024 at 09:45:21AM -0700, Stephen Hemminger wrote: > Windows does not have localtime_r but it does have a similar > function that can be used instead. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- > lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h > index eda8113662..e9741a9df2 100644 > --- a/lib/eal/windows/include/rte_os_shim.h > +++ b/lib/eal/windows/include/rte_os_shim.h > @@ -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 *timer, struct tm *buf) > +{ > + if (localtime_s(buf, timer) == 0) > + return buf; > + else > + return NULL; > +} > +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) hm, i'm always a bit concerned about expressing platform standard names from dpdk api surface. i think we should just expose and use rte_localtime_r() and not present localtime_r. can be treated as a suggestion. Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v16 03/15] windows: add os shim for localtime_r 2024-03-27 16:56 ` Tyler Retzlaff @ 2024-03-27 17:30 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 17:30 UTC (permalink / raw) To: Tyler Retzlaff; +Cc: dev, Dmitry Kozlyuk, Pallavi Kadam On Wed, 27 Mar 2024 09:56:59 -0700 Tyler Retzlaff <roretzla@linux.microsoft.com> wrote: > On Wed, Mar 27, 2024 at 09:45:21AM -0700, Stephen Hemminger wrote: > > Windows does not have localtime_r but it does have a similar > > function that can be used instead. > > > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > > --- > > lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ > > 1 file changed, 10 insertions(+) > > > > diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h > > index eda8113662..e9741a9df2 100644 > > --- a/lib/eal/windows/include/rte_os_shim.h > > +++ b/lib/eal/windows/include/rte_os_shim.h > > @@ -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 *timer, struct tm *buf) > > +{ > > + if (localtime_s(buf, timer) == 0) > > + return buf; > > + else > > + return NULL; > > +} > > +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) > > hm, i'm always a bit concerned about expressing platform standard names > from dpdk api surface. i think we should just expose and use > rte_localtime_r() and not present localtime_r. > > can be treated as a suggestion. > > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > I was just copying what clock_gettime was doing. But yes, should really do global update to rte_localtime() ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 04/15] windows: common wrapper for vasprintf and asprintf 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 17:08 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 05/15] eal: make eal_log_level_parse common Stephen Hemminger ` (10 subsequent siblings) 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Chenbo Xia, Nipun Gupta, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam, David Marchand, Bruce Richardson, Nick Connolly, Khoa To, Ranjit Menon Replace the windows version of asprintf() that was only usable in eal. With a more generic one that supports both vasprintf() and asprintf(). This also eliminates duplicate code. Fixes: 8f4de2dba9b9 ("bus/pci: fill bus specific information") Fixes: 9ec521006db0 ("eal/windows: hide asprintf shim") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- drivers/bus/pci/pci_common.c | 32 ------------------ lib/eal/common/eal_private.h | 10 ------ lib/eal/windows/eal.c | 28 ---------------- lib/eal/windows/include/rte_os_shim.h | 48 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 70 deletions(-) diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c index 889a48d2af..80691c75a3 100644 --- a/drivers/bus/pci/pci_common.c +++ b/drivers/bus/pci/pci_common.c @@ -45,38 +45,6 @@ const char *rte_pci_get_sysfs_path(void) return path; } -#ifdef RTE_EXEC_ENV_WINDOWS -#define asprintf pci_asprintf - -static int -__rte_format_printf(2, 3) -pci_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} -#endif /* RTE_EXEC_ENV_WINDOWS */ - static struct rte_devargs * pci_devargs_lookup(const struct rte_pci_addr *pci_addr) { diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h index 71523cfdb8..da8d77a134 100644 --- a/lib/eal/common/eal_private.h +++ b/lib/eal/common/eal_private.h @@ -737,16 +737,6 @@ void __rte_thread_init(unsigned int lcore_id, rte_cpuset_t *cpuset); */ void __rte_thread_uninit(void); -/** - * asprintf(3) replacement for Windows. - */ -#ifdef RTE_EXEC_ENV_WINDOWS -__rte_format_printf(2, 3) -int eal_asprintf(char **buffer, const char *format, ...); - -#define asprintf(buffer, format, ...) \ - eal_asprintf(buffer, format, ##__VA_ARGS__) -#endif #define EAL_LOG(level, ...) \ RTE_LOG_LINE(level, EAL, "" __VA_ARGS__) diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..8ca00c0f95 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -503,34 +503,6 @@ rte_eal_init(int argc, char **argv) return fctret; } -/* Don't use MinGW asprintf() to have identical code with all toolchains. */ -int -eal_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} - int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr, diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index e9741a9df2..65153fdb38 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -3,6 +3,7 @@ #ifndef _RTE_OS_SHIM_ #define _RTE_OS_SHIM_ +#include <stdio.h> #include <time.h> #include <rte_os.h> @@ -120,4 +121,51 @@ rte_localtime_r(const time_t *timer, struct tm *buf) } #define localtime_r(timer, buf) rte_localtime_r(timer, buf) +/* print to allocated string */ +__rte_format_printf(2, 0) +static inline int +rte_vasprintf(char **strp, const char *fmt, va_list ap) +{ + char *str; + int len, ret; + + *strp = NULL; + + /* determine size of buffer needed */ + len = _vscprintf(fmt, ap); + if (len < 0) + return -1; + + len += 1; /* for nul termination */ + str = malloc(len); + if (str == NULL) + return -1; + + ret = vsnprintf(str, len, fmt, ap); + if (ret < 0) { + free(str); + return -1; + } else { + *strp = str; + return ret; + } +} +#define vasprintf(strp, fmt, ap) rte_vasprintf(strp, fmt, ap) + +__rte_format_printf(2, 3) +static inline int +rte_asprintf(char **strp, const char *fmt, ...) +{ + int ret; + + va_list ap; + + va_start(ap, fmt); + ret = rte_vasprintf(strp, fmt, ap); + va_end(ap); + + return ret; +} + +#define asprintf(strp, fmt, ...) rte_asprintf(strp, fmt, __VA_ARGS__) #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v16 04/15] windows: common wrapper for vasprintf and asprintf 2024-03-27 16:45 ` [PATCH v16 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger @ 2024-03-27 17:08 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-27 17:08 UTC (permalink / raw) To: Stephen Hemminger Cc: dev, Chenbo Xia, Nipun Gupta, Dmitry Kozlyuk, Pallavi Kadam, David Marchand, Bruce Richardson, Nick Connolly, Khoa To, Ranjit Menon On Wed, Mar 27, 2024 at 09:45:22AM -0700, Stephen Hemminger wrote: > Replace the windows version of asprintf() that was only usable > in eal. With a more generic one that supports both vasprintf() > and asprintf(). This also eliminates duplicate code. > > Fixes: 8f4de2dba9b9 ("bus/pci: fill bus specific information") > Fixes: 9ec521006db0 ("eal/windows: hide asprintf shim") > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 05/15] eal: make eal_log_level_parse common 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 17:11 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (9 subsequent siblings) 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 8ca00c0f95..44e20643f2 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v16 05/15] eal: make eal_log_level_parse common 2024-03-27 16:45 ` [PATCH v16 05/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-27 17:11 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-27 17:11 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam On Wed, Mar 27, 2024 at 09:45:23AM -0700, Stephen Hemminger wrote: > The code to parse for log-level option should be same on > all OS variants. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 06/15] eal: do not duplicate rte_init_alert() messages 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 05/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 17:11 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (8 subsequent siblings) 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v16 06/15] eal: do not duplicate rte_init_alert() messages 2024-03-27 16:45 ` [PATCH v16 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-27 17:11 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-27 17:11 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Bruce Richardson On Wed, Mar 27, 2024 at 09:45:24AM -0700, Stephen Hemminger wrote: > The message already goes through logging, and does not need > to be printed on stderr. Message level should be ALERT > to match function name. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 07/15] eal: change rte_exit() output to match rte_log() 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 17:12 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 08/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (7 subsequent siblings) 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..ad2be63cbb 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char msg[256]; 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); + vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v16 07/15] eal: change rte_exit() output to match rte_log() 2024-03-27 16:45 ` [PATCH v16 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-27 17:12 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-27 17:12 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Wed, Mar 27, 2024 at 09:45:25AM -0700, Stephen Hemminger wrote: > 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: Cause - Cannot init EAL: Permission denied > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- this version too Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 08/15] log: move handling of syslog facility out of eal 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 09/15] eal: initialize log before everything else Stephen Hemminger ` (6 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 9 files changed, 68 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..661b2db211 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 44e20643f2..14e498a643 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 09/15] eal: initialize log before everything else 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 08/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 17:14 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 10/15] log: drop syslog support, and make code common Stephen Hemminger ` (5 subsequent siblings) 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..55ff27a4da 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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."); @@ -565,9 +574,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..b9a0fb1742 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -952,9 +961,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); @@ -1106,13 +1112,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 14e498a643..e59aba954e 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v16 09/15] eal: initialize log before everything else 2024-03-27 16:45 ` [PATCH v16 09/15] eal: initialize log before everything else Stephen Hemminger @ 2024-03-27 17:14 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-03-27 17:14 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam On Wed, Mar 27, 2024 at 09:45:27AM -0700, Stephen Hemminger wrote: > 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. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 10/15] log: drop syslog support, and make code common 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 09/15] eal: initialize log before everything else Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 11/15] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 29 +++++--- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 8 files changed, 26 insertions(+), 153 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..36e3185a10 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 661b2db211..9ab512e8a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2212,9 +2212,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..f597da2e39 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -70,12 +70,13 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) { + if (rte_logs.file != NULL) + fclose(rte_logs.file); + rte_logs.file = f; return 0; } @@ -505,13 +506,20 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -525,8 +533,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_log_get_stream(); + + /* don't close stderr on the application */ + if (log_stream != stderr) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 11/15] log: add hook for printing log messages 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 10/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 12/15] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index f597da2e39..acd4c320b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -26,16 +26,21 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); +static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ + 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 = log_print, }; struct rte_eal_opt_loglevel { @@ -78,6 +83,7 @@ rte_openlog_stream(FILE *f) fclose(rte_logs.file); rte_logs.file = f; + rte_logs.print_func = log_print; return 0; } @@ -484,7 +490,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, level, format, ap); fflush(f); return ret; } @@ -513,6 +519,15 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* default log print function */ +__rte_format_printf(3, 0) +static int +log_print(FILE *f, uint32_t level __rte_unused, + const char *format, va_list ap) +{ + return vfprintf(f, format, ap); +} + /* * Called by rte_eal_init */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 12/15] log: add timestamp option 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 11/15] log: add hook for printing log messages Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 13/15] log: add optional support of syslog Stephen Hemminger ` (2 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 183 +++++++++++++++++++++++++++- lib/log/log_internal.h | 9 ++ lib/log/version.map | 1 + 10 files changed, 268 insertions(+), 7 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 36e3185a10..e54f6e8b7f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ab512e8a1..5173835c2c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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: { @@ -2216,6 +2225,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 55ff27a4da..662a829ce8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b9a0fb1742..8cbea480e0 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index e59aba954e..b251dc3e1b 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index acd4c320b6..2dca91306e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -11,6 +11,7 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -18,7 +19,7 @@ #include "log_internal.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -26,6 +27,15 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +enum eal_log_time_format { + EAL_LOG_TIMESTAMP_NONE = 0, + EAL_LOG_TIMESTAMP_TIME, /* time since start */ + EAL_LOG_TIMESTAMP_DELTA, /* time since last message */ + EAL_LOG_TIMESTAMP_RELTIME, + EAL_LOG_TIMESTAMP_CTIME, + EAL_LOG_TIMESTAMP_ISO, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -35,6 +45,11 @@ static struct rte_logs { uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ log_print_t print_func; + + enum eal_log_time_format time_format; + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ + size_t dynamic_types_len; struct rte_log_dynamic_type *dynamic_types; } rte_logs = { @@ -375,6 +390,9 @@ RTE_INIT_PRIO(log_init, LOG) { uint32_t i; + clock_gettime(CLOCK_MONOTONIC, &rte_logs.started); + rte_logs.previous = rte_logs.started; + rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -519,6 +537,152 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + rte_logs.time_format = EAL_LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + + +/* Format current timespec into ISO8601 format */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &rte_logs.previous); + rte_logs.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +static ssize_t +format_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (rte_logs.time_format) { + case EAL_LOG_TIMESTAMP_NONE: + return 0; + + case EAL_LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.previous); + rte_logs.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case EAL_LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case EAL_LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -528,12 +692,29 @@ log_print(FILE *f, uint32_t level __rte_unused, return vfprintf(f, format, ap); } +/* print timestamp before message */ +__rte_format_printf(3, 0) +static int +log_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + fprintf(f, "[%s] ", tsbuf); + + return log_print(f, level, format, ap); +} + /* * Called by rte_eal_init */ void eal_log_init(const char *id __rte_unused) { + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print_with_timestamp; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 13/15] log: add optional support of syslog 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 12/15] log: add timestamp option Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ---- doc/guides/prog_guide/log_lib.rst | 17 +++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 121 ++++++++++++++++-- 5 files changed, 137 insertions(+), 38 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e54f6e8b7f..08f4866461 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5173835c2c..9ca7db04aa 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2221,6 +2221,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 2dca91306e..ec0d55273e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -13,15 +13,17 @@ #include <sys/queue.h> #include <unistd.h> +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#else +#include <syslog.h> +#endif + #include <rte_log.h> #include <rte_per_lcore.h> #include "log_internal.h" -#ifdef RTE_EXEC_ENV_WINDOWS -#include <rte_os_shim.h> -#endif - struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -36,14 +38,25 @@ enum eal_log_time_format { EAL_LOG_TIMESTAMP_ISO, }; +enum eal_log_syslog { + EAL_LOG_SYSLOG_NONE = 0, /* do not use syslog */ + EAL_LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + EAL_LOG_SYSLOG_ALWAYS, /* always use syslog */ + EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ +#ifndef RTE_EXEC_ENV_WINDOWS + enum eal_log_syslog syslog_opt; +#endif log_print_t print_func; enum eal_log_time_format time_format; @@ -532,9 +545,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) /* Placeholder */ int -eal_log_syslog(const char *mode __rte_unused) +eal_log_syslog(const char *str) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(str); return -1; +#else + if (str == NULL || strcmp(str, "auto") == 0) + /* log to syslog only if stderr is not a terminal */ + rte_logs.syslog_opt = EAL_LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +#endif } /* Set the log timestamp format */ @@ -706,17 +733,95 @@ log_print_with_timestamp(FILE *f, uint32_t level, return log_print(f, level, format, ap); } +#ifndef RTE_EXEC_ENV_WINDOWS +static bool +using_syslog(bool is_terminal) +{ + switch (rte_logs.syslog_opt) { + default: + return false; + + case EAL_LOG_SYSLOG_ALWAYS: + case EAL_LOG_SYSLOG_BOTH: + return true; + + case EAL_LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + /* - * Called by rte_eal_init + * wrapper for log stream to put messages into syslog + * useful for cases like: + * rte_hex_dump(rte_get_log_stream(), ...) */ -void -eal_log_init(const char *id __rte_unused) +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) { + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +static void +log_open_syslog(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + +#ifdef LOG_PERROR + if (rte_logs.syslog_opt == EAL_LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; +#endif + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; +} +#endif + +/* Choose how log output is directed */ +static void +log_output_selection(const char *id) +{ + RTE_SET_USED(id); + +#ifndef RTE_EXEC_ENV_WINDOWS + bool is_terminal = isatty(STDERR_FILENO); + + if (using_syslog(is_terminal)) { + log_open_syslog(id, is_terminal); + return; + } +#endif if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) rte_logs.print_func = log_print_with_timestamp; +} +/* + * Called by rte_eal_init + */ +void +eal_log_init(const char *id) +{ + rte_logs.print_func = log_print; default_log_stream = stderr; + log_output_selection(id); + #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 14/15] log: add support for systemd journal 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (12 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 13/15] log: add optional support of syslog Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/lib/log/log.c b/lib/log/log.c index ec0d55273e..650d294120 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -17,6 +17,10 @@ #include <rte_os_shim.h> #else #include <syslog.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> #endif #include <rte_log.h> @@ -56,6 +60,7 @@ static struct rte_logs { FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ #ifndef RTE_EXEC_ENV_WINDOWS enum eal_log_syslog syslog_opt; + int journal_fd; #endif log_print_t print_func; @@ -775,6 +780,138 @@ static cookie_io_functions_t syslog_log_func = { .close = syslog_log_close, }; +/* + * send message using journal protocol to journald + */ +static int +journal_send(uint32_t level, const char *buf, size_t len) +{ + struct iovec iov[3]; + char msg[] = "MESSAGE="; + char prio[32]; + int ret; + + iov[0].iov_base = msg; + iov[0].iov_len = strlen(msg); + + iov[1].iov_base = (char *)(uintptr_t)buf; + iov[1].iov_len = len; + + /* priority value between 0 ("emerg") and 7 ("debug") */ + iov[2].iov_base = prio; + iov[2].iov_len = snprintf(prio, sizeof(prio), + "PRIORITY=%i\n", level - 1); + + ret = writev(rte_logs.journal_fd, iov, 3); + return ret; +} + +__rte_format_printf(3, 0) +static int +journal_print(FILE *f __rte_unused, uint32_t level, const char *format, va_list ap) +{ + char buf[BUFSIZ]; + size_t len; + + len = vsnprintf(buf, sizeof(buf), format, ap); + if (len == 0) + return 0; + + /* check for truncation */ + if (len >= sizeof(buf) - 1) + len = sizeof(buf) - 1; + + /* check that message ends with newline, if not add one */ + if (buf[len - 1] != '\n') + buf[len++] = '\n'; + + return journal_send(level, buf, len); +} + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(rte_log_cur_msg_loglevel(), buf, size); +} + +static cookie_io_functions_t journal_log_func = { + .write = journal_log_write, +}; + +/* + * Check if stderr is going to system journal. + * This is the documented way to handle systemd journal + * + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(const char *id) +{ + char *syslog_id = NULL; + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + ssize_t len; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) + return -1; + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) + goto error; + + /* Send syslog identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\n", id); + if (len == 0) + goto error; + + if (write(s, syslog_id, len) != len) + goto error; + + free(syslog_id); + + /* redirect other log messages to journal */ + FILE *log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; + + return s; + +error: + free(syslog_id); + close(s); + return -1; +} + static void log_open_syslog(const char *id, bool is_terminal) { @@ -797,11 +934,24 @@ log_open_syslog(const char *id, bool is_terminal) static void log_output_selection(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); - -#ifndef RTE_EXEC_ENV_WINDOWS +#else bool is_terminal = isatty(STDERR_FILENO); + /* If stderr is redirected to systemd journal then upgrade */ + if (!is_terminal && is_journal(STDERR_FILENO)) { + int jfd = open_journal(id); + + if (jfd < 0) { + RTE_LOG_LINE(NOTICE, EAL, "Cannot connect to journal: %s", + strerror(errno)); + } else { + rte_logs.print_func = journal_print; + return; + } + } + if (using_syslog(is_terminal)) { log_open_syslog(id, is_terminal); return; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v16 15/15] log: colorize log output 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger ` (13 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 14/15] log: add support for systemd journal Stephen Hemminger @ 2024-03-27 16:45 ` Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 16:45 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 24 ++++ doc/guides/prog_guide/log_lib.rst | 16 ++- lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 165 +++++++++++++++++++++++++++- lib/log/log_internal.h | 5 + lib/log/version.map | 1 + 7 files changed, 219 insertions(+), 5 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 08f4866461..c6c05e2e1d 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..40727ebaae 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ @@ -101,7 +116,6 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. - Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ca7db04aa..5e7ab29ae3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -75,6 +75,7 @@ eal_long_options[] = { {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_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_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[]) 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; @@ -1862,6 +1864,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) { @@ -2229,6 +2239,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..5a63c1dd3a 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -37,6 +37,8 @@ enum { OPT_LOG_LEVEL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_TRACE "trace" OPT_TRACE_NUM, #define OPT_TRACE_DIR "trace-dir" diff --git a/lib/log/log.c b/lib/log/log.c index 650d294120..da14959117 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -23,6 +23,7 @@ #include <sys/un.h> #endif +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -49,6 +50,12 @@ enum eal_log_syslog { EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ }; +enum eal_log_color { + EAL_LOG_COLOR_AUTO = 0, /* default */ + EAL_LOG_COLOR_NEVER, + EAL_LOG_COLOR_ALWAYS, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -64,6 +71,7 @@ static struct rte_logs { #endif log_print_t print_func; + enum eal_log_color color_mode; enum eal_log_time_format time_format; struct timespec started; /* when log was initialized */ struct timespec previous; /* when last msg was printed */ @@ -715,6 +723,75 @@ format_timestamp(char *tsbuf, size_t tsbuflen) return 0; } +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR +}; + +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\e[31m", + [COLOR_GREEN] = "\e[32m", + [COLOR_YELLOW] = "\e[33m", + [COLOR_BLUE] = "\e[34m", + [COLOR_MAGENTA] = "\e[35m", + [COLOR_CYAN] = "\e[36m", + [COLOR_WHITE] = "\e[37m", + [COLOR_BOLD] = "\e[1m", + [COLOR_CLEAR] = "\e[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +static ssize_t +color_log_write(FILE *f, int level, char *msg) +{ + char *cp; + ssize_t ret = 0; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(stderr, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -930,15 +1007,84 @@ log_open_syslog(const char *id, bool is_terminal) } #endif +__rte_format_printf(3, 0) +static int +color_print(FILE *f, uint32_t level, const char *format, va_list ap) +{ + char *buf = NULL; + int ret; + + /* need to make temporary buffer for color scan */ + ret = vasprintf(&buf, format, ap); + if (ret > 0) { + ret = color_log_write(f, level, buf); + free(buf); + return ret; + } + + /* if vasprintf fails, print without color */ + return log_print(f, level, format, ap); +} + +__rte_format_printf(3, 0) +static int +color_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, level, format, ap); +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +static inline bool +use_color(bool is_terminal) +{ + switch (rte_logs.color_mode) { + default: + case EAL_LOG_COLOR_NEVER: + return false; + case EAL_LOG_COLOR_ALWAYS: + return true; + case EAL_LOG_COLOR_AUTO: + return is_terminal; + } + +} + /* Choose how log output is directed */ static void log_output_selection(const char *id) { + bool is_terminal = isatty(STDERR_FILENO); + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); #else - bool is_terminal = isatty(STDERR_FILENO); - /* If stderr is redirected to systemd journal then upgrade */ if (!is_terminal && is_journal(STDERR_FILENO)) { int jfd = open_journal(id); @@ -957,8 +1103,19 @@ log_output_selection(const char *id) return; } #endif - if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) - rte_logs.print_func = log_print_with_timestamp; + + if (use_color(is_terminal)) { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = color_print; + else + rte_logs.print_func = color_print_with_timestamp; + } else { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print; + else + rte_logs.print_func = log_print_with_timestamp; + } + } /* diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..525e1397fd 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -47,5 +47,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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 14d6681a5f..7fa79b20ff 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 00/15] Logging unification and improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (15 preceding siblings ...) 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 01/15] maintainers: add for log library Stephen Hemminger ` (14 more replies) 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (12 subsequent siblings) 29 siblings, 15 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Improvements and unification of logging library (for 24.07 release). 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. I find color helpful because 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 syslog. Add myself as maintainer for log because by now have added more than previous authors... Will add a release note in next release (after this is merged) v17 - fix isatty incompatability on Windows Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r windows: common wrapper for vasprintf and asprintf 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog log: add support for systemd journal log: colorize log output MAINTAINERS | 1 + app/test/test_eal_flags.c | 64 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 - doc/guides/prog_guide/log_lib.rst | 57 ++ drivers/bus/pci/pci_common.c | 32 - lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 126 ++-- lib/eal/common/eal_options.h | 5 + lib/eal/common/eal_private.h | 10 - lib/eal/freebsd/eal.c | 64 +- lib/eal/linux/eal.c | 68 +- lib/eal/windows/eal.c | 77 +-- lib/eal/windows/getopt.c | 23 +- lib/eal/windows/include/getopt.h | 8 +- lib/eal/windows/include/rte_os_shim.h | 58 ++ lib/log/log.c | 651 +++++++++++++++++- lib/log/log_freebsd.c | 5 +- lib/log/log_internal.h | 25 +- lib/log/log_linux.c | 61 -- lib/log/log_windows.c | 18 - lib/log/meson.build | 5 +- lib/log/version.map | 4 +- 22 files changed, 972 insertions(+), 428 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 01/15] maintainers: add for log library 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (13 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7abb3aee49..54c28a601d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 02/15] windows: make getopt functions have const properties 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 01/15] maintainers: add for log library Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (12 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 03/15] windows: add os shim for localtime_r 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 01/15] maintainers: add for log library Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger ` (11 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 04/15] windows: common wrapper for vasprintf and asprintf 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 05/15] eal: make eal_log_level_parse common Stephen Hemminger ` (10 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Chenbo Xia, Nipun Gupta, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam, David Marchand, Bruce Richardson, Ranjit Menon, Nick Connolly, Khoa To Replace the windows version of asprintf() that was only usable in eal. With a more generic one that supports both vasprintf() and asprintf(). This also eliminates duplicate code. Fixes: 8f4de2dba9b9 ("bus/pci: fill bus specific information") Fixes: 9ec521006db0 ("eal/windows: hide asprintf shim") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- drivers/bus/pci/pci_common.c | 32 ------------------ lib/eal/common/eal_private.h | 10 ------ lib/eal/windows/eal.c | 28 ---------------- lib/eal/windows/include/rte_os_shim.h | 48 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 70 deletions(-) diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c index 889a48d2af..80691c75a3 100644 --- a/drivers/bus/pci/pci_common.c +++ b/drivers/bus/pci/pci_common.c @@ -45,38 +45,6 @@ const char *rte_pci_get_sysfs_path(void) return path; } -#ifdef RTE_EXEC_ENV_WINDOWS -#define asprintf pci_asprintf - -static int -__rte_format_printf(2, 3) -pci_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} -#endif /* RTE_EXEC_ENV_WINDOWS */ - static struct rte_devargs * pci_devargs_lookup(const struct rte_pci_addr *pci_addr) { diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h index 71523cfdb8..da8d77a134 100644 --- a/lib/eal/common/eal_private.h +++ b/lib/eal/common/eal_private.h @@ -737,16 +737,6 @@ void __rte_thread_init(unsigned int lcore_id, rte_cpuset_t *cpuset); */ void __rte_thread_uninit(void); -/** - * asprintf(3) replacement for Windows. - */ -#ifdef RTE_EXEC_ENV_WINDOWS -__rte_format_printf(2, 3) -int eal_asprintf(char **buffer, const char *format, ...); - -#define asprintf(buffer, format, ...) \ - eal_asprintf(buffer, format, ##__VA_ARGS__) -#endif #define EAL_LOG(level, ...) \ RTE_LOG_LINE(level, EAL, "" __VA_ARGS__) diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..8ca00c0f95 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -503,34 +503,6 @@ rte_eal_init(int argc, char **argv) return fctret; } -/* Don't use MinGW asprintf() to have identical code with all toolchains. */ -int -eal_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} - int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr, diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index e9741a9df2..65153fdb38 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -3,6 +3,7 @@ #ifndef _RTE_OS_SHIM_ #define _RTE_OS_SHIM_ +#include <stdio.h> #include <time.h> #include <rte_os.h> @@ -120,4 +121,51 @@ rte_localtime_r(const time_t *timer, struct tm *buf) } #define localtime_r(timer, buf) rte_localtime_r(timer, buf) +/* print to allocated string */ +__rte_format_printf(2, 0) +static inline int +rte_vasprintf(char **strp, const char *fmt, va_list ap) +{ + char *str; + int len, ret; + + *strp = NULL; + + /* determine size of buffer needed */ + len = _vscprintf(fmt, ap); + if (len < 0) + return -1; + + len += 1; /* for nul termination */ + str = malloc(len); + if (str == NULL) + return -1; + + ret = vsnprintf(str, len, fmt, ap); + if (ret < 0) { + free(str); + return -1; + } else { + *strp = str; + return ret; + } +} +#define vasprintf(strp, fmt, ap) rte_vasprintf(strp, fmt, ap) + +__rte_format_printf(2, 3) +static inline int +rte_asprintf(char **strp, const char *fmt, ...) +{ + int ret; + + va_list ap; + + va_start(ap, fmt); + ret = rte_vasprintf(strp, fmt, ap); + va_end(ap); + + return ret; +} + +#define asprintf(strp, fmt, ...) rte_asprintf(strp, fmt, __VA_ARGS__) #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 05/15] eal: make eal_log_level_parse common 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (9 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 8ca00c0f95..44e20643f2 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 06/15] eal: do not duplicate rte_init_alert() messages 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 05/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (8 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 07/15] eal: change rte_exit() output to match rte_log() 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 08/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (7 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..ad2be63cbb 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char msg[256]; 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); + vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 08/15] log: move handling of syslog facility out of eal 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 09/15] eal: initialize log before everything else Stephen Hemminger ` (6 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 9 files changed, 68 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..661b2db211 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 44e20643f2..14e498a643 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 09/15] eal: initialize log before everything else 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 08/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 10/15] log: drop syslog support, and make code common Stephen Hemminger ` (5 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..55ff27a4da 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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."); @@ -565,9 +574,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..b9a0fb1742 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -952,9 +961,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); @@ -1106,13 +1112,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 14e498a643..e59aba954e 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 10/15] log: drop syslog support, and make code common 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 09/15] eal: initialize log before everything else Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 11/15] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 29 +++++--- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 8 files changed, 26 insertions(+), 153 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..36e3185a10 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 661b2db211..9ab512e8a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2212,9 +2212,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..f597da2e39 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -70,12 +70,13 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) { + if (rte_logs.file != NULL) + fclose(rte_logs.file); + rte_logs.file = f; return 0; } @@ -505,13 +506,20 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -525,8 +533,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_log_get_stream(); + + /* don't close stderr on the application */ + if (log_stream != stderr) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 11/15] log: add hook for printing log messages 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 10/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 12/15] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index f597da2e39..acd4c320b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -26,16 +26,21 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); +static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ + 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 = log_print, }; struct rte_eal_opt_loglevel { @@ -78,6 +83,7 @@ rte_openlog_stream(FILE *f) fclose(rte_logs.file); rte_logs.file = f; + rte_logs.print_func = log_print; return 0; } @@ -484,7 +490,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, level, format, ap); fflush(f); return ret; } @@ -513,6 +519,15 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* default log print function */ +__rte_format_printf(3, 0) +static int +log_print(FILE *f, uint32_t level __rte_unused, + const char *format, va_list ap) +{ + return vfprintf(f, format, ap); +} + /* * Called by rte_eal_init */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 12/15] log: add timestamp option 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 11/15] log: add hook for printing log messages Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 13/15] log: add optional support of syslog Stephen Hemminger ` (2 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 183 +++++++++++++++++++++++++++- lib/log/log_internal.h | 9 ++ lib/log/version.map | 1 + 10 files changed, 268 insertions(+), 7 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 36e3185a10..e54f6e8b7f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ab512e8a1..5173835c2c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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: { @@ -2216,6 +2225,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 55ff27a4da..662a829ce8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b9a0fb1742..8cbea480e0 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index e59aba954e..b251dc3e1b 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index acd4c320b6..2dca91306e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -11,6 +11,7 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -18,7 +19,7 @@ #include "log_internal.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -26,6 +27,15 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +enum eal_log_time_format { + EAL_LOG_TIMESTAMP_NONE = 0, + EAL_LOG_TIMESTAMP_TIME, /* time since start */ + EAL_LOG_TIMESTAMP_DELTA, /* time since last message */ + EAL_LOG_TIMESTAMP_RELTIME, + EAL_LOG_TIMESTAMP_CTIME, + EAL_LOG_TIMESTAMP_ISO, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -35,6 +45,11 @@ static struct rte_logs { uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ log_print_t print_func; + + enum eal_log_time_format time_format; + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ + size_t dynamic_types_len; struct rte_log_dynamic_type *dynamic_types; } rte_logs = { @@ -375,6 +390,9 @@ RTE_INIT_PRIO(log_init, LOG) { uint32_t i; + clock_gettime(CLOCK_MONOTONIC, &rte_logs.started); + rte_logs.previous = rte_logs.started; + rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -519,6 +537,152 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + rte_logs.time_format = EAL_LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + + +/* Format current timespec into ISO8601 format */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &rte_logs.previous); + rte_logs.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +static ssize_t +format_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (rte_logs.time_format) { + case EAL_LOG_TIMESTAMP_NONE: + return 0; + + case EAL_LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.previous); + rte_logs.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case EAL_LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case EAL_LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -528,12 +692,29 @@ log_print(FILE *f, uint32_t level __rte_unused, return vfprintf(f, format, ap); } +/* print timestamp before message */ +__rte_format_printf(3, 0) +static int +log_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + fprintf(f, "[%s] ", tsbuf); + + return log_print(f, level, format, ap); +} + /* * Called by rte_eal_init */ void eal_log_init(const char *id __rte_unused) { + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print_with_timestamp; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 13/15] log: add optional support of syslog 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 12/15] log: add timestamp option Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ---- doc/guides/prog_guide/log_lib.rst | 17 +++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 121 ++++++++++++++++-- 5 files changed, 137 insertions(+), 38 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e54f6e8b7f..08f4866461 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5173835c2c..9ca7db04aa 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2221,6 +2221,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 2dca91306e..ec0d55273e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -13,15 +13,17 @@ #include <sys/queue.h> #include <unistd.h> +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#else +#include <syslog.h> +#endif + #include <rte_log.h> #include <rte_per_lcore.h> #include "log_internal.h" -#ifdef RTE_EXEC_ENV_WINDOWS -#include <rte_os_shim.h> -#endif - struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -36,14 +38,25 @@ enum eal_log_time_format { EAL_LOG_TIMESTAMP_ISO, }; +enum eal_log_syslog { + EAL_LOG_SYSLOG_NONE = 0, /* do not use syslog */ + EAL_LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + EAL_LOG_SYSLOG_ALWAYS, /* always use syslog */ + EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ +#ifndef RTE_EXEC_ENV_WINDOWS + enum eal_log_syslog syslog_opt; +#endif log_print_t print_func; enum eal_log_time_format time_format; @@ -532,9 +545,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) /* Placeholder */ int -eal_log_syslog(const char *mode __rte_unused) +eal_log_syslog(const char *str) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(str); return -1; +#else + if (str == NULL || strcmp(str, "auto") == 0) + /* log to syslog only if stderr is not a terminal */ + rte_logs.syslog_opt = EAL_LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +#endif } /* Set the log timestamp format */ @@ -706,17 +733,95 @@ log_print_with_timestamp(FILE *f, uint32_t level, return log_print(f, level, format, ap); } +#ifndef RTE_EXEC_ENV_WINDOWS +static bool +using_syslog(bool is_terminal) +{ + switch (rte_logs.syslog_opt) { + default: + return false; + + case EAL_LOG_SYSLOG_ALWAYS: + case EAL_LOG_SYSLOG_BOTH: + return true; + + case EAL_LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + /* - * Called by rte_eal_init + * wrapper for log stream to put messages into syslog + * useful for cases like: + * rte_hex_dump(rte_get_log_stream(), ...) */ -void -eal_log_init(const char *id __rte_unused) +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) { + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +static void +log_open_syslog(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + +#ifdef LOG_PERROR + if (rte_logs.syslog_opt == EAL_LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; +#endif + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; +} +#endif + +/* Choose how log output is directed */ +static void +log_output_selection(const char *id) +{ + RTE_SET_USED(id); + +#ifndef RTE_EXEC_ENV_WINDOWS + bool is_terminal = isatty(STDERR_FILENO); + + if (using_syslog(is_terminal)) { + log_open_syslog(id, is_terminal); + return; + } +#endif if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) rte_logs.print_func = log_print_with_timestamp; +} +/* + * Called by rte_eal_init + */ +void +eal_log_init(const char *id) +{ + rte_logs.print_func = log_print; default_log_stream = stderr; + log_output_selection(id); + #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 14/15] log: add support for systemd journal 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (12 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 13/15] log: add optional support of syslog Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/lib/log/log.c b/lib/log/log.c index ec0d55273e..650d294120 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -17,6 +17,10 @@ #include <rte_os_shim.h> #else #include <syslog.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> #endif #include <rte_log.h> @@ -56,6 +60,7 @@ static struct rte_logs { FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ #ifndef RTE_EXEC_ENV_WINDOWS enum eal_log_syslog syslog_opt; + int journal_fd; #endif log_print_t print_func; @@ -775,6 +780,138 @@ static cookie_io_functions_t syslog_log_func = { .close = syslog_log_close, }; +/* + * send message using journal protocol to journald + */ +static int +journal_send(uint32_t level, const char *buf, size_t len) +{ + struct iovec iov[3]; + char msg[] = "MESSAGE="; + char prio[32]; + int ret; + + iov[0].iov_base = msg; + iov[0].iov_len = strlen(msg); + + iov[1].iov_base = (char *)(uintptr_t)buf; + iov[1].iov_len = len; + + /* priority value between 0 ("emerg") and 7 ("debug") */ + iov[2].iov_base = prio; + iov[2].iov_len = snprintf(prio, sizeof(prio), + "PRIORITY=%i\n", level - 1); + + ret = writev(rte_logs.journal_fd, iov, 3); + return ret; +} + +__rte_format_printf(3, 0) +static int +journal_print(FILE *f __rte_unused, uint32_t level, const char *format, va_list ap) +{ + char buf[BUFSIZ]; + size_t len; + + len = vsnprintf(buf, sizeof(buf), format, ap); + if (len == 0) + return 0; + + /* check for truncation */ + if (len >= sizeof(buf) - 1) + len = sizeof(buf) - 1; + + /* check that message ends with newline, if not add one */ + if (buf[len - 1] != '\n') + buf[len++] = '\n'; + + return journal_send(level, buf, len); +} + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(rte_log_cur_msg_loglevel(), buf, size); +} + +static cookie_io_functions_t journal_log_func = { + .write = journal_log_write, +}; + +/* + * Check if stderr is going to system journal. + * This is the documented way to handle systemd journal + * + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(const char *id) +{ + char *syslog_id = NULL; + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + ssize_t len; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) + return -1; + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) + goto error; + + /* Send syslog identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\n", id); + if (len == 0) + goto error; + + if (write(s, syslog_id, len) != len) + goto error; + + free(syslog_id); + + /* redirect other log messages to journal */ + FILE *log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; + + return s; + +error: + free(syslog_id); + close(s); + return -1; +} + static void log_open_syslog(const char *id, bool is_terminal) { @@ -797,11 +934,24 @@ log_open_syslog(const char *id, bool is_terminal) static void log_output_selection(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); - -#ifndef RTE_EXEC_ENV_WINDOWS +#else bool is_terminal = isatty(STDERR_FILENO); + /* If stderr is redirected to systemd journal then upgrade */ + if (!is_terminal && is_journal(STDERR_FILENO)) { + int jfd = open_journal(id); + + if (jfd < 0) { + RTE_LOG_LINE(NOTICE, EAL, "Cannot connect to journal: %s", + strerror(errno)); + } else { + rte_logs.print_func = journal_print; + return; + } + } + if (using_syslog(is_terminal)) { log_open_syslog(id, is_terminal); return; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v17 15/15] log: colorize log output 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger ` (13 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 14/15] log: add support for systemd journal Stephen Hemminger @ 2024-03-27 23:28 ` Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-27 23:28 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 24 ++++ doc/guides/prog_guide/log_lib.rst | 16 ++- lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 167 +++++++++++++++++++++++++++- lib/log/log_internal.h | 5 + lib/log/version.map | 1 + 7 files changed, 222 insertions(+), 4 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 08f4866461..c6c05e2e1d 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..40727ebaae 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ @@ -101,7 +116,6 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. - Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ca7db04aa..5e7ab29ae3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -75,6 +75,7 @@ eal_long_options[] = { {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_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_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[]) 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; @@ -1862,6 +1864,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) { @@ -2229,6 +2239,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..5a63c1dd3a 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -37,6 +37,8 @@ enum { OPT_LOG_LEVEL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_TRACE "trace" OPT_TRACE_NUM, #define OPT_TRACE_DIR "trace-dir" diff --git a/lib/log/log.c b/lib/log/log.c index 650d294120..16c0369083 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -23,6 +23,7 @@ #include <sys/un.h> #endif +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -49,6 +50,12 @@ enum eal_log_syslog { EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ }; +enum eal_log_color { + EAL_LOG_COLOR_AUTO = 0, /* default */ + EAL_LOG_COLOR_NEVER, + EAL_LOG_COLOR_ALWAYS, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -64,6 +71,7 @@ static struct rte_logs { #endif log_print_t print_func; + enum eal_log_color color_mode; enum eal_log_time_format time_format; struct timespec started; /* when log was initialized */ struct timespec previous; /* when last msg was printed */ @@ -715,6 +723,75 @@ format_timestamp(char *tsbuf, size_t tsbuflen) return 0; } +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR +}; + +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\e[31m", + [COLOR_GREEN] = "\e[32m", + [COLOR_YELLOW] = "\e[33m", + [COLOR_BLUE] = "\e[34m", + [COLOR_MAGENTA] = "\e[35m", + [COLOR_CYAN] = "\e[36m", + [COLOR_WHITE] = "\e[37m", + [COLOR_BOLD] = "\e[1m", + [COLOR_CLEAR] = "\e[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +static ssize_t +color_log_write(FILE *f, int level, char *msg) +{ + char *cp; + ssize_t ret = 0; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(stderr, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -930,14 +1007,87 @@ log_open_syslog(const char *id, bool is_terminal) } #endif +__rte_format_printf(3, 0) +static int +color_print(FILE *f, uint32_t level, const char *format, va_list ap) +{ + char *buf = NULL; + int ret; + + /* need to make temporary buffer for color scan */ + ret = vasprintf(&buf, format, ap); + if (ret > 0) { + ret = color_log_write(f, level, buf); + free(buf); + return ret; + } + + /* if vasprintf fails, print without color */ + return log_print(f, level, format, ap); +} + +__rte_format_printf(3, 0) +static int +color_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, level, format, ap); +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +static inline bool +use_color(bool is_terminal) +{ + switch (rte_logs.color_mode) { + default: + case EAL_LOG_COLOR_NEVER: + return false; + case EAL_LOG_COLOR_ALWAYS: + return true; + case EAL_LOG_COLOR_AUTO: + return is_terminal; + } + +} + /* Choose how log output is directed */ static void log_output_selection(const char *id) { + bool is_terminal; + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); + + is_terminal = _isatty(fileno(stderr)); #else - bool is_terminal = isatty(STDERR_FILENO); + is_terminal = isatty(STDERR_FILENO); /* If stderr is redirected to systemd journal then upgrade */ if (!is_terminal && is_journal(STDERR_FILENO)) { @@ -957,8 +1107,19 @@ log_output_selection(const char *id) return; } #endif - if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) - rte_logs.print_func = log_print_with_timestamp; + + if (use_color(is_terminal)) { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = color_print; + else + rte_logs.print_func = color_print_with_timestamp; + } else { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print; + else + rte_logs.print_func = log_print_with_timestamp; + } + } /* diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..525e1397fd 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -47,5 +47,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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 14d6681a5f..7fa79b20ff 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 00/15] Logging unification and improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (16 preceding siblings ...) 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 01/15] maintainers: add for log library Stephen Hemminger ` (14 more replies) 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (11 subsequent siblings) 29 siblings, 15 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: 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. I find color helpful because 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 syslog. Add myself as maintainer for log because by now have added more than previous authors... v18 - handle more Windows MSVC incompatabilities. Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r windows: common wrapper for vasprintf and asprintf 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog log: add support for systemd journal log: colorize log output MAINTAINERS | 1 + app/test/test_eal_flags.c | 64 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 - doc/guides/prog_guide/log_lib.rst | 57 ++ drivers/bus/pci/pci_common.c | 32 - lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 126 ++-- lib/eal/common/eal_options.h | 5 + lib/eal/common/eal_private.h | 10 - lib/eal/freebsd/eal.c | 64 +- lib/eal/linux/eal.c | 68 +- lib/eal/windows/eal.c | 77 +-- lib/eal/windows/getopt.c | 23 +- lib/eal/windows/include/getopt.h | 8 +- lib/eal/windows/include/rte_os_shim.h | 58 ++ lib/log/log.c | 652 +++++++++++++++++- lib/log/log_freebsd.c | 5 +- lib/log/log_internal.h | 25 +- lib/log/log_linux.c | 61 -- lib/log/log_windows.c | 18 - lib/log/meson.build | 5 +- lib/log/version.map | 4 +- 22 files changed, 973 insertions(+), 428 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 01/15] maintainers: add for log library 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (13 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7abb3aee49..54c28a601d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 02/15] windows: make getopt functions have const properties 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 01/15] maintainers: add for log library Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (12 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 03/15] windows: add os shim for localtime_r 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 01/15] maintainers: add for log library Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger ` (11 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 04/15] windows: common wrapper for vasprintf and asprintf 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 05/15] eal: make eal_log_level_parse common Stephen Hemminger ` (10 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Chenbo Xia, Nipun Gupta, Dmitry Kozlyuk, Pallavi Kadam, Bruce Richardson, David Marchand, Nick Connolly, Ranjit Menon, Khoa To Replace the windows version of asprintf() that was only usable in eal. With a more generic one that supports both vasprintf() and asprintf(). This also eliminates duplicate code. Fixes: 8f4de2dba9b9 ("bus/pci: fill bus specific information") Fixes: 9ec521006db0 ("eal/windows: hide asprintf shim") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- drivers/bus/pci/pci_common.c | 32 ------------------ lib/eal/common/eal_private.h | 10 ------ lib/eal/windows/eal.c | 28 ---------------- lib/eal/windows/include/rte_os_shim.h | 48 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 70 deletions(-) diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c index 889a48d2af..80691c75a3 100644 --- a/drivers/bus/pci/pci_common.c +++ b/drivers/bus/pci/pci_common.c @@ -45,38 +45,6 @@ const char *rte_pci_get_sysfs_path(void) return path; } -#ifdef RTE_EXEC_ENV_WINDOWS -#define asprintf pci_asprintf - -static int -__rte_format_printf(2, 3) -pci_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} -#endif /* RTE_EXEC_ENV_WINDOWS */ - static struct rte_devargs * pci_devargs_lookup(const struct rte_pci_addr *pci_addr) { diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h index 71523cfdb8..da8d77a134 100644 --- a/lib/eal/common/eal_private.h +++ b/lib/eal/common/eal_private.h @@ -737,16 +737,6 @@ void __rte_thread_init(unsigned int lcore_id, rte_cpuset_t *cpuset); */ void __rte_thread_uninit(void); -/** - * asprintf(3) replacement for Windows. - */ -#ifdef RTE_EXEC_ENV_WINDOWS -__rte_format_printf(2, 3) -int eal_asprintf(char **buffer, const char *format, ...); - -#define asprintf(buffer, format, ...) \ - eal_asprintf(buffer, format, ##__VA_ARGS__) -#endif #define EAL_LOG(level, ...) \ RTE_LOG_LINE(level, EAL, "" __VA_ARGS__) diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..8ca00c0f95 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -503,34 +503,6 @@ rte_eal_init(int argc, char **argv) return fctret; } -/* Don't use MinGW asprintf() to have identical code with all toolchains. */ -int -eal_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} - int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr, diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index e9741a9df2..65153fdb38 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -3,6 +3,7 @@ #ifndef _RTE_OS_SHIM_ #define _RTE_OS_SHIM_ +#include <stdio.h> #include <time.h> #include <rte_os.h> @@ -120,4 +121,51 @@ rte_localtime_r(const time_t *timer, struct tm *buf) } #define localtime_r(timer, buf) rte_localtime_r(timer, buf) +/* print to allocated string */ +__rte_format_printf(2, 0) +static inline int +rte_vasprintf(char **strp, const char *fmt, va_list ap) +{ + char *str; + int len, ret; + + *strp = NULL; + + /* determine size of buffer needed */ + len = _vscprintf(fmt, ap); + if (len < 0) + return -1; + + len += 1; /* for nul termination */ + str = malloc(len); + if (str == NULL) + return -1; + + ret = vsnprintf(str, len, fmt, ap); + if (ret < 0) { + free(str); + return -1; + } else { + *strp = str; + return ret; + } +} +#define vasprintf(strp, fmt, ap) rte_vasprintf(strp, fmt, ap) + +__rte_format_printf(2, 3) +static inline int +rte_asprintf(char **strp, const char *fmt, ...) +{ + int ret; + + va_list ap; + + va_start(ap, fmt); + ret = rte_vasprintf(strp, fmt, ap); + va_end(ap); + + return ret; +} + +#define asprintf(strp, fmt, ...) rte_asprintf(strp, fmt, __VA_ARGS__) #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 05/15] eal: make eal_log_level_parse common 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (9 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 8ca00c0f95..44e20643f2 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 06/15] eal: do not duplicate rte_init_alert() messages 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 05/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (8 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 07/15] eal: change rte_exit() output to match rte_log() 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 08/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (7 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..ad2be63cbb 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char msg[256]; 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); + vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 08/15] log: move handling of syslog facility out of eal 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 09/15] eal: initialize log before everything else Stephen Hemminger ` (6 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 9 files changed, 68 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..661b2db211 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 44e20643f2..14e498a643 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 09/15] eal: initialize log before everything else 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 08/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 10/15] log: drop syslog support, and make code common Stephen Hemminger ` (5 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..55ff27a4da 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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."); @@ -565,9 +574,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..b9a0fb1742 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -952,9 +961,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); @@ -1106,13 +1112,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 14e498a643..e59aba954e 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 10/15] log: drop syslog support, and make code common 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 09/15] eal: initialize log before everything else Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 11/15] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 29 +++++--- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 8 files changed, 26 insertions(+), 153 deletions(-) delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..36e3185a10 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 661b2db211..9ab512e8a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2212,9 +2212,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..f597da2e39 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -70,12 +70,13 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) { + if (rte_logs.file != NULL) + fclose(rte_logs.file); + rte_logs.file = f; return 0; } @@ -505,13 +506,20 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -525,8 +533,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_log_get_stream(); + + /* don't close stderr on the application */ + if (log_stream != stderr) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 11/15] log: add hook for printing log messages 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 10/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 12/15] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index f597da2e39..acd4c320b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -26,16 +26,21 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); +static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ + 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 = log_print, }; struct rte_eal_opt_loglevel { @@ -78,6 +83,7 @@ rte_openlog_stream(FILE *f) fclose(rte_logs.file); rte_logs.file = f; + rte_logs.print_func = log_print; return 0; } @@ -484,7 +490,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, level, format, ap); fflush(f); return ret; } @@ -513,6 +519,15 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* default log print function */ +__rte_format_printf(3, 0) +static int +log_print(FILE *f, uint32_t level __rte_unused, + const char *format, va_list ap) +{ + return vfprintf(f, format, ap); +} + /* * Called by rte_eal_init */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 12/15] log: add timestamp option 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 11/15] log: add hook for printing log messages Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 13/15] log: add optional support of syslog Stephen Hemminger ` (2 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 183 +++++++++++++++++++++++++++- lib/log/log_internal.h | 9 ++ lib/log/version.map | 1 + 10 files changed, 268 insertions(+), 7 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 36e3185a10..e54f6e8b7f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ab512e8a1..5173835c2c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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: { @@ -2216,6 +2225,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 55ff27a4da..662a829ce8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b9a0fb1742..8cbea480e0 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index e59aba954e..b251dc3e1b 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index acd4c320b6..2dca91306e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -11,6 +11,7 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -18,7 +19,7 @@ #include "log_internal.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -26,6 +27,15 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; +enum eal_log_time_format { + EAL_LOG_TIMESTAMP_NONE = 0, + EAL_LOG_TIMESTAMP_TIME, /* time since start */ + EAL_LOG_TIMESTAMP_DELTA, /* time since last message */ + EAL_LOG_TIMESTAMP_RELTIME, + EAL_LOG_TIMESTAMP_CTIME, + EAL_LOG_TIMESTAMP_ISO, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -35,6 +45,11 @@ static struct rte_logs { uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ log_print_t print_func; + + enum eal_log_time_format time_format; + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ + size_t dynamic_types_len; struct rte_log_dynamic_type *dynamic_types; } rte_logs = { @@ -375,6 +390,9 @@ RTE_INIT_PRIO(log_init, LOG) { uint32_t i; + clock_gettime(CLOCK_MONOTONIC, &rte_logs.started); + rte_logs.previous = rte_logs.started; + rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -519,6 +537,152 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + rte_logs.time_format = EAL_LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + rte_logs.time_format = EAL_LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + + +/* Format current timespec into ISO8601 format */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &rte_logs.previous); + rte_logs.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +static ssize_t +format_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (rte_logs.time_format) { + case EAL_LOG_TIMESTAMP_NONE: + return 0; + + case EAL_LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &rte_logs.previous); + rte_logs.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case EAL_LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case EAL_LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case EAL_LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -528,12 +692,29 @@ log_print(FILE *f, uint32_t level __rte_unused, return vfprintf(f, format, ap); } +/* print timestamp before message */ +__rte_format_printf(3, 0) +static int +log_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + fprintf(f, "[%s] ", tsbuf); + + return log_print(f, level, format, ap); +} + /* * Called by rte_eal_init */ void eal_log_init(const char *id __rte_unused) { + if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print_with_timestamp; + default_log_stream = stderr; #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 13/15] log: add optional support of syslog 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 12/15] log: add timestamp option Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ---- doc/guides/prog_guide/log_lib.rst | 17 +++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 121 ++++++++++++++++-- 5 files changed, 137 insertions(+), 38 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e54f6e8b7f..08f4866461 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5173835c2c..9ca7db04aa 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2221,6 +2221,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 2dca91306e..ec0d55273e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -13,15 +13,17 @@ #include <sys/queue.h> #include <unistd.h> +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#else +#include <syslog.h> +#endif + #include <rte_log.h> #include <rte_per_lcore.h> #include "log_internal.h" -#ifdef RTE_EXEC_ENV_WINDOWS -#include <rte_os_shim.h> -#endif - struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -36,14 +38,25 @@ enum eal_log_time_format { EAL_LOG_TIMESTAMP_ISO, }; +enum eal_log_syslog { + EAL_LOG_SYSLOG_NONE = 0, /* do not use syslog */ + EAL_LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + EAL_LOG_SYSLOG_ALWAYS, /* always use syslog */ + EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + /** The rte_log structure. */ static struct rte_logs { uint32_t type; /**< Bitfield with enabled logs. */ uint32_t level; /**< Log level. */ FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ +#ifndef RTE_EXEC_ENV_WINDOWS + enum eal_log_syslog syslog_opt; +#endif log_print_t print_func; enum eal_log_time_format time_format; @@ -532,9 +545,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) /* Placeholder */ int -eal_log_syslog(const char *mode __rte_unused) +eal_log_syslog(const char *str) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(str); return -1; +#else + if (str == NULL || strcmp(str, "auto") == 0) + /* log to syslog only if stderr is not a terminal */ + rte_logs.syslog_opt = EAL_LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + rte_logs.syslog_opt = EAL_LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +#endif } /* Set the log timestamp format */ @@ -706,17 +733,95 @@ log_print_with_timestamp(FILE *f, uint32_t level, return log_print(f, level, format, ap); } +#ifndef RTE_EXEC_ENV_WINDOWS +static bool +using_syslog(bool is_terminal) +{ + switch (rte_logs.syslog_opt) { + default: + return false; + + case EAL_LOG_SYSLOG_ALWAYS: + case EAL_LOG_SYSLOG_BOTH: + return true; + + case EAL_LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + /* - * Called by rte_eal_init + * wrapper for log stream to put messages into syslog + * useful for cases like: + * rte_hex_dump(rte_get_log_stream(), ...) */ -void -eal_log_init(const char *id __rte_unused) +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) { + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +static void +log_open_syslog(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + +#ifdef LOG_PERROR + if (rte_logs.syslog_opt == EAL_LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; +#endif + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; +} +#endif + +/* Choose how log output is directed */ +static void +log_output_selection(const char *id) +{ + RTE_SET_USED(id); + +#ifndef RTE_EXEC_ENV_WINDOWS + bool is_terminal = isatty(STDERR_FILENO); + + if (using_syslog(is_terminal)) { + log_open_syslog(id, is_terminal); + return; + } +#endif if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) rte_logs.print_func = log_print_with_timestamp; +} +/* + * Called by rte_eal_init + */ +void +eal_log_init(const char *id) +{ + rte_logs.print_func = log_print; default_log_stream = stderr; + log_output_selection(id); + #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 14/15] log: add support for systemd journal 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (12 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 13/15] log: add optional support of syslog Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/lib/log/log.c b/lib/log/log.c index ec0d55273e..650d294120 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -17,6 +17,10 @@ #include <rte_os_shim.h> #else #include <syslog.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> #endif #include <rte_log.h> @@ -56,6 +60,7 @@ static struct rte_logs { FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ #ifndef RTE_EXEC_ENV_WINDOWS enum eal_log_syslog syslog_opt; + int journal_fd; #endif log_print_t print_func; @@ -775,6 +780,138 @@ static cookie_io_functions_t syslog_log_func = { .close = syslog_log_close, }; +/* + * send message using journal protocol to journald + */ +static int +journal_send(uint32_t level, const char *buf, size_t len) +{ + struct iovec iov[3]; + char msg[] = "MESSAGE="; + char prio[32]; + int ret; + + iov[0].iov_base = msg; + iov[0].iov_len = strlen(msg); + + iov[1].iov_base = (char *)(uintptr_t)buf; + iov[1].iov_len = len; + + /* priority value between 0 ("emerg") and 7 ("debug") */ + iov[2].iov_base = prio; + iov[2].iov_len = snprintf(prio, sizeof(prio), + "PRIORITY=%i\n", level - 1); + + ret = writev(rte_logs.journal_fd, iov, 3); + return ret; +} + +__rte_format_printf(3, 0) +static int +journal_print(FILE *f __rte_unused, uint32_t level, const char *format, va_list ap) +{ + char buf[BUFSIZ]; + size_t len; + + len = vsnprintf(buf, sizeof(buf), format, ap); + if (len == 0) + return 0; + + /* check for truncation */ + if (len >= sizeof(buf) - 1) + len = sizeof(buf) - 1; + + /* check that message ends with newline, if not add one */ + if (buf[len - 1] != '\n') + buf[len++] = '\n'; + + return journal_send(level, buf, len); +} + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(rte_log_cur_msg_loglevel(), buf, size); +} + +static cookie_io_functions_t journal_log_func = { + .write = journal_log_write, +}; + +/* + * Check if stderr is going to system journal. + * This is the documented way to handle systemd journal + * + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(const char *id) +{ + char *syslog_id = NULL; + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + ssize_t len; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) + return -1; + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) + goto error; + + /* Send syslog identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\n", id); + if (len == 0) + goto error; + + if (write(s, syslog_id, len) != len) + goto error; + + free(syslog_id); + + /* redirect other log messages to journal */ + FILE *log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) + default_log_stream = log_stream; + + return s; + +error: + free(syslog_id); + close(s); + return -1; +} + static void log_open_syslog(const char *id, bool is_terminal) { @@ -797,11 +934,24 @@ log_open_syslog(const char *id, bool is_terminal) static void log_output_selection(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); - -#ifndef RTE_EXEC_ENV_WINDOWS +#else bool is_terminal = isatty(STDERR_FILENO); + /* If stderr is redirected to systemd journal then upgrade */ + if (!is_terminal && is_journal(STDERR_FILENO)) { + int jfd = open_journal(id); + + if (jfd < 0) { + RTE_LOG_LINE(NOTICE, EAL, "Cannot connect to journal: %s", + strerror(errno)); + } else { + rte_logs.print_func = journal_print; + return; + } + } + if (using_syslog(is_terminal)) { log_open_syslog(id, is_terminal); return; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v18 15/15] log: colorize log output 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger ` (13 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 14/15] log: add support for systemd journal Stephen Hemminger @ 2024-03-28 23:49 ` Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-28 23:49 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 24 ++++ doc/guides/prog_guide/log_lib.rst | 16 ++- lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 168 +++++++++++++++++++++++++++- lib/log/log_internal.h | 5 + lib/log/version.map | 1 + 7 files changed, 223 insertions(+), 4 deletions(-) diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 08f4866461..c6c05e2e1d 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..40727ebaae 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ @@ -101,7 +116,6 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. - Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ca7db04aa..5e7ab29ae3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -75,6 +75,7 @@ eal_long_options[] = { {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_LOG_COLOR, 2, NULL, OPT_LOG_COLOR_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[]) 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; @@ -1862,6 +1864,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) { @@ -2229,6 +2239,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..5a63c1dd3a 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -37,6 +37,8 @@ enum { OPT_LOG_LEVEL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_TRACE "trace" OPT_TRACE_NUM, #define OPT_TRACE_DIR "trace-dir" diff --git a/lib/log/log.c b/lib/log/log.c index 650d294120..75c5e2af78 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -23,6 +23,7 @@ #include <sys/un.h> #endif +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> @@ -49,6 +50,12 @@ enum eal_log_syslog { EAL_LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ }; +enum eal_log_color { + EAL_LOG_COLOR_AUTO = 0, /* default */ + EAL_LOG_COLOR_NEVER, + EAL_LOG_COLOR_ALWAYS, +}; + typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); static int log_print(FILE *f, uint32_t level, const char *format, va_list ap); @@ -64,6 +71,7 @@ static struct rte_logs { #endif log_print_t print_func; + enum eal_log_color color_mode; enum eal_log_time_format time_format; struct timespec started; /* when log was initialized */ struct timespec previous; /* when last msg was printed */ @@ -715,6 +723,76 @@ format_timestamp(char *tsbuf, size_t tsbuflen) return 0; } +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR +}; + +/* Standard terminal escape codes for colors and bold */ +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\033[31m", + [COLOR_GREEN] = "\033[32m", + [COLOR_YELLOW] = "\033[33m", + [COLOR_BLUE] = "\033[34m", + [COLOR_MAGENTA] = "\033[35m", + [COLOR_CYAN] = "\033[36m", + [COLOR_WHITE] = "\033[37m", + [COLOR_BOLD] = "\033[1m", + [COLOR_CLEAR] = "\033[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +static ssize_t +color_log_write(FILE *f, int level, char *msg) +{ + char *cp; + ssize_t ret = 0; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(stderr, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + /* default log print function */ __rte_format_printf(3, 0) static int @@ -930,14 +1008,87 @@ log_open_syslog(const char *id, bool is_terminal) } #endif +__rte_format_printf(3, 0) +static int +color_print(FILE *f, uint32_t level, const char *format, va_list ap) +{ + char *buf = NULL; + int ret; + + /* need to make temporary buffer for color scan */ + ret = vasprintf(&buf, format, ap); + if (ret > 0) { + ret = color_log_write(f, level, buf); + free(buf); + return ret; + } + + /* if vasprintf fails, print without color */ + return log_print(f, level, format, ap); +} + +__rte_format_printf(3, 0) +static int +color_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (format_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, level, format, ap); +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + rte_logs.color_mode = EAL_LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +static inline bool +use_color(bool is_terminal) +{ + switch (rte_logs.color_mode) { + default: + case EAL_LOG_COLOR_NEVER: + return false; + case EAL_LOG_COLOR_ALWAYS: + return true; + case EAL_LOG_COLOR_AUTO: + return is_terminal; + } + +} + /* Choose how log output is directed */ static void log_output_selection(const char *id) { + bool is_terminal; + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); + + is_terminal = _isatty(_fileno(stderr)); #else - bool is_terminal = isatty(STDERR_FILENO); + is_terminal = isatty(STDERR_FILENO); /* If stderr is redirected to systemd journal then upgrade */ if (!is_terminal && is_journal(STDERR_FILENO)) { @@ -957,8 +1108,19 @@ log_output_selection(const char *id) return; } #endif - if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) - rte_logs.print_func = log_print_with_timestamp; + + if (use_color(is_terminal)) { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = color_print; + else + rte_logs.print_func = color_print_with_timestamp; + } else { + if (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE) + rte_logs.print_func = log_print; + else + rte_logs.print_func = log_print_with_timestamp; + } + } /* diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..525e1397fd 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -47,5 +47,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 */ diff --git a/lib/log/version.map b/lib/log/version.map index 14d6681a5f..7fa79b20ff 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_level2str; eal_log_save_pattern; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 00/15] Logging unification and improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (17 preceding siblings ...) 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 01/15] maintainers: add for log library Stephen Hemminger ` (14 more replies) 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (10 subsequent siblings) 29 siblings, 15 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: 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 syslog. Add myself as maintainer for log because by now have added more than previous authors... v19 - split log outputs into seperate files, which makes it more OO and cleaner. - make journal log configurable (mostly for testing) Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r windows: common wrapper for vasprintf and asprintf 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog log: add support for systemd journal log: colorize log output MAINTAINERS | 1 + app/test/test_eal_flags.c | 64 +++++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 --- doc/guides/prog_guide/log_lib.rst | 71 ++++++ drivers/bus/pci/pci_common.c | 32 --- lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 137 ++++++----- lib/eal/common/eal_options.h | 7 + lib/eal/common/eal_private.h | 10 - lib/eal/freebsd/eal.c | 64 ++---- lib/eal/linux/eal.c | 68 ++---- lib/eal/windows/eal.c | 77 +------ lib/eal/windows/getopt.c | 23 +- lib/eal/windows/include/getopt.h | 8 +- lib/eal/windows/include/rte_os_shim.h | 58 +++++ lib/log/log.c | 87 ++++--- lib/log/log_color.c | 160 +++++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 28 ++- lib/log/log_journal.c | 216 ++++++++++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 34 +++ lib/log/log_stubs.c | 34 +++ lib/log/log_syslog.c | 89 ++++++++ lib/log/log_timestamp.c | 204 +++++++++++++++++ lib/log/log_windows.c | 18 -- lib/log/meson.build | 14 +- lib/log/version.map | 5 +- 28 files changed, 1172 insertions(+), 448 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_stubs.c 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.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 01/15] maintainers: add for log library 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (13 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7abb3aee49..54c28a601d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 02/15] windows: make getopt functions have const properties 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 01/15] maintainers: add for log library Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (12 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 03/15] windows: add os shim for localtime_r 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 01/15] maintainers: add for log library Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger ` (11 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 04/15] windows: common wrapper for vasprintf and asprintf 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 05/15] eal: make eal_log_level_parse common Stephen Hemminger ` (10 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Chenbo Xia, Nipun Gupta, Dmitry Kozlyuk, Pallavi Kadam, Bruce Richardson, David Marchand, Nick Connolly, Ranjit Menon, Khoa To Replace the windows version of asprintf() that was only usable in eal. With a more generic one that supports both vasprintf() and asprintf(). This also eliminates duplicate code. Fixes: 8f4de2dba9b9 ("bus/pci: fill bus specific information") Fixes: 9ec521006db0 ("eal/windows: hide asprintf shim") Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- drivers/bus/pci/pci_common.c | 32 ------------------ lib/eal/common/eal_private.h | 10 ------ lib/eal/windows/eal.c | 28 ---------------- lib/eal/windows/include/rte_os_shim.h | 48 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 70 deletions(-) diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c index 889a48d2af..80691c75a3 100644 --- a/drivers/bus/pci/pci_common.c +++ b/drivers/bus/pci/pci_common.c @@ -45,38 +45,6 @@ const char *rte_pci_get_sysfs_path(void) return path; } -#ifdef RTE_EXEC_ENV_WINDOWS -#define asprintf pci_asprintf - -static int -__rte_format_printf(2, 3) -pci_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} -#endif /* RTE_EXEC_ENV_WINDOWS */ - static struct rte_devargs * pci_devargs_lookup(const struct rte_pci_addr *pci_addr) { diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h index 71523cfdb8..da8d77a134 100644 --- a/lib/eal/common/eal_private.h +++ b/lib/eal/common/eal_private.h @@ -737,16 +737,6 @@ void __rte_thread_init(unsigned int lcore_id, rte_cpuset_t *cpuset); */ void __rte_thread_uninit(void); -/** - * asprintf(3) replacement for Windows. - */ -#ifdef RTE_EXEC_ENV_WINDOWS -__rte_format_printf(2, 3) -int eal_asprintf(char **buffer, const char *format, ...); - -#define asprintf(buffer, format, ...) \ - eal_asprintf(buffer, format, ##__VA_ARGS__) -#endif #define EAL_LOG(level, ...) \ RTE_LOG_LINE(level, EAL, "" __VA_ARGS__) diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..8ca00c0f95 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -503,34 +503,6 @@ rte_eal_init(int argc, char **argv) return fctret; } -/* Don't use MinGW asprintf() to have identical code with all toolchains. */ -int -eal_asprintf(char **buffer, const char *format, ...) -{ - int size, ret; - va_list arg; - - va_start(arg, format); - size = vsnprintf(NULL, 0, format, arg); - va_end(arg); - if (size < 0) - return -1; - size++; - - *buffer = malloc(size); - if (*buffer == NULL) - return -1; - - va_start(arg, format); - ret = vsnprintf(*buffer, size, format, arg); - va_end(arg); - if (ret != size - 1) { - free(*buffer); - return -1; - } - return ret; -} - int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr, diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index e9741a9df2..65153fdb38 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -3,6 +3,7 @@ #ifndef _RTE_OS_SHIM_ #define _RTE_OS_SHIM_ +#include <stdio.h> #include <time.h> #include <rte_os.h> @@ -120,4 +121,51 @@ rte_localtime_r(const time_t *timer, struct tm *buf) } #define localtime_r(timer, buf) rte_localtime_r(timer, buf) +/* print to allocated string */ +__rte_format_printf(2, 0) +static inline int +rte_vasprintf(char **strp, const char *fmt, va_list ap) +{ + char *str; + int len, ret; + + *strp = NULL; + + /* determine size of buffer needed */ + len = _vscprintf(fmt, ap); + if (len < 0) + return -1; + + len += 1; /* for nul termination */ + str = malloc(len); + if (str == NULL) + return -1; + + ret = vsnprintf(str, len, fmt, ap); + if (ret < 0) { + free(str); + return -1; + } else { + *strp = str; + return ret; + } +} +#define vasprintf(strp, fmt, ap) rte_vasprintf(strp, fmt, ap) + +__rte_format_printf(2, 3) +static inline int +rte_asprintf(char **strp, const char *fmt, ...) +{ + int ret; + + va_list ap; + + va_start(ap, fmt); + ret = rte_vasprintf(strp, fmt, ap); + va_end(ap); + + return ret; +} + +#define asprintf(strp, fmt, ...) rte_asprintf(strp, fmt, __VA_ARGS__) #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 05/15] eal: make eal_log_level_parse common 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (9 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 8ca00c0f95..44e20643f2 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 06/15] eal: do not duplicate rte_init_alert() messages 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 05/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (8 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 07/15] eal: change rte_exit() output to match rte_log() 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 08/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (7 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..ad2be63cbb 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char msg[256]; 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); + vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 08/15] log: move handling of syslog facility out of eal 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 09/15] eal: initialize log before everything else Stephen Hemminger ` (6 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log.c | 2 ++ lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 10 files changed, 70 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..661b2db211 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 44e20643f2..14e498a643 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..4b24e145b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,6 +13,7 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 09/15] eal: initialize log before everything else 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 08/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 10/15] log: drop syslog support, and make code common Stephen Hemminger ` (5 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..55ff27a4da 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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."); @@ -565,9 +574,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..b9a0fb1742 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -952,9 +961,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); @@ -1106,13 +1112,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 14e498a643..e59aba954e 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 10/15] log: drop syslog support, and make code common 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 09/15] eal: initialize log before everything else Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 11/15] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 41 +++++------ lib/log/log_freebsd.c | 11 --- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 9 files changed, 23 insertions(+), 179 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..36e3185a10 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 661b2db211..9ab512e8a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2212,9 +2212,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 4b24e145b6..3fe86ddcd7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -57,9 +57,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -72,8 +69,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -87,17 +82,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -507,14 +492,19 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; - #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); @@ -527,8 +517,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 33a0925c43..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include <rte_common.h> -#include "log_internal.h" - -void -eal_log_init(__rte_unused const char *id) -{ -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 11/15] log: add hook for printing log messages 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 10/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 12/15] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 14 +++++++++++++- lib/log/log_private.h | 11 +++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_private.h diff --git a/lib/log/log.c b/lib/log/log.c index 3fe86ddcd7..71b00528d0 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -18,6 +18,7 @@ #include <rte_per_lcore.h> #include "log_internal.h" +#include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS #define strdup _strdup @@ -28,16 +29,19 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; + /** 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 = log_print, }; struct rte_eal_opt_loglevel { @@ -74,6 +78,7 @@ int rte_openlog_stream(FILE *f) { rte_logs.file = f; + rte_logs.print_func = log_print; return 0; } @@ -470,7 +475,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, level, format, ap); fflush(f); return ret; } @@ -499,6 +504,13 @@ eal_log_syslog(const char *mode __rte_unused) return -1; } +/* default log print function */ +int +log_print(FILE *f, uint32_t level __rte_unused, const char *format, va_list ap) +{ + return vfprintf(f, format, ap); +} + /* * Called by rte_eal_init */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..afd833c3bd --- /dev/null +++ b/lib/log/log_private.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef LOG_PRIVATE_H +#define LOG_PRIVATE_H + +typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap); + +__rte_format_printf(3, 0) +int log_print(FILE *f, uint32_t level, const char *format, va_list ap); + +#endif /* LOG_PRIVATE_H */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 12/15] log: add timestamp option 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 11/15] log: add hook for printing log messages Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 13/15] log: add optional support of syslog Stephen Hemminger ` (2 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 10 +- lib/log/log_internal.h | 9 ++ lib/log/log_private.h | 7 + lib/log/log_timestamp.c | 204 ++++++++++++++++++++++++++++ lib/log/meson.build | 6 +- lib/log/version.map | 1 + 13 files changed, 309 insertions(+), 10 deletions(-) create mode 100644 lib/log/log_timestamp.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 36e3185a10..e54f6e8b7f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ab512e8a1..5173835c2c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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: { @@ -2216,6 +2225,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 55ff27a4da..662a829ce8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b9a0fb1742..8cbea480e0 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index e59aba954e..b251dc3e1b 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 71b00528d0..3c15f2a560 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -21,7 +21,7 @@ #include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -29,13 +29,13 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; - /** 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 = { @@ -359,7 +359,6 @@ static const struct logtype logtype_strings[] = { RTE_INIT_PRIO(log_init, LOG) { uint32_t i; - rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -517,6 +516,11 @@ log_print(FILE *f, uint32_t level __rte_unused, const char *format, va_list ap) void eal_log_init(const char *id __rte_unused) { + if (log_timestamp_enabled()) + rte_logs.print_func = log_print_with_timestamp; + else + rte_logs.print_func = log_print; + #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index afd833c3bd..070baee8dd 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -8,4 +8,11 @@ typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap) __rte_format_printf(3, 0) int log_print(FILE *f, uint32_t level, const char *format, va_list ap); +bool log_timestamp_enabled(void); + +ssize_t log_timestamp(char *tsbuf, size_t tsbuflen); + +__rte_format_printf(3, 0) +int log_print_with_timestamp(FILE *f, uint32_t level, const char *format, va_list ap); + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..ecabf72506 --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &log_time.previous); + log_time.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.previous); + log_time.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, uint32_t level, const char *format, va_list ap) +{ + char tsbuf[128]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + fprintf(f, "[%s] ", tsbuf); + + return log_print(f, level, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + clock_gettime(CLOCK_MONOTONIC, &log_time.started); + log_time.previous = log_time.started; +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 891f77a237..04235f6ee5 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,5 +2,9 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files('log.c') +sources = files( + 'log.c', + 'log_timestamp.c', +) + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 13/15] log: add optional support of syslog 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 12/15] log: add timestamp option Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------ doc/guides/prog_guide/log_lib.rst | 17 ++++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 25 +++--- lib/log/log_private.h | 4 + lib/log/log_stubs.c | 28 ++++++ lib/log/log_syslog.c | 89 +++++++++++++++++++ lib/log/meson.build | 6 ++ 9 files changed, 165 insertions(+), 41 deletions(-) create mode 100644 lib/log/log_stubs.c create mode 100644 lib/log/log_syslog.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e54f6e8b7f..08f4866461 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5173835c2c..9ca7db04aa 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2221,6 +2221,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 3c15f2a560..ddb8400d73 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -12,18 +12,19 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> -#include "log_internal.h" -#include "log_private.h" - #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif +#include "log_internal.h" +#include "log_private.h" + struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -496,13 +497,6 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } -/* Placeholder */ -int -eal_log_syslog(const char *mode __rte_unused) -{ - return -1; -} - /* default log print function */ int log_print(FILE *f, uint32_t level __rte_unused, const char *format, va_list ap) @@ -514,8 +508,17 @@ log_print(FILE *f, uint32_t level __rte_unused, const char *format, va_list ap) * Called by rte_eal_init */ void -eal_log_init(const char *id __rte_unused) +eal_log_init(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(id); +#else + bool is_terminal = isatty(STDERR_FILENO); + + if (log_syslog_enabled(is_terminal)) + log_syslog_open(id, is_terminal); + else +#endif if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 070baee8dd..0e7d10ffca 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -15,4 +15,8 @@ ssize_t log_timestamp(char *tsbuf, size_t tsbuflen); __rte_format_printf(3, 0) int log_print_with_timestamp(FILE *f, uint32_t level, const char *format, va_list ap); +bool log_syslog_enabled(bool is_tty); +void log_syslog_open(const char *id, bool is_terminal); + + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_stubs.c b/lib/log/log_stubs.c new file mode 100644 index 0000000000..cb34217af8 --- /dev/null +++ b/lib/log/log_stubs.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <regex.h> +#include <fnmatch.h> +#include <sys/queue.h> +#include <unistd.h> +#include <rte_os_shim.h> + +#include <rte_log.h> +#include <rte_per_lcore.h> + +#include "log_internal.h" +#include "log_private.h" + +/* Stubs for Windows */ +int +eal_log_syslog(const char *str __rte_unused) +{ + return -1; +} diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..33eff3a1cf --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_SYSLOG_NONE = 0, /* do not use syslog */ + LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + LOG_SYSLOG_ALWAYS, /* always use syslog */ + LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +} log_syslog_opt; + +int +eal_log_syslog(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_syslog_opt = LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + log_syslog_opt = LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + log_syslog_opt = LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +} + +bool +log_syslog_enabled(bool is_terminal) +{ + switch (log_syslog_opt) { + default: + return false; + + case LOG_SYSLOG_ALWAYS: + case LOG_SYSLOG_BOTH: + return true; + + case LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + +/* + * wrapper for log stream to put messages into syslog + * useful for cases like: + * rte_hex_dump(rte_get_log_stream(), ...) + */ +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +void +log_syslog_open(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + + if (log_syslog_opt == LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; + + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + rte_openlog_stream(log_stream); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 04235f6ee5..37507299e7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,4 +7,10 @@ sources = files( 'log_timestamp.c', ) +if is_windows + sources += files('log_stubs.c') +else + sources += files('log_syslog.c') +endif + headers = files('rte_log.h') -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 14/15] log: add support for systemd journal 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (12 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 13/15] log: add optional support of syslog Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 15/15] log: colorize log output Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/prog_guide/log_lib.rst | 14 ++ lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 5 + lib/log/log_internal.h | 3 + lib/log/log_journal.c | 216 ++++++++++++++++++++++++++++ lib/log/log_private.h | 4 + lib/log/log_stubs.c | 6 + lib/log/meson.build | 5 + lib/log/version.map | 1 + 10 files changed, 267 insertions(+) create mode 100644 lib/log/log_journal.c diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..476dedb097 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -100,6 +100,20 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. +Messages can be redirected to systemd journal which is an enhanced version of syslog with the ``--log-journal`` option. + +There are three possible settings for this option: + +*auto* + If stderr is redirected to journal by ``systemd`` service + then use journal socket to instead of stderr for log. + This is the default. + +*never* + Do not try to use journal. + +*always* + Always try to direct messages to journal socket. Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ca7db04aa..9a82118184 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_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 }, @@ -1617,6 +1618,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: case OPT_SYSLOG_NUM: + case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; @@ -1843,6 +1845,14 @@ eal_parse_common_option(int opt, const char *optarg, return -1; } break; + + case OPT_LOG_JOURNAL_NUM: + if (eal_log_journal(optarg) < 0) { + EAL_LOG(ERR, "invalid parameters for --" + OPT_LOG_JOURNAL); + return -1; + } + break; #endif case OPT_LOG_LEVEL_NUM: @@ -2223,6 +2233,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" + " --"OPT_LOG_JOURNAL"[=<when>] Enable use of systemd journal\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..c5a1c70288 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -35,6 +35,8 @@ enum { OPT_LCORES_NUM, #define OPT_LOG_LEVEL "log-level" OPT_LOG_LEVEL_NUM, +#define OPT_LOG_JOURNAL "log-journal" + OPT_LOG_JOURNAL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, #define OPT_TRACE "trace" diff --git a/lib/log/log.c b/lib/log/log.c index ddb8400d73..d97bde984e 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -515,6 +515,11 @@ eal_log_init(const char *id) #else bool is_terminal = isatty(STDERR_FILENO); +#ifdef RTE_EXEC_ENV_LINUX + if (log_journal_enabled(id)) + rte_logs.print_func = journal_print; + else +#endif if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..f7b5aafc9d --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#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" + +static enum { + LOG_JOURNAL_NEVER = 0, /* do not use journal */ + LOG_JOURNAL_AUTO, /* use if stderr is set to journal */ + LOG_JOURNAL_ALWAYS, /* always try to use journal */ +} log_journal_opt = LOG_JOURNAL_AUTO; + +static int log_journal_fd = -1; + +int +eal_log_journal(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_journal_opt = LOG_JOURNAL_AUTO; + else if (strcmp(str, "always") == 0) + log_journal_opt = LOG_JOURNAL_ALWAYS; + else if (strcmp(str, "never") == 0) + log_journal_opt = LOG_JOURNAL_NEVER; + else + return -1; + return 0; +} + +/* + * send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +static int +journal_send(uint32_t level, const char *buf, size_t len) +{ + struct iovec iov[3]; + const unsigned int niov = RTE_DIM(iov); + char msg[] = "MESSAGE="; + char pbuf[16]; /* "PRIORITY=N\n" */ + + iov[0].iov_base = msg; + iov[0].iov_len = strlen(msg); + + iov[1].iov_base = (char *)(uintptr_t)buf; + iov[1].iov_len = len; + + /* priority value between 0 ("emerg") and 7 ("debug") */ + iov[2].iov_base = pbuf; + iov[2].iov_len = snprintf(pbuf, sizeof(pbuf), + "PRIORITY=%i\n", level - 1); + + return writev(log_journal_fd, iov, niov); +} + +int +journal_print(FILE *f __rte_unused, uint32_t level, + const char *format, va_list ap) +{ + char *buf = NULL; + size_t len; + int ret; + + len = vasprintf(&buf, format, ap); + if (len == 0) + return 0; + + /* check that message ends with newline, if not add one */ + if (buf[len - 1] != '\n') { + char *nbuf; + + nbuf = realloc(buf, len + 1); + if (nbuf == NULL) { + free(buf); + return 0; + } + buf = nbuf; + buf[len++] = '\n'; + } + + ret = journal_send(level, buf, len); + free(buf); + return ret; +} + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(rte_log_cur_msg_loglevel(), buf, size); +} + +static int +journal_log_close(__rte_unused void *c) +{ + close(log_journal_fd); + log_journal_fd = -1; + 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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return -1; + } + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + perror("connect"); + close(s); + return -1; + } + + return s; +} + +bool log_journal_enabled(const char *id) +{ + FILE *log_stream; + char *syslog_id = NULL; + ssize_t len; + + if (log_journal_opt == LOG_JOURNAL_NEVER) + return false; + + if (log_journal_opt == LOG_JOURNAL_AUTO && + !is_journal(STDERR_FILENO)) + return false; + + log_journal_fd = open_journal(); + if (log_journal_fd < 0) + return false; + + /* Send identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", + id, getpid()); + if (len == 0) + goto error; + + if (write(log_journal_fd, syslog_id, len) != len) { + perror("write"); + goto error; + } + + free(syslog_id); + + /* redirect other log messages to journal */ + log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) { + rte_openlog_stream(log_stream); + return true; + } + +error: + free(syslog_id); + close(log_journal_fd); + log_journal_fd = -1; + return false; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 0e7d10ffca..988579fc08 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -18,5 +18,9 @@ int log_print_with_timestamp(FILE *f, uint32_t level, const char *format, va_lis bool log_syslog_enabled(bool is_tty); void log_syslog_open(const char *id, bool is_terminal); +bool log_journal_enabled(const char *id); + +__rte_format_printf(3, 0) +int journal_print(FILE *f, uint32_t level, const char *format, va_list ap); #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_stubs.c b/lib/log/log_stubs.c index cb34217af8..803a6e9f6b 100644 --- a/lib/log/log_stubs.c +++ b/lib/log/log_stubs.c @@ -26,3 +26,9 @@ eal_log_syslog(const char *str __rte_unused) { return -1; } + +int +eal_log_journal(const char *str __rte_unused) +{ + return -1; +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 37507299e7..5b9be7f6f1 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,10 +7,15 @@ sources = files( 'log_timestamp.c', ) +if is_linux + sources += files('log_journal.c') +endif + if is_windows sources += files('log_stubs.c') else sources += files('log_syslog.c') endif + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 14d6681a5f..7af97ece43 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -26,6 +26,7 @@ INTERNAL { global: eal_log_init; + eal_log_journal; eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v19 15/15] log: colorize log output 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger ` (13 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 14/15] log: add support for systemd journal Stephen Hemminger @ 2024-03-30 3:00 ` Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 3:00 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 24 +++++ doc/guides/prog_guide/log_lib.rst | 16 ++- lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 6 +- lib/log/log.c | 24 +++-- lib/log/log_color.c | 160 ++++++++++++++++++++++++++++ lib/log/log_internal.h | 5 + lib/log/log_private.h | 8 ++ lib/log/meson.build | 2 +- lib/log/version.map | 1 + 10 files changed, 247 insertions(+), 10 deletions(-) create mode 100644 lib/log/log_color.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 08f4866461..c6c05e2e1d 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 476dedb097..f46720fe34 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ @@ -115,7 +130,6 @@ There are three possible settings for this option: *always* Always try to direct messages to journal socket. - Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9a82118184..70fdf3f5a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_NUM }, {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM }, @@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[]) case OPT_SYSLOG_NUM: case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: + case OPT_LOG_COLOR_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1872,6 +1874,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) { @@ -2240,6 +2250,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index c5a1c70288..c0686c2544 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -33,10 +33,12 @@ enum { OPT_HUGE_UNLINK_NUM, #define OPT_LCORES "lcores" OPT_LCORES_NUM, -#define OPT_LOG_LEVEL "log-level" - OPT_LOG_LEVEL_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_LOG_JOURNAL "log-journal" OPT_LOG_JOURNAL_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" diff --git a/lib/log/log.c b/lib/log/log.c index d97bde984e..a2254b461b 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -510,10 +510,14 @@ log_print(FILE *f, uint32_t level __rte_unused, const char *format, va_list ap) void eal_log_init(const char *id) { + bool is_terminal; + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); + + is_terminal = _isatty(_fileno(stderr)); #else - bool is_terminal = isatty(STDERR_FILENO); + is_terminal = isatty(STDERR_FILENO); #ifdef RTE_EXEC_ENV_LINUX if (log_journal_enabled(id)) @@ -523,11 +527,19 @@ eal_log_init(const char *id) if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else -#endif - if (log_timestamp_enabled()) - rte_logs.print_func = log_print_with_timestamp; - else - rte_logs.print_func = log_print; +#endif /* RTE_EXEC_ENV_WINDOWS */ + + if (log_color_enabled(is_terminal)) { + if (log_timestamp_enabled()) + rte_logs.print_func = color_print_with_timestamp; + else + rte_logs.print_func = color_print; + } else { + if (log_timestamp_enabled()) + rte_logs.print_func = log_print_with_timestamp; + else + rte_logs.print_func = log_print; + } #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..2bed521bc0 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, /* default */ + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +/* Standard terminal escape codes for colors and bold */ +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\033[31m", + [COLOR_GREEN] = "\033[32m", + [COLOR_YELLOW] = "\033[33m", + [COLOR_BLUE] = "\033[34m", + [COLOR_MAGENTA] = "\033[35m", + [COLOR_CYAN] = "\033[36m", + [COLOR_WHITE] = "\033[37m", + [COLOR_BOLD] = "\033[1m", + [COLOR_CLEAR] = "\033[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +static ssize_t +color_log_write(FILE *f, int level, char *msg) +{ + char *cp; + ssize_t ret = 0; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(stderr, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + switch (log_color_mode) { + default: + case LOG_COLOR_NEVER: + return false; + case LOG_COLOR_ALWAYS: + return true; + case LOG_COLOR_AUTO: + return is_terminal; + } +} + +int +color_print(FILE *f, uint32_t level, const char *format, va_list ap) +{ + char *buf = NULL; + int ret; + + /* need to make temporary buffer for color scan */ + ret = vasprintf(&buf, format, ap); + if (ret > 0) { + ret = color_log_write(f, level, buf); + free(buf); + return ret; + } + + /* if vasprintf fails, print without color */ + return log_print(f, level, format, ap); +} + +int +color_print_with_timestamp(FILE *f, uint32_t level, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, level, format, ap); +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 82fdc21ac2..bba7041ea3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 988579fc08..bb93584f29 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -23,4 +23,12 @@ bool log_journal_enabled(const char *id); __rte_format_printf(3, 0) int journal_print(FILE *f, uint32_t level, const char *format, va_list ap); +bool log_color_enabled(bool is_tty); + +__rte_format_printf(3, 0) +int color_print(FILE *f, uint32_t level, const char *format, va_list ap); + +__rte_format_printf(3, 0) +int color_print_with_timestamp(FILE *f, uint32_t level, const char *format, va_list ap); + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 5b9be7f6f1..3467cb5e9d 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) @@ -17,5 +18,4 @@ else sources += files('log_syslog.c') endif - headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 7af97ece43..eb3200dcde 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; eal_log_level2str; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 00/14] Logging unification and improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (18 preceding siblings ...) 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 01/14] maintainers: add for log library Stephen Hemminger ` (13 more replies) 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (9 subsequent siblings) 29 siblings, 14 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: 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 syslog. Add myself as maintainer for log because by now have added more than previous authors. v20 - avoid use vasprintf if possible, because it requires extra patch for Windows, and increases risk of missed message if malloc pool is corrupted. - fix build on FreeBSD. Stephen Hemminger (14): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog log: add support for systemd journal log: colorize log output MAINTAINERS | 1 + app/test/test_eal_flags.c | 64 +++++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 --- doc/guides/prog_guide/log_lib.rst | 71 ++++++ lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 137 +++++++----- lib/eal/common/eal_options.h | 7 + lib/eal/freebsd/eal.c | 64 ++---- lib/eal/linux/eal.c | 68 ++---- lib/eal/windows/eal.c | 49 +--- 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 | 80 ++++--- lib/log/log_color.c | 148 ++++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 28 ++- lib/log/log_journal.c | 200 +++++++++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 34 +++ lib/log/log_stubs.c | 37 +++ lib/log/log_syslog.c | 88 ++++++++ lib/log/log_timestamp.c | 210 ++++++++++++++++++ lib/log/log_windows.c | 18 -- lib/log/meson.build | 14 +- lib/log/version.map | 5 +- 26 files changed, 1097 insertions(+), 378 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_stubs.c 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.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 01/14] maintainers: add for log library 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 02/14] windows: make getopt functions have const properties Stephen Hemminger ` (12 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7abb3aee49..54c28a601d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 02/14] windows: make getopt functions have const properties 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 01/14] maintainers: add for log library Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 03/14] windows: add os shim for localtime_r Stephen Hemminger ` (11 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 03/14] windows: add os shim for localtime_r 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 01/14] maintainers: add for log library Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 02/14] windows: make getopt functions have const properties Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 04/14] eal: make eal_log_level_parse common Stephen Hemminger ` (10 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 04/14] eal: make eal_log_level_parse common 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 03/14] windows: add os shim for localtime_r Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 05/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (9 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/common/eal_common_options.c | 46 +++++++++++++++++++++++++++++ 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, 47 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..5435399b85 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) @@ -2173,6 +2218,7 @@ rte_vect_set_max_simd_bitwidth(uint16_t bitwidth) return 0; } + void eal_common_usage(void) { diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..85171b2768 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 05/14] eal: do not duplicate rte_init_alert() messages 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 04/14] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 06/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (8 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 06/14] eal: change rte_exit() output to match rte_log() 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 05/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 07/14] log: move handling of syslog facility out of eal Stephen Hemminger ` (7 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..ad2be63cbb 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char msg[256]; 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); + vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 07/14] log: move handling of syslog facility out of eal 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 06/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 08/14] eal: initialize log before everything else Stephen Hemminger ` (6 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log.c | 2 ++ lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 10 files changed, 70 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5435399b85..661b2db211 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 85171b2768..2519a30017 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..4b24e145b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,6 +13,7 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 08/14] eal: initialize log before everything else 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 07/14] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 09/14] log: drop syslog support, and make code common Stephen Hemminger ` (5 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..55ff27a4da 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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."); @@ -565,9 +574,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..b9a0fb1742 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -952,9 +961,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); @@ -1106,13 +1112,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 2519a30017..74b3ece30c 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 09/14] log: drop syslog support, and make code common 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 08/14] eal: initialize log before everything else Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 10/14] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 41 +++++------ lib/log/log_freebsd.c | 11 --- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 9 files changed, 23 insertions(+), 179 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..36e3185a10 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 661b2db211..9ab512e8a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2212,9 +2212,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 4b24e145b6..3fe86ddcd7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -57,9 +57,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -72,8 +69,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -87,17 +82,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -507,14 +492,19 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; - #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); @@ -527,8 +517,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 33a0925c43..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include <rte_common.h> -#include "log_internal.h" - -void -eal_log_init(__rte_unused const char *id) -{ -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 10/14] log: add hook for printing log messages 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 09/14] log: drop syslog support, and make code common Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 11/14] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 7 ++++++- lib/log/log_private.h | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_private.h diff --git a/lib/log/log.c b/lib/log/log.c index 3fe86ddcd7..979b20c3ef 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -18,6 +18,7 @@ #include <rte_per_lcore.h> #include "log_internal.h" +#include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS #define strdup _strdup @@ -28,16 +29,19 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; + /** 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 { @@ -74,6 +78,7 @@ int rte_openlog_stream(FILE *f) { rte_logs.file = f; + rte_logs.print_func = vfprintf; return 0; } @@ -470,7 +475,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; } diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..67d2463b2f --- /dev/null +++ b/lib/log/log_private.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef LOG_PRIVATE_H +#define LOG_PRIVATE_H + +/* Note: same as vfprintf() */ +typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); + +#endif /* LOG_PRIVATE_H */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 11/14] log: add timestamp option 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 10/14] log: add hook for printing log messages Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 12/14] log: add optional support of syslog Stephen Hemminger ` (2 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Bruce Richardson, Dmitry Kozlyuk, Tyler Retzlaff, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 10 +- lib/log/log_internal.h | 9 ++ lib/log/log_private.h | 11 ++ lib/log/log_timestamp.c | 210 ++++++++++++++++++++++++++++ lib/log/meson.build | 6 +- lib/log/version.map | 1 + 13 files changed, 319 insertions(+), 10 deletions(-) create mode 100644 lib/log/log_timestamp.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 36e3185a10..e54f6e8b7f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ab512e8a1..5173835c2c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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: { @@ -2216,6 +2225,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 55ff27a4da..662a829ce8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b9a0fb1742..8cbea480e0 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 74b3ece30c..4283c920c8 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 979b20c3ef..71db4894fa 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -21,7 +21,7 @@ #include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -29,13 +29,13 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; - /** 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 = { @@ -359,7 +359,6 @@ static const struct logtype logtype_strings[] = { RTE_INIT_PRIO(log_init, LOG) { uint32_t i; - rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -510,6 +509,11 @@ eal_log_syslog(const char *mode __rte_unused) void eal_log_init(const char *id __rte_unused) { + 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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67d2463b2f..67cfe72fc6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -3,7 +3,18 @@ #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 + /* Note: same as vfprintf() */ typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); +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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..04d8eba37b --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &log_time.previous); + log_time.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.previous); + log_time.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + clock_gettime(CLOCK_MONOTONIC, &log_time.started); + log_time.previous = log_time.started; +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 891f77a237..04235f6ee5 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,5 +2,9 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files('log.c') +sources = files( + 'log.c', + 'log_timestamp.c', +) + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 12/14] log: add optional support of syslog 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 11/14] log: add timestamp option Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 13/14] log: add support for systemd journal Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 14/14] log: colorize log output Stephen Hemminger 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------ doc/guides/prog_guide/log_lib.rst | 17 ++++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 25 +++--- lib/log/log_private.h | 4 + lib/log/log_stubs.c | 28 ++++++ lib/log/log_syslog.c | 88 +++++++++++++++++++ lib/log/meson.build | 6 ++ 9 files changed, 164 insertions(+), 41 deletions(-) create mode 100644 lib/log/log_stubs.c create mode 100644 lib/log/log_syslog.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e54f6e8b7f..08f4866461 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 5173835c2c..9ca7db04aa 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2221,6 +2221,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 71db4894fa..4430b251a1 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -12,18 +12,19 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> -#include "log_internal.h" -#include "log_private.h" - #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif +#include "log_internal.h" +#include "log_private.h" + struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -496,19 +497,21 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } -/* Placeholder */ -int -eal_log_syslog(const char *mode __rte_unused) -{ - return -1; -} - /* * Called by rte_eal_init */ void -eal_log_init(const char *id __rte_unused) +eal_log_init(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(id); +#else + bool is_terminal = isatty(STDERR_FILENO); + + if (log_syslog_enabled(is_terminal)) + log_syslog_open(id, is_terminal); + else +#endif if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67cfe72fc6..c4eb533529 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -17,4 +17,8 @@ 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_syslog_enabled(bool is_tty); +void log_syslog_open(const char *id, bool is_terminal); + + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_stubs.c b/lib/log/log_stubs.c new file mode 100644 index 0000000000..cb34217af8 --- /dev/null +++ b/lib/log/log_stubs.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <regex.h> +#include <fnmatch.h> +#include <sys/queue.h> +#include <unistd.h> +#include <rte_os_shim.h> + +#include <rte_log.h> +#include <rte_per_lcore.h> + +#include "log_internal.h" +#include "log_private.h" + +/* Stubs for Windows */ +int +eal_log_syslog(const char *str __rte_unused) +{ + return -1; +} diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..fb69921e05 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_SYSLOG_NONE = 0, /* do not use syslog */ + LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + LOG_SYSLOG_ALWAYS, /* always use syslog */ + LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +} log_syslog_opt; + +int +eal_log_syslog(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_syslog_opt = LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + log_syslog_opt = LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + log_syslog_opt = LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +} + +bool +log_syslog_enabled(bool is_terminal) +{ + switch (log_syslog_opt) { + default: + return false; + + case LOG_SYSLOG_ALWAYS: + case LOG_SYSLOG_BOTH: + return true; + + case LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + +/* + * When syslog is used, the log stream is redirected to a + * pseudo FILE handle that calls these functions. + */ +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +void +log_syslog_open(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + + if (log_syslog_opt == LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; + + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + rte_openlog_stream(log_stream); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 04235f6ee5..37507299e7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,4 +7,10 @@ sources = files( 'log_timestamp.c', ) +if is_windows + sources += files('log_stubs.c') +else + sources += files('log_syslog.c') +endif + headers = files('rte_log.h') -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 13/14] log: add support for systemd journal 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 12/14] log: add optional support of syslog Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 2024-04-01 11:18 ` Luca Boccassi 2024-03-30 16:42 ` [PATCH v20 14/14] log: colorize log output Stephen Hemminger 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/prog_guide/log_lib.rst | 14 ++ lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 5 + lib/log/log_internal.h | 3 + lib/log/log_journal.c | 200 ++++++++++++++++++++++++++++ lib/log/log_private.h | 2 + lib/log/log_stubs.c | 11 +- lib/log/meson.build | 10 +- lib/log/version.map | 1 + 10 files changed, 255 insertions(+), 4 deletions(-) create mode 100644 lib/log/log_journal.c diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..476dedb097 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -100,6 +100,20 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. +Messages can be redirected to systemd journal which is an enhanced version of syslog with the ``--log-journal`` option. + +There are three possible settings for this option: + +*auto* + If stderr is redirected to journal by ``systemd`` service + then use journal socket to instead of stderr for log. + This is the default. + +*never* + Do not try to use journal. + +*always* + Always try to direct messages to journal socket. Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9ca7db04aa..9a82118184 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_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 }, @@ -1617,6 +1618,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: case OPT_SYSLOG_NUM: + case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; @@ -1843,6 +1845,14 @@ eal_parse_common_option(int opt, const char *optarg, return -1; } break; + + case OPT_LOG_JOURNAL_NUM: + if (eal_log_journal(optarg) < 0) { + EAL_LOG(ERR, "invalid parameters for --" + OPT_LOG_JOURNAL); + return -1; + } + break; #endif case OPT_LOG_LEVEL_NUM: @@ -2223,6 +2233,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" + " --"OPT_LOG_JOURNAL"[=<when>] Enable use of systemd journal\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..c5a1c70288 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -35,6 +35,8 @@ enum { OPT_LCORES_NUM, #define OPT_LOG_LEVEL "log-level" OPT_LOG_LEVEL_NUM, +#define OPT_LOG_JOURNAL "log-journal" + OPT_LOG_JOURNAL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, #define OPT_TRACE "trace" diff --git a/lib/log/log.c b/lib/log/log.c index 4430b251a1..13d68402d9 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -508,6 +508,11 @@ eal_log_init(const char *id) #else bool is_terminal = isatty(STDERR_FILENO); +#ifdef RTE_EXEC_ENV_LINUX + if (log_journal_enabled()) + log_journal_open(id); + else +#endif if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..2475174fce --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,200 @@ +/* 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" + +static enum { + LOG_JOURNAL_NEVER = 0, /* do not use journal */ + LOG_JOURNAL_AUTO, /* use if stderr is set to journal */ + LOG_JOURNAL_ALWAYS, /* always try to use journal */ +} log_journal_opt = LOG_JOURNAL_AUTO; + +static int log_journal_fd = -1; + +int +eal_log_journal(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_journal_opt = LOG_JOURNAL_AUTO; + else if (strcmp(str, "always") == 0) + log_journal_opt = LOG_JOURNAL_ALWAYS; + else if (strcmp(str, "never") == 0) + log_journal_opt = LOG_JOURNAL_NEVER; + else + return -1; + return 0; +} + +/* + * send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +static int +journal_send(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[16]; /* "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(log_journal_fd, iov, n); +} + + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(buf, size); +} + +static int +journal_log_close(__rte_unused void *c) +{ + close(log_journal_fd); + log_journal_fd = -1; + 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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return -1; + } + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + perror("connect"); + close(s); + return -1; + } + + return s; +} + +bool log_journal_enabled(void) +{ + if (log_journal_opt == LOG_JOURNAL_NEVER) + return false; + + if (log_journal_opt == LOG_JOURNAL_AUTO && + !is_journal(STDERR_FILENO)) + return false; + + log_journal_fd = open_journal(); + if (log_journal_fd < 0) + return false; + + return true; +} + +void log_journal_open(const char *id) +{ + FILE *log_stream; + char *syslog_id = NULL; + ssize_t len; + + /* Send identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", + id, getpid()); + if (len == 0) + goto error; + + if (write(log_journal_fd, syslog_id, len) != len) { + perror("write"); + goto error; + } + + free(syslog_id); + + /* redirect other log messages to journal */ + log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) { + rte_openlog_stream(log_stream); + return; + } + +error: + free(syslog_id); + close(log_journal_fd); + log_journal_fd = -1; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index c4eb533529..91976ab313 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -20,5 +20,7 @@ int log_print_with_timestamp(FILE *f, const char *format, va_list ap); bool log_syslog_enabled(bool is_tty); void log_syslog_open(const char *id, bool is_terminal); +bool log_journal_enabled(void); +void log_journal_open(const char *id); #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_stubs.c b/lib/log/log_stubs.c index cb34217af8..6b2099f57b 100644 --- a/lib/log/log_stubs.c +++ b/lib/log/log_stubs.c @@ -20,9 +20,18 @@ #include "log_internal.h" #include "log_private.h" -/* Stubs for Windows */ +#ifdef RTE_EXEC_ENV_WINDOWS int eal_log_syslog(const char *str __rte_unused) { return -1; } +#endif + +#ifndef RTE_EXEC_ENV_LINUX +int +eal_log_journal(const char *str __rte_unused) +{ + return -1; +} +#endif diff --git a/lib/log/meson.build b/lib/log/meson.build index 37507299e7..0a80027326 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,10 +7,14 @@ sources = files( 'log_timestamp.c', ) -if is_windows - sources += files('log_stubs.c') -else +if not is_windows sources += files('log_syslog.c') endif +if is_linux + sources += files('log_journal.c') +else + sources += files('log_stubs.c') +endif + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 14d6681a5f..7af97ece43 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -26,6 +26,7 @@ INTERNAL { global: eal_log_init; + eal_log_journal; eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v20 13/14] log: add support for systemd journal 2024-03-30 16:42 ` [PATCH v20 13/14] log: add support for systemd journal Stephen Hemminger @ 2024-04-01 11:18 ` Luca Boccassi 0 siblings, 0 replies; 445+ messages in thread From: Luca Boccassi @ 2024-04-01 11:18 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Sat, 30 Mar 2024 at 16:46, Stephen Hemminger <stephen@networkplumber.org> wrote: > > 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/ > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- > doc/guides/prog_guide/log_lib.rst | 14 ++ > lib/eal/common/eal_common_options.c | 11 ++ > lib/eal/common/eal_options.h | 2 + > lib/log/log.c | 5 + > lib/log/log_internal.h | 3 + > lib/log/log_journal.c | 200 ++++++++++++++++++++++++++++ > lib/log/log_private.h | 2 + > lib/log/log_stubs.c | 11 +- > lib/log/meson.build | 10 +- > lib/log/version.map | 1 + > 10 files changed, 255 insertions(+), 4 deletions(-) > create mode 100644 lib/log/log_journal.c This is very nice work, I like it a lot! > +/* > + * send structured message using journal protocol > + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ > + */ > +static int > +journal_send(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[16]; /* "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(log_journal_fd, iov, n); > +} Doesn't need to be implemented immediately, but the nicest thing about talking directly to the journal is the ability to send lots of arbitrary and useful metadata together with a message, so would be nice if the logging function took an optional string vector that is appended, or some other such mechanism. A very useful example is creating a UUID and then setting MESSAGE_ID=uuid when logging particularly important messages that are useful to filter by this type - for example, when an interface state changes to up/down. That way, one can do 'journalctl MESSAGE_ID=abc..' and get all messages about interface state changes. A project can also ship a catalog file that adds additional context to each ID, that is automatically parsed and displayed to users. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v20 14/14] log: colorize log output 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger ` (12 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 13/14] log: add support for systemd journal Stephen Hemminger @ 2024-03-30 16:42 ` Stephen Hemminger 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-03-30 16:42 UTC (permalink / raw) To: dev; +Cc: 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 24 +++++ doc/guides/prog_guide/log_lib.rst | 16 ++- lib/eal/common/eal_common_options.c | 11 +++ lib/eal/common/eal_options.h | 6 +- lib/log/log.c | 24 +++-- lib/log/log_color.c | 148 ++++++++++++++++++++++++++++ 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, 235 insertions(+), 9 deletions(-) create mode 100644 lib/log/log_color.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 08f4866461..c6c05e2e1d 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 476dedb097..f46720fe34 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ @@ -115,7 +130,6 @@ There are three possible settings for this option: *always* Always try to direct messages to journal socket. - Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 9a82118184..70fdf3f5a1 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_NUM }, {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM }, @@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[]) case OPT_SYSLOG_NUM: case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: + case OPT_LOG_COLOR_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1872,6 +1874,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) { @@ -2240,6 +2250,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index c5a1c70288..c0686c2544 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -33,10 +33,12 @@ enum { OPT_HUGE_UNLINK_NUM, #define OPT_LCORES "lcores" OPT_LCORES_NUM, -#define OPT_LOG_LEVEL "log-level" - OPT_LOG_LEVEL_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_LOG_JOURNAL "log-journal" OPT_LOG_JOURNAL_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" diff --git a/lib/log/log.c b/lib/log/log.c index 13d68402d9..856c0a0a29 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -503,10 +503,14 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) void eal_log_init(const char *id) { + bool is_terminal; + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); + + is_terminal = _isatty(_fileno(stderr)); #else - bool is_terminal = isatty(STDERR_FILENO); + is_terminal = isatty(STDERR_FILENO); #ifdef RTE_EXEC_ENV_LINUX if (log_journal_enabled()) @@ -516,11 +520,19 @@ eal_log_init(const char *id) if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else -#endif - if (log_timestamp_enabled()) - rte_logs.print_func = log_print_with_timestamp; - else - rte_logs.print_func = vfprintf; +#endif /* RTE_EXEC_ENV_WINDOWS */ + + if (log_color_enabled(is_terminal)) { + if (log_timestamp_enabled()) + rte_logs.print_func = color_print_with_timestamp; + else + rte_logs.print_func = color_print; + } 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, diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..897a10a342 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, /* default */ + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +/* Standard terminal escape codes for colors and bold */ +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\033[31m", + [COLOR_GREEN] = "\033[32m", + [COLOR_YELLOW] = "\033[33m", + [COLOR_BLUE] = "\033[34m", + [COLOR_MAGENTA] = "\033[35m", + [COLOR_CYAN] = "\033[36m", + [COLOR_WHITE] = "\033[37m", + [COLOR_BOLD] = "\033[1m", + [COLOR_CLEAR] = "\033[0m", +}; + +__rte_format_printf(3, 4) +static int color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + switch (log_color_mode) { + default: + case LOG_COLOR_NEVER: + return false; + case LOG_COLOR_ALWAYS: + return true; + case LOG_COLOR_AUTO: + return is_terminal; + } +} + +int +color_print(FILE *f, const char *format, va_list ap) +{ + const int level = rte_log_cur_msg_loglevel(); + char *cp, *msg; + char buf[LINE_MAX]; + int ret = 0; + + vsnprintf(buf, LINE_MAX, format, ap); + msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(f, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + +int +color_print_with_timestamp(FILE *f, + const char *format, va_list ap) +{ + char tsbuf[128]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, format, ap); +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 82fdc21ac2..bba7041ea3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 91976ab313..5952bfb453 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -23,4 +23,12 @@ void log_syslog_open(const char *id, bool is_terminal); bool log_journal_enabled(void); void log_journal_open(const char *id); +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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 0a80027326..4041feed13 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 7af97ece43..eb3200dcde 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; eal_log_level2str; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 00/14] Log library unification ane enhancements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (19 preceding siblings ...) 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 01/14] maintainers: add for log library Stephen Hemminger ` (13 more replies) 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (8 subsequent siblings) 29 siblings, 14 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev; +Cc: 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 syslog if output is going to a terminal. Add myself as maintainer for log because by now have added more than previous authors. v21 - rebase and clean up a couple of blank lines that snuck in Stephen Hemminger (14): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog log: add support for systemd journal log: colorize log output MAINTAINERS | 1 + app/test/test_eal_flags.c | 64 +++++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 --- doc/guides/prog_guide/log_lib.rst | 72 ++++++ lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 136 +++++++----- lib/eal/common/eal_options.h | 7 + lib/eal/freebsd/eal.c | 64 ++---- lib/eal/linux/eal.c | 68 ++---- lib/eal/windows/eal.c | 49 +--- 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 | 80 ++++--- lib/log/log_color.c | 148 ++++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 28 ++- lib/log/log_journal.c | 200 +++++++++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 34 +++ lib/log/log_stubs.c | 37 +++ lib/log/log_syslog.c | 88 ++++++++ lib/log/log_timestamp.c | 210 ++++++++++++++++++ lib/log/log_windows.c | 18 -- lib/log/meson.build | 14 +- lib/log/version.map | 5 +- 26 files changed, 1097 insertions(+), 378 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_stubs.c 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.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 01/14] maintainers: add for log library 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-06 5:35 ` Morten Brørup 2024-06-04 0:44 ` [PATCH v21 02/14] windows: make getopt functions have const properties Stephen Hemminger ` (12 subsequent siblings) 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c9adff9846..92e502c64b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -181,6 +181,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v21 01/14] maintainers: add for log library 2024-06-04 0:44 ` [PATCH v21 01/14] maintainers: add for log library Stephen Hemminger @ 2024-06-06 5:35 ` Morten Brørup 0 siblings, 0 replies; 445+ messages in thread From: Morten Brørup @ 2024-06-06 5:35 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Tyler Retzlaff, Thomas Monjalon > From: Stephen Hemminger [mailto:stephen@networkplumber.org] > Sent: Tuesday, 4 June 2024 02.45 > > "You touch it you own it" > Add myself as maintainer for log library. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > --- For the series, Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 02/14] windows: make getopt functions have const properties 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 01/14] maintainers: add for log library Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 2:31 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 03/14] windows: add os shim for localtime_r Stephen Hemminger ` (11 subsequent siblings) 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v21 02/14] windows: make getopt functions have const properties 2024-06-04 0:44 ` [PATCH v21 02/14] windows: make getopt functions have const properties Stephen Hemminger @ 2024-06-04 2:31 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 2:31 UTC (permalink / raw) To: dev; +Cc: Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam On Mon, 3 Jun 2024 17:44:50 -0700 Stephen Hemminger <stephen@networkplumber.org> wrote: > 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. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Ignore checkpatch complaints about this file. It is better for the code to not change from the original FreeBSD. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 03/14] windows: add os shim for localtime_r 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 01/14] maintainers: add for log library Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 02/14] windows: make getopt functions have const properties Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 04/14] eal: make eal_log_level_parse common Stephen Hemminger ` (10 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 04/14] eal: make eal_log_level_parse common 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (2 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 03/14] windows: add os shim for localtime_r Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 05/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (9 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/common/eal_common_options.c | 45 +++++++++++++++++++++++++++++ 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, 46 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index e541f07939..cb3c52c67a 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index bab77118e9..9825bcea0b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fd422f1f62..bffeb1f34e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 52f0e7462d..85171b2768 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 05/14] eal: do not duplicate rte_init_alert() messages 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (3 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 04/14] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 06/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (8 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 9825bcea0b..17b56f38aa 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index bffeb1f34e..23dc26b124 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 06/14] eal: change rte_exit() output to match rte_log() 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (4 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 05/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 07/14] log: move handling of syslog facility out of eal Stephen Hemminger ` (7 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..ad2be63cbb 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char msg[256]; 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); + vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 07/14] log: move handling of syslog facility out of eal 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (5 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 06/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 08/14] eal: initialize log before everything else Stephen Hemminger ` (6 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log.c | 2 ++ lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 10 files changed, 70 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index cb3c52c67a..02e0f6fe55 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 17b56f38aa..6552f9c138 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 23dc26b124..3d0c34063e 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1106,8 +1106,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 85171b2768..2519a30017 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..4b24e145b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,6 +13,7 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 0648f8831a..9c6c49bf06 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 08/14] eal: initialize log before everything else 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (6 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 07/14] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 09/14] log: drop syslog support, and make code common Stephen Hemminger ` (5 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 6552f9c138..55ff27a4da 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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."); @@ -565,9 +574,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 3d0c34063e..b9a0fb1742 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -952,9 +961,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); @@ -1106,13 +1112,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 2519a30017..74b3ece30c 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 09/14] log: drop syslog support, and make code common 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (7 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 08/14] eal: initialize log before everything else Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 2:30 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 10/14] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 41 +++++------ lib/log/log_freebsd.c | 11 --- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 9 files changed, 23 insertions(+), 179 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 6cb4b06757..36e3185a10 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 02e0f6fe55..89e0465f04 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2211,9 +2211,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 4b24e145b6..3fe86ddcd7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -57,9 +57,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -72,8 +69,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -87,17 +82,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -507,14 +492,19 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; - #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); @@ -527,8 +517,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 33a0925c43..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include <rte_common.h> -#include "log_internal.h" - -void -eal_log_init(__rte_unused const char *id) -{ -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 9c6c49bf06..32b9680c31 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v21 09/14] log: drop syslog support, and make code common 2024-06-04 0:44 ` [PATCH v21 09/14] log: drop syslog support, and make code common Stephen Hemminger @ 2024-06-04 2:30 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 2:30 UTC (permalink / raw) To: dev; +Cc: Tyler Retzlaff On Mon, 3 Jun 2024 17:44:57 -0700 Stephen Hemminger <stephen@networkplumber.org> wrote: > This patch makes the log setup code common across all platforms. > > Drops syslog support for now, will come back in later patch. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Ignore checkpatch complaints on this patch. It is better for the test code in test_eal_flags.c to match the existing style, rather than being different because checkpatch wants it to be static. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 10/14] log: add hook for printing log messages 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (8 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 09/14] log: drop syslog support, and make code common Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 11/14] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- lib/log/log.c | 7 ++++++- lib/log/log_private.h | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_private.h diff --git a/lib/log/log.c b/lib/log/log.c index 3fe86ddcd7..979b20c3ef 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -18,6 +18,7 @@ #include <rte_per_lcore.h> #include "log_internal.h" +#include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS #define strdup _strdup @@ -28,16 +29,19 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; + /** 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 { @@ -74,6 +78,7 @@ int rte_openlog_stream(FILE *f) { rte_logs.file = f; + rte_logs.print_func = vfprintf; return 0; } @@ -470,7 +475,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; } diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..67d2463b2f --- /dev/null +++ b/lib/log/log_private.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef LOG_PRIVATE_H +#define LOG_PRIVATE_H + +/* Note: same as vfprintf() */ +typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); + +#endif /* LOG_PRIVATE_H */ -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 11/14] log: add timestamp option 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (9 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 10/14] log: add hook for printing log messages Stephen Hemminger @ 2024-06-04 0:44 ` Stephen Hemminger 2024-06-04 2:33 ` Stephen Hemminger 2024-06-04 0:45 ` [PATCH v21 12/14] log: add optional support of syslog Stephen Hemminger ` (2 subsequent siblings) 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:44 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 10 +- lib/log/log_internal.h | 9 ++ lib/log/log_private.h | 11 ++ lib/log/log_timestamp.c | 210 ++++++++++++++++++++++++++++ lib/log/meson.build | 6 +- lib/log/version.map | 1 + 13 files changed, 319 insertions(+), 10 deletions(-) create mode 100644 lib/log/log_timestamp.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 36e3185a10..e54f6e8b7f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 89e0465f04..b6c648dcf3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 55ff27a4da..662a829ce8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index b9a0fb1742..8cbea480e0 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 74b3ece30c..4283c920c8 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 979b20c3ef..71db4894fa 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -21,7 +21,7 @@ #include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -29,13 +29,13 @@ struct rte_log_dynamic_type { uint32_t loglevel; }; - /** 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 = { @@ -359,7 +359,6 @@ static const struct logtype logtype_strings[] = { RTE_INIT_PRIO(log_init, LOG) { uint32_t i; - rte_log_set_global_level(RTE_LOG_DEBUG); rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, @@ -510,6 +509,11 @@ eal_log_syslog(const char *mode __rte_unused) void eal_log_init(const char *id __rte_unused) { + 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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67d2463b2f..67cfe72fc6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -3,7 +3,18 @@ #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 + /* Note: same as vfprintf() */ typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); +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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..04d8eba37b --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &log_time.previous); + log_time.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.previous); + log_time.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + clock_gettime(CLOCK_MONOTONIC, &log_time.started); + log_time.previous = log_time.started; +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 891f77a237..04235f6ee5 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,5 +2,9 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files('log.c') +sources = files( + 'log.c', + 'log_timestamp.c', +) + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 32b9680c31..14d6681a5f 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v21 11/14] log: add timestamp option 2024-06-04 0:44 ` [PATCH v21 11/14] log: add timestamp option Stephen Hemminger @ 2024-06-04 2:33 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 2:33 UTC (permalink / raw) To: dev; +Cc: Tyler Retzlaff, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam On Mon, 3 Jun 2024 17:44:59 -0700 Stephen Hemminger <stephen@networkplumber.org> wrote: > 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 > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Ignore bogus checkpatch warning from this patch. Checkpatch thinks that #include <stdio.h> is a spelling error! ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 12/14] log: add optional support of syslog 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (10 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 11/14] log: add timestamp option Stephen Hemminger @ 2024-06-04 0:45 ` Stephen Hemminger 2024-06-04 2:34 ` Stephen Hemminger 2024-06-04 0:45 ` [PATCH v21 13/14] log: add support for systemd journal Stephen Hemminger 2024-06-04 0:45 ` [PATCH v21 14/14] log: colorize log output Stephen Hemminger 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------ doc/guides/prog_guide/log_lib.rst | 17 ++++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 25 +++--- lib/log/log_private.h | 4 + lib/log/log_stubs.c | 28 ++++++ lib/log/log_syslog.c | 88 +++++++++++++++++++ lib/log/meson.build | 6 ++ 9 files changed, 164 insertions(+), 41 deletions(-) create mode 100644 lib/log/log_stubs.c create mode 100644 lib/log/log_syslog.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e54f6e8b7f..08f4866461 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index b6c648dcf3..59454bb473 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2220,6 +2220,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 71db4894fa..4430b251a1 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -12,18 +12,19 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> -#include "log_internal.h" -#include "log_private.h" - #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif +#include "log_internal.h" +#include "log_private.h" + struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -496,19 +497,21 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } -/* Placeholder */ -int -eal_log_syslog(const char *mode __rte_unused) -{ - return -1; -} - /* * Called by rte_eal_init */ void -eal_log_init(const char *id __rte_unused) +eal_log_init(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(id); +#else + bool is_terminal = isatty(STDERR_FILENO); + + if (log_syslog_enabled(is_terminal)) + log_syslog_open(id, is_terminal); + else +#endif if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67cfe72fc6..c4eb533529 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -17,4 +17,8 @@ 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_syslog_enabled(bool is_tty); +void log_syslog_open(const char *id, bool is_terminal); + + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_stubs.c b/lib/log/log_stubs.c new file mode 100644 index 0000000000..cb34217af8 --- /dev/null +++ b/lib/log/log_stubs.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <regex.h> +#include <fnmatch.h> +#include <sys/queue.h> +#include <unistd.h> +#include <rte_os_shim.h> + +#include <rte_log.h> +#include <rte_per_lcore.h> + +#include "log_internal.h" +#include "log_private.h" + +/* Stubs for Windows */ +int +eal_log_syslog(const char *str __rte_unused) +{ + return -1; +} diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..fb69921e05 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_SYSLOG_NONE = 0, /* do not use syslog */ + LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + LOG_SYSLOG_ALWAYS, /* always use syslog */ + LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +} log_syslog_opt; + +int +eal_log_syslog(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_syslog_opt = LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + log_syslog_opt = LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + log_syslog_opt = LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +} + +bool +log_syslog_enabled(bool is_terminal) +{ + switch (log_syslog_opt) { + default: + return false; + + case LOG_SYSLOG_ALWAYS: + case LOG_SYSLOG_BOTH: + return true; + + case LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + +/* + * When syslog is used, the log stream is redirected to a + * pseudo FILE handle that calls these functions. + */ +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +void +log_syslog_open(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + + if (log_syslog_opt == LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; + + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + rte_openlog_stream(log_stream); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 04235f6ee5..37507299e7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,4 +7,10 @@ sources = files( 'log_timestamp.c', ) +if is_windows + sources += files('log_stubs.c') +else + sources += files('log_syslog.c') +endif + headers = files('rte_log.h') -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v21 12/14] log: add optional support of syslog 2024-06-04 0:45 ` [PATCH v21 12/14] log: add optional support of syslog Stephen Hemminger @ 2024-06-04 2:34 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 2:34 UTC (permalink / raw) To: dev; +Cc: Tyler Retzlaff On Mon, 3 Jun 2024 17:45:00 -0700 Stephen Hemminger <stephen@networkplumber.org> wrote: > Log to syslog only if option is specified. And if syslog is used > then normally only log to syslog, don't duplicate output. > Also enables syslog support on FreeBSD. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > --- Ignore checkpatch complaints. 1. The tests should use the same style as other tests. 2. Checkpatch can't figure out code indent correctly with #ifdefs. 3. Checkpatch thinks stdio.h is spelling error. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 13/14] log: add support for systemd journal 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (11 preceding siblings ...) 2024-06-04 0:45 ` [PATCH v21 12/14] log: add optional support of syslog Stephen Hemminger @ 2024-06-04 0:45 ` Stephen Hemminger 2024-06-04 2:35 ` Stephen Hemminger 2024-06-04 0:45 ` [PATCH v21 14/14] log: colorize log output Stephen Hemminger 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/prog_guide/log_lib.rst | 14 ++ lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 5 + lib/log/log_internal.h | 3 + lib/log/log_journal.c | 200 ++++++++++++++++++++++++++++ lib/log/log_private.h | 2 + lib/log/log_stubs.c | 11 +- lib/log/meson.build | 10 +- lib/log/version.map | 1 + 10 files changed, 255 insertions(+), 4 deletions(-) create mode 100644 lib/log/log_journal.c diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..476dedb097 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -100,6 +100,20 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. +Messages can be redirected to systemd journal which is an enhanced version of syslog with the ``--log-journal`` option. + +There are three possible settings for this option: + +*auto* + If stderr is redirected to journal by ``systemd`` service + then use journal socket to instead of stderr for log. + This is the default. + +*never* + Do not try to use journal. + +*always* + Always try to direct messages to journal socket. Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 59454bb473..42cdc4a1da 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_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 }, @@ -1617,6 +1618,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: case OPT_SYSLOG_NUM: + case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; @@ -1843,6 +1845,14 @@ eal_parse_common_option(int opt, const char *optarg, return -1; } break; + + case OPT_LOG_JOURNAL_NUM: + if (eal_log_journal(optarg) < 0) { + EAL_LOG(ERR, "invalid parameters for --" + OPT_LOG_JOURNAL); + return -1; + } + break; #endif case OPT_LOG_LEVEL_NUM: @@ -2222,6 +2232,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" + " --"OPT_LOG_JOURNAL"[=<when>] Enable use of systemd journal\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..c5a1c70288 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -35,6 +35,8 @@ enum { OPT_LCORES_NUM, #define OPT_LOG_LEVEL "log-level" OPT_LOG_LEVEL_NUM, +#define OPT_LOG_JOURNAL "log-journal" + OPT_LOG_JOURNAL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, #define OPT_TRACE "trace" diff --git a/lib/log/log.c b/lib/log/log.c index 4430b251a1..13d68402d9 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -508,6 +508,11 @@ eal_log_init(const char *id) #else bool is_terminal = isatty(STDERR_FILENO); +#ifdef RTE_EXEC_ENV_LINUX + if (log_journal_enabled()) + log_journal_open(id); + else +#endif if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..2475174fce --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,200 @@ +/* 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" + +static enum { + LOG_JOURNAL_NEVER = 0, /* do not use journal */ + LOG_JOURNAL_AUTO, /* use if stderr is set to journal */ + LOG_JOURNAL_ALWAYS, /* always try to use journal */ +} log_journal_opt = LOG_JOURNAL_AUTO; + +static int log_journal_fd = -1; + +int +eal_log_journal(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_journal_opt = LOG_JOURNAL_AUTO; + else if (strcmp(str, "always") == 0) + log_journal_opt = LOG_JOURNAL_ALWAYS; + else if (strcmp(str, "never") == 0) + log_journal_opt = LOG_JOURNAL_NEVER; + else + return -1; + return 0; +} + +/* + * send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +static int +journal_send(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[16]; /* "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(log_journal_fd, iov, n); +} + + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(buf, size); +} + +static int +journal_log_close(__rte_unused void *c) +{ + close(log_journal_fd); + log_journal_fd = -1; + 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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return -1; + } + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + perror("connect"); + close(s); + return -1; + } + + return s; +} + +bool log_journal_enabled(void) +{ + if (log_journal_opt == LOG_JOURNAL_NEVER) + return false; + + if (log_journal_opt == LOG_JOURNAL_AUTO && + !is_journal(STDERR_FILENO)) + return false; + + log_journal_fd = open_journal(); + if (log_journal_fd < 0) + return false; + + return true; +} + +void log_journal_open(const char *id) +{ + FILE *log_stream; + char *syslog_id = NULL; + ssize_t len; + + /* Send identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", + id, getpid()); + if (len == 0) + goto error; + + if (write(log_journal_fd, syslog_id, len) != len) { + perror("write"); + goto error; + } + + free(syslog_id); + + /* redirect other log messages to journal */ + log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) { + rte_openlog_stream(log_stream); + return; + } + +error: + free(syslog_id); + close(log_journal_fd); + log_journal_fd = -1; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index c4eb533529..91976ab313 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -20,5 +20,7 @@ int log_print_with_timestamp(FILE *f, const char *format, va_list ap); bool log_syslog_enabled(bool is_tty); void log_syslog_open(const char *id, bool is_terminal); +bool log_journal_enabled(void); +void log_journal_open(const char *id); #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_stubs.c b/lib/log/log_stubs.c index cb34217af8..6b2099f57b 100644 --- a/lib/log/log_stubs.c +++ b/lib/log/log_stubs.c @@ -20,9 +20,18 @@ #include "log_internal.h" #include "log_private.h" -/* Stubs for Windows */ +#ifdef RTE_EXEC_ENV_WINDOWS int eal_log_syslog(const char *str __rte_unused) { return -1; } +#endif + +#ifndef RTE_EXEC_ENV_LINUX +int +eal_log_journal(const char *str __rte_unused) +{ + return -1; +} +#endif diff --git a/lib/log/meson.build b/lib/log/meson.build index 37507299e7..0a80027326 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,10 +7,14 @@ sources = files( 'log_timestamp.c', ) -if is_windows - sources += files('log_stubs.c') -else +if not is_windows sources += files('log_syslog.c') endif +if is_linux + sources += files('log_journal.c') +else + sources += files('log_stubs.c') +endif + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 14d6681a5f..7af97ece43 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -26,6 +26,7 @@ INTERNAL { global: eal_log_init; + eal_log_journal; eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v21 13/14] log: add support for systemd journal 2024-06-04 0:45 ` [PATCH v21 13/14] log: add support for systemd journal Stephen Hemminger @ 2024-06-04 2:35 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 2:35 UTC (permalink / raw) To: dev; +Cc: Tyler Retzlaff On Mon, 3 Jun 2024 17:45:01 -0700 Stephen Hemminger <stephen@networkplumber.org> wrote: > 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/ > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Same kind of bogus checkpatch warnings: - stdio.h is not a spelling error - the indent is correct, just that checkpatch can't handle #ifdef's ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v21 14/14] log: colorize log output 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger ` (12 preceding siblings ...) 2024-06-04 0:45 ` [PATCH v21 13/14] log: add support for systemd journal Stephen Hemminger @ 2024-06-04 0:45 ` Stephen Hemminger 2024-06-04 2:37 ` Stephen Hemminger 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 0:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 24 +++++ doc/guides/prog_guide/log_lib.rst | 15 +++ lib/eal/common/eal_common_options.c | 11 +++ lib/eal/common/eal_options.h | 6 +- lib/log/log.c | 24 +++-- lib/log/log_color.c | 148 ++++++++++++++++++++++++++++ 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, 235 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_color.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 08f4866461..c6c05e2e1d 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 476dedb097..647c3fc28a 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 42cdc4a1da..b68b10e120 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_NUM }, {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM }, @@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[]) case OPT_SYSLOG_NUM: case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: + case OPT_LOG_COLOR_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1872,6 +1874,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) { @@ -2239,6 +2249,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index c5a1c70288..c0686c2544 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -33,10 +33,12 @@ enum { OPT_HUGE_UNLINK_NUM, #define OPT_LCORES "lcores" OPT_LCORES_NUM, -#define OPT_LOG_LEVEL "log-level" - OPT_LOG_LEVEL_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_LOG_JOURNAL "log-journal" OPT_LOG_JOURNAL_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" diff --git a/lib/log/log.c b/lib/log/log.c index 13d68402d9..856c0a0a29 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -503,10 +503,14 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) void eal_log_init(const char *id) { + bool is_terminal; + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); + + is_terminal = _isatty(_fileno(stderr)); #else - bool is_terminal = isatty(STDERR_FILENO); + is_terminal = isatty(STDERR_FILENO); #ifdef RTE_EXEC_ENV_LINUX if (log_journal_enabled()) @@ -516,11 +520,19 @@ eal_log_init(const char *id) if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else -#endif - if (log_timestamp_enabled()) - rte_logs.print_func = log_print_with_timestamp; - else - rte_logs.print_func = vfprintf; +#endif /* RTE_EXEC_ENV_WINDOWS */ + + if (log_color_enabled(is_terminal)) { + if (log_timestamp_enabled()) + rte_logs.print_func = color_print_with_timestamp; + else + rte_logs.print_func = color_print; + } 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, diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..db11306e55 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, /* default */ + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +/* Standard terminal escape codes for colors and bold */ +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\033[31m", + [COLOR_GREEN] = "\033[32m", + [COLOR_YELLOW] = "\033[33m", + [COLOR_BLUE] = "\033[34m", + [COLOR_MAGENTA] = "\033[35m", + [COLOR_CYAN] = "\033[36m", + [COLOR_WHITE] = "\033[37m", + [COLOR_BOLD] = "\033[1m", + [COLOR_CLEAR] = "\033[0m", +}; + +__rte_format_printf(3, 4) +static int +color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + switch (log_color_mode) { + default: + case LOG_COLOR_NEVER: + return false; + case LOG_COLOR_ALWAYS: + return true; + case LOG_COLOR_AUTO: + return is_terminal; + } +} + +int +color_print(FILE *f, const char *format, va_list ap) +{ + const int level = rte_log_cur_msg_loglevel(); + char *cp, *msg; + char buf[LINE_MAX]; + int ret = 0; + + vsnprintf(buf, LINE_MAX, format, ap); + msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(f, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, format, ap); +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 82fdc21ac2..bba7041ea3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 91976ab313..5952bfb453 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -23,4 +23,12 @@ void log_syslog_open(const char *id, bool is_terminal); bool log_journal_enabled(void); void log_journal_open(const char *id); +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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 0a80027326..4041feed13 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 7af97ece43..eb3200dcde 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_24 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; eal_log_level2str; -- 2.43.0 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v21 14/14] log: colorize log output 2024-06-04 0:45 ` [PATCH v21 14/14] log: colorize log output Stephen Hemminger @ 2024-06-04 2:37 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-06-04 2:37 UTC (permalink / raw) To: dev; +Cc: Tyler Retzlaff On Mon, 3 Jun 2024 17:45:02 -0700 Stephen Hemminger <stephen@networkplumber.org> wrote: > 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. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Yet another valid patch that checkpatch complains about: 1. indent is correct, but it can't see #ifdefs 2. stdio is not a spelling error 3. it doesn't understand that FILE is a type, so it thinks it sees a multiply operator ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 00/15] Logging improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (20 preceding siblings ...) 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 01/15] maintainers: add for log library Stephen Hemminger ` (14 more replies) 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (7 subsequent siblings) 29 siblings, 15 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: 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 syslog if output is going to a terminal. Add myself as maintainer for log because by now have added more than previous authors. v22 - rebase, rearrange some code to stifle some checkpatch complaints and add release notes Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog 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 | 64 +++++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 --- doc/guides/prog_guide/log_lib.rst | 72 ++++++ doc/guides/rel_notes/release_24_11.rst | 14 ++ lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 136 +++++++----- lib/eal/common/eal_options.h | 7 + lib/eal/freebsd/eal.c | 64 ++---- lib/eal/linux/eal.c | 68 ++---- lib/eal/windows/eal.c | 49 +--- 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 | 148 ++++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 28 ++- lib/log/log_journal.c | 200 +++++++++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 33 +++ lib/log/log_stubs.c | 37 +++ lib/log/log_syslog.c | 88 ++++++++ lib/log/log_timestamp.c | 210 ++++++++++++++++++ lib/log/log_windows.c | 18 -- lib/log/meson.build | 13 +- lib/log/version.map | 5 +- 27 files changed, 1113 insertions(+), 377 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_stubs.c 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.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 01/15] maintainers: add for log library 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (13 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c5a703b5c0..ecf6f955cc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -185,6 +185,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 02/15] windows: make getopt functions have const properties 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 01/15] maintainers: add for log library Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (12 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 03/15] windows: add os shim for localtime_r 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 01/15] maintainers: add for log library Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 04/15] eal: make eal_log_level_parse common Stephen Hemminger ` (11 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 04/15] eal: make eal_log_level_parse common 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (10 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/common/eal_common_options.c | 45 +++++++++++++++++++++++++++++ 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, 46 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index f1a5e329a5..b0ceeef632 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 1229230063..d3b40e81d8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index d742cc98e2..0ded386472 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 28b78a95a6..a77e590a72 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 05/15] eal: do not duplicate rte_init_alert() messages 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 04/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (9 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3b40e81d8..7b974608e4 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 0ded386472..7c26393d00 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 06/15] eal: change rte_exit() output to match rte_log() 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 07/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (8 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..ad2be63cbb 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char msg[256]; 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); + vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 07/15] log: move handling of syslog facility out of eal 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 08/15] eal: initialize log before everything else Stephen Hemminger ` (7 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log.c | 2 ++ lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 10 files changed, 70 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index b0ceeef632..641c63998f 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7b974608e4..a609d40ee0 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 7c26393d00..5aedd348d1 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1113,8 +1113,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index a77e590a72..69a8fc8d80 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..4b24e145b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,6 +13,7 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 19d7f9cdb6..879567ba15 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 08/15] eal: initialize log before everything else 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 07/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 09/15] log: drop syslog support, and make code common Stephen Hemminger ` (6 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a609d40ee0..118c1f593b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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 +581,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 5aedd348d1..fab633976d 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -959,9 +968,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); @@ -1113,13 +1119,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 69a8fc8d80..c9648b7da7 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 09/15] log: drop syslog support, and make code common 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 08/15] eal: initialize log before everything else Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 10/15] log: add hook for printing log messages Stephen Hemminger ` (5 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 41 +++++------ lib/log/log_freebsd.c | 11 --- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 9 files changed, 23 insertions(+), 179 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 71d8dba731..a5c0c67357 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 641c63998f..2ca2a7a0c4 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2211,9 +2211,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 4b24e145b6..3fe86ddcd7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -57,9 +57,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -72,8 +69,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -87,17 +82,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -507,14 +492,19 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; - #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); @@ -527,8 +517,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 33a0925c43..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include <rte_common.h> -#include "log_internal.h" - -void -eal_log_init(__rte_unused const char *id) -{ -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 879567ba15..a0341196d4 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 10/15] log: add hook for printing log messages 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 09/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 11/15] log: add timestamp option Stephen Hemminger ` (4 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/log/log.c | 6 +++++- lib/log/log_private.h | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_private.h diff --git a/lib/log/log.c b/lib/log/log.c index 3fe86ddcd7..48543ee941 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -18,6 +18,7 @@ #include <rte_per_lcore.h> #include "log_internal.h" +#include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS #define strdup _strdup @@ -33,11 +34,13 @@ 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 { @@ -74,6 +77,7 @@ int rte_openlog_stream(FILE *f) { rte_logs.file = f; + rte_logs.print_func = vfprintf; return 0; } @@ -470,7 +474,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; } diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..67d2463b2f --- /dev/null +++ b/lib/log/log_private.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef LOG_PRIVATE_H +#define LOG_PRIVATE_H + +/* Note: same as vfprintf() */ +typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); + +#endif /* LOG_PRIVATE_H */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 11/15] log: add timestamp option 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 10/15] log: add hook for printing log messages Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 12/15] log: add optional support of syslog Stephen Hemminger ` (3 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 7 +- lib/log/log_internal.h | 9 ++ lib/log/log_private.h | 11 ++ lib/log/log_timestamp.c | 210 ++++++++++++++++++++++++++++ lib/log/meson.build | 6 +- lib/log/version.map | 1 + 13 files changed, 318 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_timestamp.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index a5c0c67357..40dd288d5f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 2ca2a7a0c4..27627fe5e4 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 118c1f593b..06bccbd026 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fab633976d..ceaa1f9487 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index c9648b7da7..0fda2abb97 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 48543ee941..6ab856272c 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -21,7 +21,7 @@ #include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -509,6 +509,11 @@ eal_log_syslog(const char *mode __rte_unused) void eal_log_init(const char *id __rte_unused) { + 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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67d2463b2f..67cfe72fc6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -3,7 +3,18 @@ #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 + /* Note: same as vfprintf() */ typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); +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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..04d8eba37b --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &log_time.previous); + log_time.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.previous); + log_time.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + clock_gettime(CLOCK_MONOTONIC, &log_time.started); + log_time.previous = log_time.started; +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 891f77a237..04235f6ee5 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,5 +2,9 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files('log.c') +sources = files( + 'log.c', + 'log_timestamp.c', +) + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index a0341196d4..155f8b3bbe 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 12/15] log: add optional support of syslog 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 11/15] log: add timestamp option Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 13/15] log: add support for systemd journal Stephen Hemminger ` (2 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------ doc/guides/prog_guide/log_lib.rst | 17 ++++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 28 +++--- lib/log/log_private.h | 3 + lib/log/log_stubs.c | 28 ++++++ lib/log/log_syslog.c | 88 +++++++++++++++++++ lib/log/meson.build | 6 ++ 9 files changed, 166 insertions(+), 41 deletions(-) create mode 100644 lib/log/log_stubs.c create mode 100644 lib/log/log_syslog.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 40dd288d5f..06295030b2 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 27627fe5e4..8d5a83d871 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2220,6 +2220,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 6ab856272c..4374cc81ff 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -12,18 +12,19 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> -#include "log_internal.h" -#include "log_private.h" - #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif +#include "log_internal.h" +#include "log_private.h" + struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -496,28 +497,33 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } -/* Placeholder */ -int -eal_log_syslog(const char *mode __rte_unused) -{ - return -1; -} - /* * Called by rte_eal_init */ void -eal_log_init(const char *id __rte_unused) +eal_log_init(const char *id) { +#ifdef RTE_EXEC_ENV_WINDOWS + RTE_SET_USED(id); +#else + bool is_terminal = isatty(STDERR_FILENO); + + if (log_syslog_enabled(is_terminal)) { + log_syslog_open(id, is_terminal); + goto notice; + } +#endif if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else rte_logs.print_func = vfprintf; +notice: #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); #endif + return; /* needed for goto target */ } /* diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67cfe72fc6..e9a7a8829a 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -17,4 +17,7 @@ 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_syslog_enabled(bool is_tty); +void log_syslog_open(const char *id, bool is_terminal); + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_stubs.c b/lib/log/log_stubs.c new file mode 100644 index 0000000000..cb34217af8 --- /dev/null +++ b/lib/log/log_stubs.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <regex.h> +#include <fnmatch.h> +#include <sys/queue.h> +#include <unistd.h> +#include <rte_os_shim.h> + +#include <rte_log.h> +#include <rte_per_lcore.h> + +#include "log_internal.h" +#include "log_private.h" + +/* Stubs for Windows */ +int +eal_log_syslog(const char *str __rte_unused) +{ + return -1; +} diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..fb69921e05 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_SYSLOG_NONE = 0, /* do not use syslog */ + LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + LOG_SYSLOG_ALWAYS, /* always use syslog */ + LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +} log_syslog_opt; + +int +eal_log_syslog(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_syslog_opt = LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + log_syslog_opt = LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + log_syslog_opt = LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +} + +bool +log_syslog_enabled(bool is_terminal) +{ + switch (log_syslog_opt) { + default: + return false; + + case LOG_SYSLOG_ALWAYS: + case LOG_SYSLOG_BOTH: + return true; + + case LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + +/* + * When syslog is used, the log stream is redirected to a + * pseudo FILE handle that calls these functions. + */ +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +void +log_syslog_open(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + + if (log_syslog_opt == LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; + + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + rte_openlog_stream(log_stream); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 04235f6ee5..a4ceed491d 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,4 +7,10 @@ sources = files( 'log_timestamp.c', ) +if is_windows + sources += files('log_stubs.c') +else + sources += files('log_syslog.c') +endif + headers = files('rte_log.h') -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 13/15] log: add support for systemd journal 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 12/15] log: add optional support of syslog Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 14/15] log: colorize log output Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 15/15] doc: add release note about log library Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- doc/guides/prog_guide/log_lib.rst | 14 ++ lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 6 + lib/log/log_internal.h | 3 + lib/log/log_journal.c | 200 ++++++++++++++++++++++++++++ lib/log/log_private.h | 2 + lib/log/log_stubs.c | 11 +- lib/log/meson.build | 3 + lib/log/version.map | 1 + 10 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_journal.c diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..476dedb097 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -100,6 +100,20 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. +Messages can be redirected to systemd journal which is an enhanced version of syslog with the ``--log-journal`` option. + +There are three possible settings for this option: + +*auto* + If stderr is redirected to journal by ``systemd`` service + then use journal socket to instead of stderr for log. + This is the default. + +*never* + Do not try to use journal. + +*always* + Always try to direct messages to journal socket. Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 8d5a83d871..59b9cdf5ff 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_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 }, @@ -1617,6 +1618,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: case OPT_SYSLOG_NUM: + case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; @@ -1843,6 +1845,14 @@ eal_parse_common_option(int opt, const char *optarg, return -1; } break; + + case OPT_LOG_JOURNAL_NUM: + if (eal_log_journal(optarg) < 0) { + EAL_LOG(ERR, "invalid parameters for --" + OPT_LOG_JOURNAL); + return -1; + } + break; #endif case OPT_LOG_LEVEL_NUM: @@ -2222,6 +2232,7 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" + " --"OPT_LOG_JOURNAL"[=<when>] Enable use of systemd journal\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..c5a1c70288 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -35,6 +35,8 @@ enum { OPT_LCORES_NUM, #define OPT_LOG_LEVEL "log-level" OPT_LOG_LEVEL_NUM, +#define OPT_LOG_JOURNAL "log-journal" + OPT_LOG_JOURNAL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, #define OPT_TRACE "trace" diff --git a/lib/log/log.c b/lib/log/log.c index 4374cc81ff..180011ae67 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -508,6 +508,12 @@ eal_log_init(const char *id) #else bool is_terminal = isatty(STDERR_FILENO); +#ifdef RTE_EXEC_ENV_LINUX + if (log_journal_enabled()) { + log_journal_open(id); + goto notice; + } +#endif if (log_syslog_enabled(is_terminal)) { log_syslog_open(id, is_terminal); goto notice; diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..2475174fce --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,200 @@ +/* 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" + +static enum { + LOG_JOURNAL_NEVER = 0, /* do not use journal */ + LOG_JOURNAL_AUTO, /* use if stderr is set to journal */ + LOG_JOURNAL_ALWAYS, /* always try to use journal */ +} log_journal_opt = LOG_JOURNAL_AUTO; + +static int log_journal_fd = -1; + +int +eal_log_journal(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_journal_opt = LOG_JOURNAL_AUTO; + else if (strcmp(str, "always") == 0) + log_journal_opt = LOG_JOURNAL_ALWAYS; + else if (strcmp(str, "never") == 0) + log_journal_opt = LOG_JOURNAL_NEVER; + else + return -1; + return 0; +} + +/* + * send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +static int +journal_send(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[16]; /* "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(log_journal_fd, iov, n); +} + + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(buf, size); +} + +static int +journal_log_close(__rte_unused void *c) +{ + close(log_journal_fd); + log_journal_fd = -1; + 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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return -1; + } + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + perror("connect"); + close(s); + return -1; + } + + return s; +} + +bool log_journal_enabled(void) +{ + if (log_journal_opt == LOG_JOURNAL_NEVER) + return false; + + if (log_journal_opt == LOG_JOURNAL_AUTO && + !is_journal(STDERR_FILENO)) + return false; + + log_journal_fd = open_journal(); + if (log_journal_fd < 0) + return false; + + return true; +} + +void log_journal_open(const char *id) +{ + FILE *log_stream; + char *syslog_id = NULL; + ssize_t len; + + /* Send identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", + id, getpid()); + if (len == 0) + goto error; + + if (write(log_journal_fd, syslog_id, len) != len) { + perror("write"); + goto error; + } + + free(syslog_id); + + /* redirect other log messages to journal */ + log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) { + rte_openlog_stream(log_stream); + return; + } + +error: + free(syslog_id); + close(log_journal_fd); + log_journal_fd = -1; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index e9a7a8829a..cb7bb32f2c 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -19,5 +19,7 @@ int log_print_with_timestamp(FILE *f, const char *format, va_list ap); bool log_syslog_enabled(bool is_tty); void log_syslog_open(const char *id, bool is_terminal); +bool log_journal_enabled(void); +void log_journal_open(const char *id); #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_stubs.c b/lib/log/log_stubs.c index cb34217af8..6b2099f57b 100644 --- a/lib/log/log_stubs.c +++ b/lib/log/log_stubs.c @@ -20,9 +20,18 @@ #include "log_internal.h" #include "log_private.h" -/* Stubs for Windows */ +#ifdef RTE_EXEC_ENV_WINDOWS int eal_log_syslog(const char *str __rte_unused) { return -1; } +#endif + +#ifndef RTE_EXEC_ENV_LINUX +int +eal_log_journal(const char *str __rte_unused) +{ + return -1; +} +#endif diff --git a/lib/log/meson.build b/lib/log/meson.build index a4ceed491d..873c17238e 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -11,6 +11,9 @@ if is_windows sources += files('log_stubs.c') else sources += files('log_syslog.c') +if is_linux + sources += files('log_journal.c') +endif endif headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 155f8b3bbe..b00657b98d 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -26,6 +26,7 @@ INTERNAL { global: eal_log_init; + eal_log_journal; eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 14/15] log: colorize log output 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (12 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 13/15] log: add support for systemd journal Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 15/15] doc: add release note about log library Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- app/test/test_eal_flags.c | 24 +++++ doc/guides/prog_guide/log_lib.rst | 15 +++ lib/eal/common/eal_common_options.c | 11 +++ lib/eal/common/eal_options.h | 6 +- lib/log/log.c | 25 +++-- lib/log/log_color.c | 148 ++++++++++++++++++++++++++++ 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, 236 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_color.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 06295030b2..6ee56ec97a 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 476dedb097..647c3fc28a 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 59b9cdf5ff..db9a18188a 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_NUM }, {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM }, @@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[]) case OPT_SYSLOG_NUM: case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: + case OPT_LOG_COLOR_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1872,6 +1874,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) { @@ -2239,6 +2249,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index c5a1c70288..c0686c2544 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -33,10 +33,12 @@ enum { OPT_HUGE_UNLINK_NUM, #define OPT_LCORES "lcores" OPT_LCORES_NUM, -#define OPT_LOG_LEVEL "log-level" - OPT_LOG_LEVEL_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_LOG_JOURNAL "log-journal" OPT_LOG_JOURNAL_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" diff --git a/lib/log/log.c b/lib/log/log.c index 180011ae67..adccf2762b 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -503,10 +503,14 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) void eal_log_init(const char *id) { + bool is_terminal; + #ifdef RTE_EXEC_ENV_WINDOWS RTE_SET_USED(id); + + is_terminal = _isatty(_fileno(stderr)); #else - bool is_terminal = isatty(STDERR_FILENO); + is_terminal = isatty(STDERR_FILENO); #ifdef RTE_EXEC_ENV_LINUX if (log_journal_enabled()) { @@ -518,11 +522,20 @@ eal_log_init(const char *id) log_syslog_open(id, is_terminal); goto notice; } -#endif - if (log_timestamp_enabled()) - rte_logs.print_func = log_print_with_timestamp; - else - rte_logs.print_func = vfprintf; + +#endif /* RTE_EXEC_ENV_WINDOWS */ + + if (log_color_enabled(is_terminal)) { + if (log_timestamp_enabled()) + rte_logs.print_func = color_print_with_timestamp; + else + rte_logs.print_func = color_print; + } else { + if (log_timestamp_enabled()) + rte_logs.print_func = log_print_with_timestamp; + else + rte_logs.print_func = vfprintf; + } notice: #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..db11306e55 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, /* default */ + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +/* Standard terminal escape codes for colors and bold */ +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\033[31m", + [COLOR_GREEN] = "\033[32m", + [COLOR_YELLOW] = "\033[33m", + [COLOR_BLUE] = "\033[34m", + [COLOR_MAGENTA] = "\033[35m", + [COLOR_CYAN] = "\033[36m", + [COLOR_WHITE] = "\033[37m", + [COLOR_BOLD] = "\033[1m", + [COLOR_CLEAR] = "\033[0m", +}; + +__rte_format_printf(3, 4) +static int +color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + switch (log_color_mode) { + default: + case LOG_COLOR_NEVER: + return false; + case LOG_COLOR_ALWAYS: + return true; + case LOG_COLOR_AUTO: + return is_terminal; + } +} + +int +color_print(FILE *f, const char *format, va_list ap) +{ + const int level = rte_log_cur_msg_loglevel(); + char *cp, *msg; + char buf[LINE_MAX]; + int ret = 0; + + vsnprintf(buf, LINE_MAX, format, ap); + msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(f, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, format, ap); +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 82fdc21ac2..bba7041ea3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index cb7bb32f2c..382ad0e892 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -22,4 +22,12 @@ void log_syslog_open(const char *id, bool is_terminal); bool log_journal_enabled(void); void log_journal_open(const char *id); +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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 873c17238e..8fa5a5a47c 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index b00657b98d..2611d3a22a 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_25 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; eal_log_level2str; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v22 15/15] doc: add release note about log library 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger ` (13 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 14/15] log: colorize log output Stephen Hemminger @ 2024-09-17 20:35 ` Stephen Hemminger 2024-09-18 4:38 ` Morten Brørup 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-17 20:35 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger Significant enough to add some documentation. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- doc/guides/rel_notes/release_24_11.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst index 0ff70d9057..4ed483b06f 100644 --- a/doc/guides/rel_notes/release_24_11.rst +++ b/doc/guides/rel_notes/release_24_11.rst @@ -55,6 +55,20 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Enhancements to logging library.** + + * Log is initialized earlier in startup so all messages go through the log library. + + * Log messages can be timestamped which is useful for debugging startup timing. + + * The log now supports color in the log if going to a terminal device + similar to dmesg. The default format shows timestamp in green, subsystem + in yellow, and the message is bold, boldface or normal depending on severity. + + * If DPDK is being used by a systemd service and the log output is being + sent of standard error then DPDK will switch to journal native protocol. + + * On FreeBSD the log library uses syslog the same as Linux. Removed Items ------------- -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* RE: [PATCH v22 15/15] doc: add release note about log library 2024-09-17 20:35 ` [PATCH v22 15/15] doc: add release note about log library Stephen Hemminger @ 2024-09-18 4:38 ` Morten Brørup 0 siblings, 0 replies; 445+ messages in thread From: Morten Brørup @ 2024-09-18 4:38 UTC (permalink / raw) To: Stephen Hemminger, dev Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 00/15] Logging improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (21 preceding siblings ...) 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 01/15] maintainers: add for log library Stephen Hemminger ` (15 more replies) 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (6 subsequent siblings) 29 siblings, 16 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: 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 syslog if output is going to a terminal. Add myself as maintainer for log because by now have added more than previous authors. v23 - simplify and fix Windows and FreeBSD builds; fix #ifdefs. Change from defining stubs to using inline functions in log_private.h. Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog 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 | 64 +++++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 --- doc/guides/prog_guide/log_lib.rst | 72 ++++++ doc/guides/rel_notes/release_24_11.rst | 15 ++ lib/eal/common/eal_common_debug.c | 11 +- lib/eal/common/eal_common_options.c | 140 +++++++----- lib/eal/common/eal_options.h | 7 + lib/eal/freebsd/eal.c | 64 ++---- lib/eal/linux/eal.c | 68 ++---- lib/eal/windows/eal.c | 49 +--- 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 | 71 +++--- lib/log/log_color.c | 148 ++++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 28 ++- lib/log/log_journal.c | 200 +++++++++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 61 +++++ lib/log/log_syslog.c | 88 ++++++++ lib/log/log_timestamp.c | 210 ++++++++++++++++++ lib/log/log_windows.c | 18 -- lib/log/meson.build | 12 +- lib/log/version.map | 5 +- 26 files changed, 1096 insertions(+), 377 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.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 01/15] maintainers: add for log library 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:01 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (14 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c5a703b5c0..ecf6f955cc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -185,6 +185,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 01/15] maintainers: add for log library 2024-09-18 4:56 ` [PATCH v23 01/15] maintainers: add for log library Stephen Hemminger @ 2024-09-18 7:01 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:01 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Tyler Retzlaff, Morten Brørup Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/18 12:56, Stephen Hemminger wrote: > "You touch it you own it" > Add myself as maintainer for log library. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > --- > MAINTAINERS | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/MAINTAINERS b/MAINTAINERS > index c5a703b5c0..ecf6f955cc 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -185,6 +185,7 @@ F: app/test/test_threads.c > F: app/test/test_version.c > > Logging > +M: Stephen Hemminger <stephen@networkplumber.org> > F: lib/log/ > F: doc/guides/prog_guide/log_lib.rst > F: app/test/test_logs.c ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 02/15] windows: make getopt functions have const properties 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 01/15] maintainers: add for log library Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:04 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (13 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 02/15] windows: make getopt functions have const properties 2024-09-18 4:56 ` [PATCH v23 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-09-18 7:04 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:04 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/18 12:56, Stephen Hemminger wrote: > 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. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 03/15] windows: add os shim for localtime_r 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 01/15] maintainers: add for log library Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:09 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 04/15] eal: make eal_log_level_parse common Stephen Hemminger ` (12 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..e9741a9df2 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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 *timer, struct tm *buf) +{ + if (localtime_s(buf, timer) == 0) + return buf; + else + return NULL; +} +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) + #endif /* _RTE_OS_SHIM_ */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 03/15] windows: add os shim for localtime_r 2024-09-18 4:56 ` [PATCH v23 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-09-18 7:09 ` fengchengwen 2024-09-18 15:25 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:09 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Tyler Retzlaff, Morten Brørup On 2024/9/18 12:56, Stephen Hemminger wrote: > Windows does not have localtime_r but it does have a similar > function that can be used instead. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > --- > lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h > index eda8113662..e9741a9df2 100644 > --- a/lib/eal/windows/include/rte_os_shim.h > +++ b/lib/eal/windows/include/rte_os_shim.h > @@ -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 *timer, struct tm *buf) buf always means char *, but this function return struct tm *, suggest: struct tm *localtime_r(const time_t *timep, struct tm *result) > +{ > + if (localtime_s(buf, timer) == 0) > + return buf; > + else > + return NULL; > +} > +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) > + > #endif /* _RTE_OS_SHIM_ */ ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 03/15] windows: add os shim for localtime_r 2024-09-18 7:09 ` fengchengwen @ 2024-09-18 15:25 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 15:25 UTC (permalink / raw) To: fengchengwen; +Cc: dev, Tyler Retzlaff, Morten Brørup On Wed, 18 Sep 2024 15:09:25 +0800 fengchengwen <fengchengwen@huawei.com> wrote: > > diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h > > index eda8113662..e9741a9df2 100644 > > --- a/lib/eal/windows/include/rte_os_shim.h > > +++ b/lib/eal/windows/include/rte_os_shim.h > > @@ -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 *timer, struct tm *buf) > > buf always means char *, but this function return struct tm *, > suggest: > struct tm *localtime_r(const time_t *timep, struct tm *result) > > > +{ > > + if (localtime_s(buf, timer) == 0) > > + return buf; > > + else > > + return NULL; > > +} > > +#define localtime_r(timer, buf) rte_localtime_r(timer, buf) This is a windows wrapper around the GNU extension localtime_r() so the signature needs to be the same, will change the name of the args to match man page. struct tm *localtime_r(const time_t *restrict timep, struct tm *restrict result); ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 04/15] eal: make eal_log_level_parse common 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:18 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (11 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/common/eal_common_options.c | 45 +++++++++++++++++++++++++++++ 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, 46 insertions(+), 116 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index f1a5e329a5..b0ceeef632 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -1640,6 +1640,51 @@ 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; + case '?': + /* getopt is not happy, stop right now */ + goto out; + default: + continue; + } + } +out: + /* 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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 1229230063..d3b40e81d8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index d742cc98e2..0ded386472 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 28b78a95a6..a77e590a72 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 04/15] eal: make eal_log_level_parse common 2024-09-18 4:56 ` [PATCH v23 04/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-09-18 7:18 ` fengchengwen 2024-09-18 15:24 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:18 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Tyler Retzlaff, Morten Brørup On 2024/9/18 12:56, Stephen Hemminger wrote: > The code to parse for log-level option should be same on > all OS variants. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > --- > lib/eal/common/eal_common_options.c | 45 +++++++++++++++++++++++++++++ > 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, 46 insertions(+), 116 deletions(-) > > diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c > index f1a5e329a5..b0ceeef632 100644 > --- a/lib/eal/common/eal_common_options.c > +++ b/lib/eal/common/eal_common_options.c > @@ -1640,6 +1640,51 @@ 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; > + case '?': > + /* getopt is not happy, stop right now */ > + goto out; no need goto, could use break > + default: > + continue; > + } > + } > +out: > + /* 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; > +} > + ... ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 04/15] eal: make eal_log_level_parse common 2024-09-18 7:18 ` fengchengwen @ 2024-09-18 15:24 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 15:24 UTC (permalink / raw) To: fengchengwen; +Cc: dev, Tyler Retzlaff, Morten Brørup On Wed, 18 Sep 2024 15:18:04 +0800 fengchengwen <fengchengwen@huawei.com> wrote: > > +/* 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; > > + case '?': > > + /* getopt is not happy, stop right now */ > > + goto out; > > no need goto, could use break This function is only used to pre-scan options, it should just ignore anything it doesn't care about. Can remove the ? case and default part. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 05/15] eal: do not duplicate rte_init_alert() messages 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 04/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:18 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (10 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3b40e81d8..7b974608e4 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 0ded386472..7c26393d00 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 05/15] eal: do not duplicate rte_init_alert() messages 2024-09-18 4:56 ` [PATCH v23 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-09-18 7:18 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:18 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Tyler Retzlaff, Morten Brørup Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/18 12:56, Stephen Hemminger wrote: > The message already goes through logging, and does not need > to be printed on stderr. Message level should be ALERT > to match function name. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > --- > lib/eal/freebsd/eal.c | 3 +-- > lib/eal/linux/eal.c | 3 +-- > 2 files changed, 2 insertions(+), 4 deletions(-) > > diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c > index d3b40e81d8..7b974608e4 100644 > --- a/lib/eal/freebsd/eal.c > +++ b/lib/eal/freebsd/eal.c > @@ -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(). */ > diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c > index 0ded386472..7c26393d00 100644 > --- a/lib/eal/linux/eal.c > +++ b/lib/eal/linux/eal.c > @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); > } > > /* ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 06/15] eal: change rte_exit() output to match rte_log() 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:23 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 07/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (9 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup 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: Cause - Cannot init EAL: Permission denied Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/common/eal_common_debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..ad2be63cbb 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -34,17 +34,18 @@ void rte_exit(int exit_code, const char *format, ...) { va_list ap; + char msg[256]; 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); + vsnprintf(msg, sizeof(msg), format, ap); va_end(ap); + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); + 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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 06/15] eal: change rte_exit() output to match rte_log() 2024-09-18 4:56 ` [PATCH v23 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-09-18 7:23 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:23 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Tyler Retzlaff, Morten Brørup On 2024/9/18 12:56, Stephen Hemminger wrote: > 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: Cause - Cannot init EAL: Permission denied > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > --- > lib/eal/common/eal_common_debug.c | 11 ++++++----- > 1 file changed, 6 insertions(+), 5 deletions(-) > > diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c > index 3e77995896..ad2be63cbb 100644 > --- a/lib/eal/common/eal_common_debug.c > +++ b/lib/eal/common/eal_common_debug.c > @@ -34,17 +34,18 @@ void > rte_exit(int exit_code, const char *format, ...) > { > va_list ap; > + char msg[256]; the length maybe too short. > > 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); > + vsnprintf(msg, sizeof(msg), format, ap); should handle the vsnprintf return negative value. > va_end(ap); > > + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "EAL: Cause - %s", msg); > + > 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); > } ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 07/15] log: move handling of syslog facility out of eal 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:25 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 08/15] eal: initialize log before everything else Stephen Hemminger ` (8 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log.c | 2 ++ lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 10 files changed, 70 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index b0ceeef632..641c63998f 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1882,7 +1835,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7b974608e4..a609d40ee0 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 7c26393d00..5aedd348d1 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1113,8 +1113,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index a77e590a72..69a8fc8d80 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..4b24e145b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,6 +13,7 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 19d7f9cdb6..879567ba15 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 07/15] log: move handling of syslog facility out of eal 2024-09-18 4:56 ` [PATCH v23 07/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-09-18 7:25 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:25 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Morten Brørup Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/18 12:56, Stephen Hemminger wrote: > The syslog facility property is better handled in lib/log > rather than in eal. This also allows for changes to what > syslog flag means in later steps. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 08/15] eal: initialize log before everything else 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 07/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:30 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 09/15] log: drop syslog support, and make code common Stephen Hemminger ` (7 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a609d40ee0..118c1f593b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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 +581,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 5aedd348d1..fab633976d 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -959,9 +968,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); @@ -1113,13 +1119,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 69a8fc8d80..c9648b7da7 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 08/15] eal: initialize log before everything else 2024-09-18 4:56 ` [PATCH v23 08/15] eal: initialize log before everything else Stephen Hemminger @ 2024-09-18 7:30 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:30 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Tyler Retzlaff, Morten Brørup Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/18 12:56, Stephen Hemminger wrote: > 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. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 09/15] log: drop syslog support, and make code common 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 08/15] eal: initialize log before everything else Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 10/15] log: add hook for printing log messages Stephen Hemminger ` (6 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 41 +++++------ lib/log/log_freebsd.c | 11 --- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 9 files changed, 23 insertions(+), 179 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 71d8dba731..a5c0c67357 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 641c63998f..2ca2a7a0c4 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2211,9 +2211,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 4b24e145b6..3fe86ddcd7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -57,9 +57,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -72,8 +69,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -87,17 +82,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -507,14 +492,19 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; - #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); @@ -527,8 +517,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 33a0925c43..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include <rte_common.h> -#include "log_internal.h" - -void -eal_log_init(__rte_unused const char *id) -{ -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 879567ba15..a0341196d4 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 10/15] log: add hook for printing log messages 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 09/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:32 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 11/15] log: add timestamp option Stephen Hemminger ` (5 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- lib/log/log.c | 6 +++++- lib/log/log_private.h | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_private.h diff --git a/lib/log/log.c b/lib/log/log.c index 3fe86ddcd7..48543ee941 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -18,6 +18,7 @@ #include <rte_per_lcore.h> #include "log_internal.h" +#include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS #define strdup _strdup @@ -33,11 +34,13 @@ 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 { @@ -74,6 +77,7 @@ int rte_openlog_stream(FILE *f) { rte_logs.file = f; + rte_logs.print_func = vfprintf; return 0; } @@ -470,7 +474,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; } diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..67d2463b2f --- /dev/null +++ b/lib/log/log_private.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef LOG_PRIVATE_H +#define LOG_PRIVATE_H + +/* Note: same as vfprintf() */ +typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); + +#endif /* LOG_PRIVATE_H */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 10/15] log: add hook for printing log messages 2024-09-18 4:56 ` [PATCH v23 10/15] log: add hook for printing log messages Stephen Hemminger @ 2024-09-18 7:32 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:32 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Morten Brørup Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/18 12:56, Stephen Hemminger wrote: > This is useful for when decorating log output for console > or journal. Provide basic version in this patch. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 11/15] log: add timestamp option 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 10/15] log: add hook for printing log messages Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:37 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 12/15] log: add optional support of syslog Stephen Hemminger ` (4 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 7 +- lib/log/log_internal.h | 9 ++ lib/log/log_private.h | 11 ++ lib/log/log_timestamp.c | 210 ++++++++++++++++++++++++++++ lib/log/meson.build | 6 +- lib/log/version.map | 1 + 13 files changed, 318 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_timestamp.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index a5c0c67357..40dd288d5f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 2ca2a7a0c4..27627fe5e4 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1843,7 +1845,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 --" @@ -1851,7 +1853,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 118c1f593b..06bccbd026 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fab633976d..ceaa1f9487 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index c9648b7da7..0fda2abb97 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 48543ee941..6ab856272c 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -21,7 +21,7 @@ #include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -509,6 +509,11 @@ eal_log_syslog(const char *mode __rte_unused) void eal_log_init(const char *id __rte_unused) { + 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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67d2463b2f..67cfe72fc6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -3,7 +3,18 @@ #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 + /* Note: same as vfprintf() */ typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); +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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..04d8eba37b --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &log_time.previous); + log_time.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.previous); + log_time.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + clock_gettime(CLOCK_MONOTONIC, &log_time.started); + log_time.previous = log_time.started; +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 891f77a237..04235f6ee5 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,5 +2,9 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files('log.c') +sources = files( + 'log.c', + 'log_timestamp.c', +) + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index a0341196d4..155f8b3bbe 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 11/15] log: add timestamp option 2024-09-18 4:56 ` [PATCH v23 11/15] log: add timestamp option Stephen Hemminger @ 2024-09-18 7:37 ` fengchengwen 2024-09-18 15:05 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:37 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Morten Brørup On 2024/9/18 12:56, Stephen Hemminger wrote: > 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 > ... > + > +static enum { > + LOG_TIMESTAMP_NONE = 0, > + LOG_TIMESTAMP_TIME, /* time since start */ > + LOG_TIMESTAMP_DELTA, /* time since last message */ > + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ > + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ > + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ Some of the impl should consider multiple-thread safety. And for multiple-process, how about the secondary-processes align the main-process. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 11/15] log: add timestamp option 2024-09-18 7:37 ` fengchengwen @ 2024-09-18 15:05 ` Stephen Hemminger 2024-09-19 1:20 ` fengchengwen 0 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 15:05 UTC (permalink / raw) To: fengchengwen; +Cc: dev, Morten Brørup On Wed, 18 Sep 2024 15:37:49 +0800 fengchengwen <fengchengwen@huawei.com> wrote: > ... > > > + > > +static enum { > > + LOG_TIMESTAMP_NONE = 0, > > + LOG_TIMESTAMP_TIME, /* time since start */ > > + LOG_TIMESTAMP_DELTA, /* time since last message */ > > + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ > > + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ > > + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ > > Some of the impl should consider multiple-thread safety. > > And for multiple-process, how about the secondary-processes align the main-process. As much as possible, they are thread safe, that is why locatime_r is used. Of course if multiple threads are printing it is possible that time stamps could be out of order. I.e CPU A got timestamp and is formatting message, and CPU B got timestamp is formatting message. The formatting might take longer for A. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 11/15] log: add timestamp option 2024-09-18 15:05 ` Stephen Hemminger @ 2024-09-19 1:20 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-19 1:20 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Morten Brørup On 2024/9/18 23:05, Stephen Hemminger wrote: > On Wed, 18 Sep 2024 15:37:49 +0800 > fengchengwen <fengchengwen@huawei.com> wrote: > >> ... >> >>> + >>> +static enum { >>> + LOG_TIMESTAMP_NONE = 0, >>> + LOG_TIMESTAMP_TIME, /* time since start */ >>> + LOG_TIMESTAMP_DELTA, /* time since last message */ >>> + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ >>> + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ >>> + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ >> >> Some of the impl should consider multiple-thread safety. >> >> And for multiple-process, how about the secondary-processes align the main-process. > > > As much as possible, they are thread safe, that is why locatime_r is used. > Of course if multiple threads are printing it is possible that time stamps > could be out of order. I.e CPU A got timestamp and is formatting message, > and CPU B got timestamp is formatting message. The formatting might take longer for A. Yes, the localtime_r is thread safe, but like delta, multi thread will both read and update global variable log_time.previous with any sync, this may lead problem. static struct { struct timespec started; /* when log was initialized */ struct timespec previous; /* when last msg was printed */ } log_time; e.g. 1, the previous tv_sec = 1000, tv_nsec = 90000; 2, thread A invoke log, and current tv_sec = 2000, tv_nsec = 10000; it will update the previous 3, thread B also invoke log, and current tv_sec = 2000, tv_nsec = 10001, but it read previous is tv_sec = 2000, tv_nsec = 90000 and the delta will invalid. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 12/15] log: add optional support of syslog 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 11/15] log: add timestamp option Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:41 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 13/15] log: add support for systemd journal Stephen Hemminger ` (3 subsequent siblings) 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------ doc/guides/prog_guide/log_lib.rst | 17 ++++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 28 +++--- lib/log/log_private.h | 17 ++++ lib/log/log_syslog.c | 88 +++++++++++++++++++ lib/log/meson.build | 4 + lib/log/version.map | 2 +- 9 files changed, 150 insertions(+), 43 deletions(-) create mode 100644 lib/log/log_syslog.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 40dd288d5f..06295030b2 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 27627fe5e4..8d5a83d871 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2220,6 +2220,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 6ab856272c..f748551bc0 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -12,18 +12,19 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> -#include "log_internal.h" -#include "log_private.h" - #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif +#include "log_internal.h" +#include "log_private.h" + struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -496,20 +497,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } -/* Placeholder */ -int -eal_log_syslog(const char *mode __rte_unused) -{ - return -1; -} - /* * Called by rte_eal_init */ void -eal_log_init(const char *id __rte_unused) +eal_log_init(const char *id) { - if (log_timestamp_enabled()) + bool is_terminal; + +#ifdef RTE_EXEC_ENV_WINDOWS + is_terminal = _isatty(_fileno(stderr)); +#else + is_terminal = isatty(STDERR_FILENO); +#endif + + if (log_syslog_enabled(is_terminal)) + log_syslog_open(id, is_terminal); + else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else rte_logs.print_func = vfprintf; diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67cfe72fc6..532a481340 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -17,4 +17,21 @@ 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); +#ifdef RTE_EXEC_ENV_WINDOWS +static inline bool +log_syslog_enabled(bool is_tty __rte_unused) +{ + return false; +} + +static inline void +log_syslog_open(const char *id __rte_unused, bool is_terminal __rte_unused) +{ +} +#else + +bool log_syslog_enabled(bool is_tty); +void log_syslog_open(const char *id, bool is_terminal); +#endif + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..fb69921e05 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_SYSLOG_NONE = 0, /* do not use syslog */ + LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + LOG_SYSLOG_ALWAYS, /* always use syslog */ + LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +} log_syslog_opt; + +int +eal_log_syslog(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_syslog_opt = LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + log_syslog_opt = LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + log_syslog_opt = LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +} + +bool +log_syslog_enabled(bool is_terminal) +{ + switch (log_syslog_opt) { + default: + return false; + + case LOG_SYSLOG_ALWAYS: + case LOG_SYSLOG_BOTH: + return true; + + case LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + +/* + * When syslog is used, the log stream is redirected to a + * pseudo FILE handle that calls these functions. + */ +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +void +log_syslog_open(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + + if (log_syslog_opt == LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; + + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + rte_openlog_stream(log_stream); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 04235f6ee5..4ac232786e 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,4 +7,8 @@ sources = files( 'log_timestamp.c', ) +if not is_windows + sources += files('log_syslog.c') +endif + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 155f8b3bbe..8be6907840 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,7 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_syslog; + eal_log_syslog; # WINDOWS_NO_EXPORT eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 12/15] log: add optional support of syslog 2024-09-18 4:56 ` [PATCH v23 12/15] log: add optional support of syslog Stephen Hemminger @ 2024-09-18 7:41 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:41 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Morten Brørup Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/18 12:56, Stephen Hemminger wrote: > Log to syslog only if option is specified. And if syslog is used > then normally only log to syslog, don't duplicate output. > Also enables syslog support on FreeBSD. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 13/15] log: add support for systemd journal 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 12/15] log: add optional support of syslog Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 14/15] log: colorize log output Stephen Hemminger ` (2 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- doc/guides/prog_guide/log_lib.rst | 14 ++ lib/eal/common/eal_common_options.c | 15 +++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 4 +- lib/log/log_internal.h | 3 + lib/log/log_journal.c | 200 ++++++++++++++++++++++++++++ lib/log/log_private.h | 16 +++ lib/log/meson.build | 4 + lib/log/version.map | 1 + 9 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_journal.c diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..476dedb097 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -100,6 +100,20 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. +Messages can be redirected to systemd journal which is an enhanced version of syslog with the ``--log-journal`` option. + +There are three possible settings for this option: + +*auto* + If stderr is redirected to journal by ``systemd`` service + then use journal socket to instead of stderr for log. + This is the default. + +*never* + Do not try to use journal. + +*always* + Always try to direct messages to journal socket. Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 8d5a83d871..53857b5f5c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_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 }, @@ -1617,6 +1618,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: case OPT_SYSLOG_NUM: + case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; @@ -1845,6 +1847,16 @@ eal_parse_common_option(int opt, const char *optarg, break; #endif +#ifdef RTE_EXEC_ENV_LINUX + case OPT_LOG_JOURNAL_NUM: + if (eal_log_journal(optarg) < 0) { + EAL_LOG(ERR, "invalid parameters for --" + OPT_LOG_JOURNAL); + return -1; + } + break; +#endif + case OPT_LOG_LEVEL_NUM: if (eal_parse_log_level(optarg) < 0) { EAL_LOG(ERR, @@ -2222,6 +2234,9 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif +#ifdef RTE_EXEC_ENV_LINUX + " --"OPT_LOG_JOURNAL"[=<when>] Enable use of systemd journal\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..c5a1c70288 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -35,6 +35,8 @@ enum { OPT_LCORES_NUM, #define OPT_LOG_LEVEL "log-level" OPT_LOG_LEVEL_NUM, +#define OPT_LOG_JOURNAL "log-journal" + OPT_LOG_JOURNAL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, #define OPT_TRACE "trace" diff --git a/lib/log/log.c b/lib/log/log.c index f748551bc0..96fa651e81 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -511,7 +511,9 @@ eal_log_init(const char *id) is_terminal = isatty(STDERR_FILENO); #endif - if (log_syslog_enabled(is_terminal)) + if (log_journal_enabled()) + log_journal_open(id); + else if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..2475174fce --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,200 @@ +/* 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" + +static enum { + LOG_JOURNAL_NEVER = 0, /* do not use journal */ + LOG_JOURNAL_AUTO, /* use if stderr is set to journal */ + LOG_JOURNAL_ALWAYS, /* always try to use journal */ +} log_journal_opt = LOG_JOURNAL_AUTO; + +static int log_journal_fd = -1; + +int +eal_log_journal(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_journal_opt = LOG_JOURNAL_AUTO; + else if (strcmp(str, "always") == 0) + log_journal_opt = LOG_JOURNAL_ALWAYS; + else if (strcmp(str, "never") == 0) + log_journal_opt = LOG_JOURNAL_NEVER; + else + return -1; + return 0; +} + +/* + * send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +static int +journal_send(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[16]; /* "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(log_journal_fd, iov, n); +} + + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(buf, size); +} + +static int +journal_log_close(__rte_unused void *c) +{ + close(log_journal_fd); + log_journal_fd = -1; + 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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return -1; + } + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + perror("connect"); + close(s); + return -1; + } + + return s; +} + +bool log_journal_enabled(void) +{ + if (log_journal_opt == LOG_JOURNAL_NEVER) + return false; + + if (log_journal_opt == LOG_JOURNAL_AUTO && + !is_journal(STDERR_FILENO)) + return false; + + log_journal_fd = open_journal(); + if (log_journal_fd < 0) + return false; + + return true; +} + +void log_journal_open(const char *id) +{ + FILE *log_stream; + char *syslog_id = NULL; + ssize_t len; + + /* Send identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", + id, getpid()); + if (len == 0) + goto error; + + if (write(log_journal_fd, syslog_id, len) != len) { + perror("write"); + goto error; + } + + free(syslog_id); + + /* redirect other log messages to journal */ + log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) { + rte_openlog_stream(log_stream); + return; + } + +error: + free(syslog_id); + close(log_journal_fd); + log_journal_fd = -1; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 532a481340..d8602681b2 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -34,4 +34,20 @@ bool log_syslog_enabled(bool is_tty); void log_syslog_open(const char *id, bool is_terminal); #endif +#ifdef RTE_EXEC_ENV_LINUX +bool log_journal_enabled(void); +void log_journal_open(const char *id); +#else +static inline bool +log_journal_enabled(void) +{ + return false; +} + +static inline void +log_journal_open(const char *id __rte_unused) +{ +} +#endif /* !RTE_EXEC_ENV_LINUX */ + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 4ac232786e..86e4452b19 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 8be6907840..800d3943bc 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 14/15] log: colorize log output 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (12 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 13/15] log: add support for systemd journal Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:43 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 15/15] doc: add release note about log library Stephen Hemminger 2024-09-18 8:27 ` [PATCH v23 00/15] Logging improvements Bruce Richardson 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- app/test/test_eal_flags.c | 24 +++++ doc/guides/prog_guide/log_lib.rst | 15 +++ lib/eal/common/eal_common_options.c | 11 +++ lib/eal/common/eal_options.h | 6 +- lib/log/log.c | 19 ++-- lib/log/log_color.c | 148 ++++++++++++++++++++++++++++ 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, 230 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_color.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 06295030b2..6ee56ec97a 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 476dedb097..647c3fc28a 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 53857b5f5c..271db58a30 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_NUM }, {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM }, @@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[]) case OPT_SYSLOG_NUM: case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: + case OPT_LOG_COLOR_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1874,6 +1876,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) { @@ -2243,6 +2253,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index c5a1c70288..c0686c2544 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -33,10 +33,12 @@ enum { OPT_HUGE_UNLINK_NUM, #define OPT_LCORES "lcores" OPT_LCORES_NUM, -#define OPT_LOG_LEVEL "log-level" - OPT_LOG_LEVEL_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_LOG_JOURNAL "log-journal" OPT_LOG_JOURNAL_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" diff --git a/lib/log/log.c b/lib/log/log.c index 96fa651e81..8b7b394f49 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -511,14 +511,21 @@ eal_log_init(const char *id) is_terminal = isatty(STDERR_FILENO); #endif - if (log_journal_enabled()) + if (log_journal_enabled()) { log_journal_open(id); - else if (log_syslog_enabled(is_terminal)) + } else if (log_syslog_enabled(is_terminal)) { log_syslog_open(id, is_terminal); - else if (log_timestamp_enabled()) - rte_logs.print_func = log_print_with_timestamp; - else - rte_logs.print_func = vfprintf; + } else if (log_timestamp_enabled()) { + if (log_color_enabled(is_terminal)) + rte_logs.print_func = color_print_with_timestamp; + else + rte_logs.print_func = log_print_with_timestamp; + } else { + if (log_color_enabled(is_terminal)) + rte_logs.print_func = color_print; + else + rte_logs.print_func = vfprintf; + } #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..db11306e55 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, /* default */ + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +/* Standard terminal escape codes for colors and bold */ +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\033[31m", + [COLOR_GREEN] = "\033[32m", + [COLOR_YELLOW] = "\033[33m", + [COLOR_BLUE] = "\033[34m", + [COLOR_MAGENTA] = "\033[35m", + [COLOR_CYAN] = "\033[36m", + [COLOR_WHITE] = "\033[37m", + [COLOR_BOLD] = "\033[1m", + [COLOR_CLEAR] = "\033[0m", +}; + +__rte_format_printf(3, 4) +static int +color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + switch (log_color_mode) { + default: + case LOG_COLOR_NEVER: + return false; + case LOG_COLOR_ALWAYS: + return true; + case LOG_COLOR_AUTO: + return is_terminal; + } +} + +int +color_print(FILE *f, const char *format, va_list ap) +{ + const int level = rte_log_cur_msg_loglevel(); + char *cp, *msg; + char buf[LINE_MAX]; + int ret = 0; + + vsnprintf(buf, LINE_MAX, format, ap); + msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(f, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, format, ap); +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 82fdc21ac2..bba7041ea3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index d8602681b2..855e32db90 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -50,4 +50,12 @@ log_journal_open(const char *id __rte_unused) } #endif /* !RTE_EXEC_ENV_LINUX */ +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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 86e4452b19..b3de57b9c7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 800d3943bc..09d8a4289b 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_25 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; # WINDOWS_NO_EXPORT eal_log_level2str; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 14/15] log: colorize log output 2024-09-18 4:56 ` [PATCH v23 14/15] log: colorize log output Stephen Hemminger @ 2024-09-18 7:43 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:43 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Morten Brørup Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/18 12:56, Stephen Hemminger wrote: > 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. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Morten Brørup <mb@smartsharesystems.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v23 15/15] doc: add release note about log library 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (13 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 14/15] log: colorize log output Stephen Hemminger @ 2024-09-18 4:56 ` Stephen Hemminger 2024-09-18 7:44 ` fengchengwen 2024-09-18 8:27 ` [PATCH v23 00/15] Logging improvements Bruce Richardson 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 4:56 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup Significant enough to add some documentation. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> --- doc/guides/rel_notes/release_24_11.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst index 0ff70d9057..8878ed33aa 100644 --- a/doc/guides/rel_notes/release_24_11.rst +++ b/doc/guides/rel_notes/release_24_11.rst @@ -55,6 +55,21 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Enhancements to logging library.** + + * The log is initialized earlier in startup so all messages go through the library. + + * An option is added to timestamp log messages, which is useful for debugging delays in + application and driver startup. + + * Log messages are now in color if going to a terminal (similar to dmesg). + The default format shows timestamp in green, subsystem in yellow, + and the message is bold, boldface or normal depending on severity. + + * 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. + + * On FreeBSD the log library can syslog the same as Linux. Removed Items ------------- -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 15/15] doc: add release note about log library 2024-09-18 4:56 ` [PATCH v23 15/15] doc: add release note about log library Stephen Hemminger @ 2024-09-18 7:44 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-18 7:44 UTC (permalink / raw) To: Stephen Hemminger, dev; +Cc: Morten Brørup Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/18 12:56, Stephen Hemminger wrote: > Significant enough to add some documentation. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > --- > doc/guides/rel_notes/release_24_11.rst | 15 +++++++++++++++ > 1 file changed, 15 insertions(+) > > diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst > index 0ff70d9057..8878ed33aa 100644 > --- a/doc/guides/rel_notes/release_24_11.rst > +++ b/doc/guides/rel_notes/release_24_11.rst > @@ -55,6 +55,21 @@ New Features > Also, make sure to start the actual text at the margin. > ======================================================= > > +* **Enhancements to logging library.** > + > + * The log is initialized earlier in startup so all messages go through the library. > + > + * An option is added to timestamp log messages, which is useful for debugging delays in > + application and driver startup. > + > + * Log messages are now in color if going to a terminal (similar to dmesg). > + The default format shows timestamp in green, subsystem in yellow, > + and the message is bold, boldface or normal depending on severity. > + > + * 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. > + > + * On FreeBSD the log library can syslog the same as Linux. > > Removed Items > ------------- ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v23 00/15] Logging improvements 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger ` (14 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 15/15] doc: add release note about log library Stephen Hemminger @ 2024-09-18 8:27 ` Bruce Richardson 15 siblings, 0 replies; 445+ messages in thread From: Bruce Richardson @ 2024-09-18 8:27 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev On Tue, Sep 17, 2024 at 09:56:05PM -0700, Stephen Hemminger wrote: > 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 > syslog if output is going to a terminal. > > Add myself as maintainer for log because by now have added > more than previous authors. > > v23 - simplify and fix Windows and FreeBSD builds; fix #ifdefs. > Change from defining stubs to using inline functions in log_private.h. > > Stephen Hemminger (15): > maintainers: add for log library > windows: make getopt functions have const properties > windows: add os shim for localtime_r > 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: move handling of syslog facility out of eal > eal: initialize log before everything else > log: drop syslog support, and make code common > log: add hook for printing log messages > log: add timestamp option > log: add optional support of syslog > log: add support for systemd journal > log: colorize log output > doc: add release note about log library > Thanks for the cleanup. Series-acked-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 00/15] Logging enhancements for 24.11 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (22 preceding siblings ...) 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger @ 2024-09-18 20:51 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 01/15] maintainers: add for log library Stephen Hemminger ` (14 more replies) 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (5 subsequent siblings) 29 siblings, 15 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:51 UTC (permalink / raw) To: dev; +Cc: 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 syslog if output is going to a terminal. Add myself as maintainer for log because by now have added more than previous authors. v24 - incorporate a couple of small review feedback items. expand the release note. Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog 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 | 64 +++++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 --- doc/guides/prog_guide/log_lib.rst | 72 ++++++ doc/guides/rel_notes/release_24_11.rst | 27 +++ lib/eal/common/eal_common_debug.c | 6 +- lib/eal/common/eal_common_options.c | 135 ++++++----- lib/eal/common/eal_options.h | 7 + lib/eal/freebsd/eal.c | 64 ++---- lib/eal/linux/eal.c | 68 ++---- lib/eal/windows/eal.c | 49 +--- 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 | 71 +++--- lib/log/log_color.c | 148 ++++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 28 ++- lib/log/log_journal.c | 200 +++++++++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 61 +++++ lib/log/log_syslog.c | 88 ++++++++ lib/log/log_timestamp.c | 210 ++++++++++++++++++ lib/log/log_windows.c | 18 -- lib/log/meson.build | 12 +- lib/log/version.map | 5 +- 26 files changed, 1099 insertions(+), 376 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.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 01/15] maintainers: add for log library 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (13 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Chengwen Feng, Bruce Richardson "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c5a703b5c0..ecf6f955cc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -185,6 +185,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 02/15] windows: make getopt functions have const properties 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 01/15] maintainers: add for log library Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (12 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 03/15] windows: add os shim for localtime_r 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 01/15] maintainers: add for log library Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-19 1:07 ` fengchengwen 2024-09-18 20:52 ` [PATCH v24 04/15] eal: make eal_log_level_parse common Stephen Hemminger ` (11 subsequent siblings) 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..665c9ac93b 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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_ */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v24 03/15] windows: add os shim for localtime_r 2024-09-18 20:52 ` [PATCH v24 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-09-19 1:07 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-19 1:07 UTC (permalink / raw) To: Stephen Hemminger, dev Cc: Tyler Retzlaff, Morten Brørup, Bruce Richardson Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/19 4:52, Stephen Hemminger wrote: > Windows does not have localtime_r but it does have a similar > function that can be used instead. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > Acked-by: Bruce Richardson <bruce.richardson@intel.com> > --- > lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h > index eda8113662..665c9ac93b 100644 > --- a/lib/eal/windows/include/rte_os_shim.h > +++ b/lib/eal/windows/include/rte_os_shim.h > @@ -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_ */ ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 04/15] eal: make eal_log_level_parse common 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (2 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (10 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index f1a5e329a5..eb079a65a9 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 1229230063..d3b40e81d8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index d742cc98e2..0ded386472 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 28b78a95a6..a77e590a72 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 05/15] eal: do not duplicate rte_init_alert() messages 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (3 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 04/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (9 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3b40e81d8..7b974608e4 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 0ded386472..7c26393d00 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 06/15] eal: change rte_exit() output to match rte_log() 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (4 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-19 1:09 ` fengchengwen 2024-09-18 20:52 ` [PATCH v24 07/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (8 subsequent siblings) 14 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/eal/common/eal_common_debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..bcfcd6df6f 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v24 06/15] eal: change rte_exit() output to match rte_log() 2024-09-18 20:52 ` [PATCH v24 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-09-19 1:09 ` fengchengwen 0 siblings, 0 replies; 445+ messages in thread From: fengchengwen @ 2024-09-19 1:09 UTC (permalink / raw) To: Stephen Hemminger, dev Cc: Tyler Retzlaff, Morten Brørup, Bruce Richardson Acked-by: Chengwen Feng <fengchengwen@huawei.com> On 2024/9/19 4:52, Stephen Hemminger wrote: > 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 > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > Acked-by: Bruce Richardson <bruce.richardson@intel.com> > --- > lib/eal/common/eal_common_debug.c | 6 ++---- > 1 file changed, 2 insertions(+), 4 deletions(-) > > diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c > index 3e77995896..bcfcd6df6f 100644 > --- a/lib/eal/common/eal_common_debug.c > +++ b/lib/eal/common/eal_common_debug.c > @@ -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); > } ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 07/15] log: move handling of syslog facility out of eal 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (5 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 08/15] eal: initialize log before everything else Stephen Hemminger ` (7 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log.c | 2 ++ lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 10 files changed, 70 insertions(+), 64 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index eb079a65a9..918cc013fe 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1877,7 +1830,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7b974608e4..a609d40ee0 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 7c26393d00..5aedd348d1 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1113,8 +1113,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index a77e590a72..69a8fc8d80 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..4b24e145b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,6 +13,7 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 19d7f9cdb6..879567ba15 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 08/15] eal: initialize log before everything else 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (6 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 07/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 09/15] log: drop syslog support, and make code common Stephen Hemminger ` (6 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a609d40ee0..118c1f593b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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 +581,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 5aedd348d1..fab633976d 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -959,9 +968,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); @@ -1113,13 +1119,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 69a8fc8d80..c9648b7da7 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 09/15] log: drop syslog support, and make code common 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (7 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 08/15] eal: initialize log before everything else Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 10/15] log: add hook for printing log messages Stephen Hemminger ` (5 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 41 +++++------ lib/log/log_freebsd.c | 11 --- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 9 files changed, 23 insertions(+), 179 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 71d8dba731..a5c0c67357 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 918cc013fe..ea45c79d5c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2206,9 +2206,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 4b24e145b6..3fe86ddcd7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -57,9 +57,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -72,8 +69,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -87,17 +82,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -507,14 +492,19 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; - #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); @@ -527,8 +517,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 33a0925c43..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include <rte_common.h> -#include "log_internal.h" - -void -eal_log_init(__rte_unused const char *id) -{ -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 879567ba15..a0341196d4 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 10/15] log: add hook for printing log messages 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (8 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 09/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 11/15] log: add timestamp option Stephen Hemminger ` (4 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/log/log.c | 6 +++++- lib/log/log_private.h | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_private.h diff --git a/lib/log/log.c b/lib/log/log.c index 3fe86ddcd7..48543ee941 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -18,6 +18,7 @@ #include <rte_per_lcore.h> #include "log_internal.h" +#include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS #define strdup _strdup @@ -33,11 +34,13 @@ 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 { @@ -74,6 +77,7 @@ int rte_openlog_stream(FILE *f) { rte_logs.file = f; + rte_logs.print_func = vfprintf; return 0; } @@ -470,7 +474,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; } diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..67d2463b2f --- /dev/null +++ b/lib/log/log_private.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef LOG_PRIVATE_H +#define LOG_PRIVATE_H + +/* Note: same as vfprintf() */ +typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); + +#endif /* LOG_PRIVATE_H */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 11/15] log: add timestamp option 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (9 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 10/15] log: add hook for printing log messages Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 12/15] log: add optional support of syslog Stephen Hemminger ` (3 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test/test_eal_flags.c | 26 ++++ doc/guides/prog_guide/log_lib.rst | 26 ++++ 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 | 7 +- lib/log/log_internal.h | 9 ++ lib/log/log_private.h | 11 ++ lib/log/log_timestamp.c | 210 ++++++++++++++++++++++++++++ lib/log/meson.build | 6 +- lib/log/version.map | 1 + 13 files changed, 318 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_timestamp.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index a5c0c67357..40dd288d5f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ea45c79d5c..ec3b5c3dfd 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1838,7 +1840,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 --" @@ -1846,7 +1848,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: { @@ -2210,6 +2219,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 118c1f593b..06bccbd026 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fab633976d..ceaa1f9487 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index c9648b7da7..0fda2abb97 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 48543ee941..6ab856272c 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -21,7 +21,7 @@ #include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -509,6 +509,11 @@ eal_log_syslog(const char *mode __rte_unused) void eal_log_init(const char *id __rte_unused) { + 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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67d2463b2f..67cfe72fc6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -3,7 +3,18 @@ #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 + /* Note: same as vfprintf() */ typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); +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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..04d8eba37b --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + struct timespec previous; /* when last msg was printed */ +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + static struct tm last_tm; + struct timespec delta; + + tm = localtime_r(&now->tv_sec, &tbuf); + delta = timespec_sub(now, &log_time.previous); + log_time.previous = *now; + + /* if minute, day, hour hasn't changed then print delta */ + if (tm->tm_min != last_tm.tm_min || + tm->tm_hour != last_tm.tm_hour || + tm->tm_yday != last_tm.tm_yday) { + last_tm = *tm; + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } else { + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.previous); + log_time.previous = now; + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + clock_gettime(CLOCK_MONOTONIC, &log_time.started); + log_time.previous = log_time.started; +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 891f77a237..04235f6ee5 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,5 +2,9 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files('log.c') +sources = files( + 'log.c', + 'log_timestamp.c', +) + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index a0341196d4..155f8b3bbe 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 12/15] log: add optional support of syslog 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (10 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 11/15] log: add timestamp option Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 13/15] log: add support for systemd journal Stephen Hemminger ` (2 subsequent siblings) 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------ doc/guides/prog_guide/log_lib.rst | 17 ++++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 28 +++--- lib/log/log_private.h | 17 ++++ lib/log/log_syslog.c | 88 +++++++++++++++++++ lib/log/meson.build | 4 + lib/log/version.map | 2 +- 9 files changed, 150 insertions(+), 43 deletions(-) create mode 100644 lib/log/log_syslog.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 40dd288d5f..06295030b2 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ec3b5c3dfd..ac1aadbef4 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2215,6 +2215,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 6ab856272c..f748551bc0 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -12,18 +12,19 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> -#include "log_internal.h" -#include "log_private.h" - #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif +#include "log_internal.h" +#include "log_private.h" + struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -496,20 +497,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } -/* Placeholder */ -int -eal_log_syslog(const char *mode __rte_unused) -{ - return -1; -} - /* * Called by rte_eal_init */ void -eal_log_init(const char *id __rte_unused) +eal_log_init(const char *id) { - if (log_timestamp_enabled()) + bool is_terminal; + +#ifdef RTE_EXEC_ENV_WINDOWS + is_terminal = _isatty(_fileno(stderr)); +#else + is_terminal = isatty(STDERR_FILENO); +#endif + + if (log_syslog_enabled(is_terminal)) + log_syslog_open(id, is_terminal); + else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else rte_logs.print_func = vfprintf; diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67cfe72fc6..532a481340 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -17,4 +17,21 @@ 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); +#ifdef RTE_EXEC_ENV_WINDOWS +static inline bool +log_syslog_enabled(bool is_tty __rte_unused) +{ + return false; +} + +static inline void +log_syslog_open(const char *id __rte_unused, bool is_terminal __rte_unused) +{ +} +#else + +bool log_syslog_enabled(bool is_tty); +void log_syslog_open(const char *id, bool is_terminal); +#endif + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..fb69921e05 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_SYSLOG_NONE = 0, /* do not use syslog */ + LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + LOG_SYSLOG_ALWAYS, /* always use syslog */ + LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +} log_syslog_opt; + +int +eal_log_syslog(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_syslog_opt = LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + log_syslog_opt = LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + log_syslog_opt = LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +} + +bool +log_syslog_enabled(bool is_terminal) +{ + switch (log_syslog_opt) { + default: + return false; + + case LOG_SYSLOG_ALWAYS: + case LOG_SYSLOG_BOTH: + return true; + + case LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + +/* + * When syslog is used, the log stream is redirected to a + * pseudo FILE handle that calls these functions. + */ +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +void +log_syslog_open(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + + if (log_syslog_opt == LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; + + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + rte_openlog_stream(log_stream); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 04235f6ee5..4ac232786e 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,4 +7,8 @@ sources = files( 'log_timestamp.c', ) +if not is_windows + sources += files('log_syslog.c') +endif + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 155f8b3bbe..8be6907840 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,7 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_syslog; + eal_log_syslog; # WINDOWS_NO_EXPORT eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 13/15] log: add support for systemd journal 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (11 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 12/15] log: add optional support of syslog Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 14/15] log: colorize log output Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 15/15] doc: add release note about log library Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- doc/guides/prog_guide/log_lib.rst | 14 ++ lib/eal/common/eal_common_options.c | 15 +++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 4 +- lib/log/log_internal.h | 3 + lib/log/log_journal.c | 200 ++++++++++++++++++++++++++++ lib/log/log_private.h | 16 +++ lib/log/meson.build | 4 + lib/log/version.map | 1 + 9 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_journal.c diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..476dedb097 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -100,6 +100,20 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. +Messages can be redirected to systemd journal which is an enhanced version of syslog with the ``--log-journal`` option. + +There are three possible settings for this option: + +*auto* + If stderr is redirected to journal by ``systemd`` service + then use journal socket to instead of stderr for log. + This is the default. + +*never* + Do not try to use journal. + +*always* + Always try to direct messages to journal socket. Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ac1aadbef4..6184d27ad3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_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 }, @@ -1617,6 +1618,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: case OPT_SYSLOG_NUM: + case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; @@ -1840,6 +1842,16 @@ eal_parse_common_option(int opt, const char *optarg, break; #endif +#ifdef RTE_EXEC_ENV_LINUX + case OPT_LOG_JOURNAL_NUM: + if (eal_log_journal(optarg) < 0) { + EAL_LOG(ERR, "invalid parameters for --" + OPT_LOG_JOURNAL); + return -1; + } + break; +#endif + case OPT_LOG_LEVEL_NUM: if (eal_parse_log_level(optarg) < 0) { EAL_LOG(ERR, @@ -2217,6 +2229,9 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif +#ifdef RTE_EXEC_ENV_LINUX + " --"OPT_LOG_JOURNAL"[=<when>] Enable use of systemd journal\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..c5a1c70288 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -35,6 +35,8 @@ enum { OPT_LCORES_NUM, #define OPT_LOG_LEVEL "log-level" OPT_LOG_LEVEL_NUM, +#define OPT_LOG_JOURNAL "log-journal" + OPT_LOG_JOURNAL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, #define OPT_TRACE "trace" diff --git a/lib/log/log.c b/lib/log/log.c index f748551bc0..96fa651e81 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -511,7 +511,9 @@ eal_log_init(const char *id) is_terminal = isatty(STDERR_FILENO); #endif - if (log_syslog_enabled(is_terminal)) + if (log_journal_enabled()) + log_journal_open(id); + else if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..2475174fce --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,200 @@ +/* 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" + +static enum { + LOG_JOURNAL_NEVER = 0, /* do not use journal */ + LOG_JOURNAL_AUTO, /* use if stderr is set to journal */ + LOG_JOURNAL_ALWAYS, /* always try to use journal */ +} log_journal_opt = LOG_JOURNAL_AUTO; + +static int log_journal_fd = -1; + +int +eal_log_journal(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_journal_opt = LOG_JOURNAL_AUTO; + else if (strcmp(str, "always") == 0) + log_journal_opt = LOG_JOURNAL_ALWAYS; + else if (strcmp(str, "never") == 0) + log_journal_opt = LOG_JOURNAL_NEVER; + else + return -1; + return 0; +} + +/* + * send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +static int +journal_send(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[16]; /* "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(log_journal_fd, iov, n); +} + + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(buf, size); +} + +static int +journal_log_close(__rte_unused void *c) +{ + close(log_journal_fd); + log_journal_fd = -1; + 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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return -1; + } + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + perror("connect"); + close(s); + return -1; + } + + return s; +} + +bool log_journal_enabled(void) +{ + if (log_journal_opt == LOG_JOURNAL_NEVER) + return false; + + if (log_journal_opt == LOG_JOURNAL_AUTO && + !is_journal(STDERR_FILENO)) + return false; + + log_journal_fd = open_journal(); + if (log_journal_fd < 0) + return false; + + return true; +} + +void log_journal_open(const char *id) +{ + FILE *log_stream; + char *syslog_id = NULL; + ssize_t len; + + /* Send identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", + id, getpid()); + if (len == 0) + goto error; + + if (write(log_journal_fd, syslog_id, len) != len) { + perror("write"); + goto error; + } + + free(syslog_id); + + /* redirect other log messages to journal */ + log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) { + rte_openlog_stream(log_stream); + return; + } + +error: + free(syslog_id); + close(log_journal_fd); + log_journal_fd = -1; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 532a481340..d8602681b2 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -34,4 +34,20 @@ bool log_syslog_enabled(bool is_tty); void log_syslog_open(const char *id, bool is_terminal); #endif +#ifdef RTE_EXEC_ENV_LINUX +bool log_journal_enabled(void); +void log_journal_open(const char *id); +#else +static inline bool +log_journal_enabled(void) +{ + return false; +} + +static inline void +log_journal_open(const char *id __rte_unused) +{ +} +#endif /* !RTE_EXEC_ENV_LINUX */ + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 4ac232786e..86e4452b19 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 8be6907840..800d3943bc 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 14/15] log: colorize log output 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (12 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 13/15] log: add support for systemd journal Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 15/15] doc: add release note about log library Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- app/test/test_eal_flags.c | 24 +++++ doc/guides/prog_guide/log_lib.rst | 15 +++ lib/eal/common/eal_common_options.c | 11 +++ lib/eal/common/eal_options.h | 6 +- lib/log/log.c | 19 ++-- lib/log/log_color.c | 148 ++++++++++++++++++++++++++++ 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, 230 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_color.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 06295030b2..6ee56ec97a 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 476dedb097..647c3fc28a 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 6184d27ad3..de19b1c258 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_NUM }, {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM }, @@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[]) case OPT_SYSLOG_NUM: case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: + case OPT_LOG_COLOR_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -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) { @@ -2238,6 +2248,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index c5a1c70288..c0686c2544 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -33,10 +33,12 @@ enum { OPT_HUGE_UNLINK_NUM, #define OPT_LCORES "lcores" OPT_LCORES_NUM, -#define OPT_LOG_LEVEL "log-level" - OPT_LOG_LEVEL_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_LOG_JOURNAL "log-journal" OPT_LOG_JOURNAL_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" diff --git a/lib/log/log.c b/lib/log/log.c index 96fa651e81..8b7b394f49 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -511,14 +511,21 @@ eal_log_init(const char *id) is_terminal = isatty(STDERR_FILENO); #endif - if (log_journal_enabled()) + if (log_journal_enabled()) { log_journal_open(id); - else if (log_syslog_enabled(is_terminal)) + } else if (log_syslog_enabled(is_terminal)) { log_syslog_open(id, is_terminal); - else if (log_timestamp_enabled()) - rte_logs.print_func = log_print_with_timestamp; - else - rte_logs.print_func = vfprintf; + } else if (log_timestamp_enabled()) { + if (log_color_enabled(is_terminal)) + rte_logs.print_func = color_print_with_timestamp; + else + rte_logs.print_func = log_print_with_timestamp; + } else { + if (log_color_enabled(is_terminal)) + rte_logs.print_func = color_print; + else + rte_logs.print_func = vfprintf; + } #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..db11306e55 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, /* default */ + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +/* Standard terminal escape codes for colors and bold */ +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\033[31m", + [COLOR_GREEN] = "\033[32m", + [COLOR_YELLOW] = "\033[33m", + [COLOR_BLUE] = "\033[34m", + [COLOR_MAGENTA] = "\033[35m", + [COLOR_CYAN] = "\033[36m", + [COLOR_WHITE] = "\033[37m", + [COLOR_BOLD] = "\033[1m", + [COLOR_CLEAR] = "\033[0m", +}; + +__rte_format_printf(3, 4) +static int +color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + switch (log_color_mode) { + default: + case LOG_COLOR_NEVER: + return false; + case LOG_COLOR_ALWAYS: + return true; + case LOG_COLOR_AUTO: + return is_terminal; + } +} + +int +color_print(FILE *f, const char *format, va_list ap) +{ + const int level = rte_log_cur_msg_loglevel(); + char *cp, *msg; + char buf[LINE_MAX]; + int ret = 0; + + vsnprintf(buf, LINE_MAX, format, ap); + msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(f, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, format, ap); +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 82fdc21ac2..bba7041ea3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index d8602681b2..855e32db90 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -50,4 +50,12 @@ log_journal_open(const char *id __rte_unused) } #endif /* !RTE_EXEC_ENV_LINUX */ +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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 86e4452b19..b3de57b9c7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 800d3943bc..09d8a4289b 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_25 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; # WINDOWS_NO_EXPORT eal_log_level2str; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v24 15/15] doc: add release note about log library 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (13 preceding siblings ...) 2024-09-18 20:52 ` [PATCH v24 14/15] log: colorize log output Stephen Hemminger @ 2024-09-18 20:52 ` Stephen Hemminger 14 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-18 20:52 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng Significant enough to add some documentation. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- doc/guides/rel_notes/release_24_11.rst | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst index 0ff70d9057..d6fb6c137b 100644 --- a/doc/guides/rel_notes/release_24_11.rst +++ b/doc/guides/rel_notes/release_24_11.rst @@ -55,6 +55,33 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Enhancements to logging library.** + + * Syslog related changes + + * The meaning of the *--syslog* option has changed. + Use of syslog is controlled by the *--syslog* option. + The default is now *auto* which uses syslog only if stderr + is not a terminal device. + + * The syslog facility is now set to **LOG_USER** if stderr is a terminal + and **LOG_DAEMON** otherwise. + + * Syslog is now supported on FreeBSD (but not on Windows). + + * 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. + + * Log messages are now in color if going to a terminal (similar to dmesg). + The default format shows timestamp in green, subsystem in yellow, + and the message is bold, boldface or normal depending on severity. + + * 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. + Removed Items ------------- -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 00/15] Logging enhancements for 24.11 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (23 preceding siblings ...) 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 01/15] maintainers: add for log library Stephen Hemminger ` (15 more replies) 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (4 subsequent siblings) 29 siblings, 16 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger mprovements 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 syslog if output is going to a terminal. Add myself as maintainer for log because by now have added more than previous authors. v25 - make the delta and relative time stamp formats thread safe. Use atomic 64 bit value (nanoseconds) and convert to timespec. Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog 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 | 64 ++++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 -- doc/guides/prog_guide/log_lib.rst | 72 ++++++ doc/guides/rel_notes/release_24_11.rst | 27 ++ lib/eal/common/eal_common_debug.c | 6 +- lib/eal/common/eal_common_options.c | 135 ++++++---- lib/eal/common/eal_internal_cfg.h | 1 - lib/eal/common/eal_options.h | 7 + lib/eal/freebsd/eal.c | 64 +---- lib/eal/linux/eal.c | 68 +---- lib/eal/windows/eal.c | 49 +--- 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 | 71 ++++-- lib/log/log_color.c | 148 +++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 28 +- lib/log/log_journal.c | 200 +++++++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 61 +++++ lib/log/log_syslog.c | 88 +++++++ lib/log/log_timestamp.c | 240 ++++++++++++++++++ lib/log/log_windows.c | 18 -- lib/log/meson.build | 12 +- lib/log/version.map | 5 +- 27 files changed, 1129 insertions(+), 377 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.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 01/15] maintainers: add for log library 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (14 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Chengwen Feng, Bruce Richardson "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c5a703b5c0..ecf6f955cc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -185,6 +185,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 02/15] windows: make getopt functions have const properties 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 01/15] maintainers: add for log library Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (13 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 03/15] windows: add os shim for localtime_r 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 01/15] maintainers: add for log library Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 04/15] eal: make eal_log_level_parse common Stephen Hemminger ` (12 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..665c9ac93b 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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_ */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 04/15] eal: make eal_log_level_parse common 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (2 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (11 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index f1a5e329a5..eb079a65a9 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 1229230063..d3b40e81d8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index d742cc98e2..0ded386472 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 28b78a95a6..a77e590a72 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 05/15] eal: do not duplicate rte_init_alert() messages 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (3 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 04/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (10 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3b40e81d8..7b974608e4 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 0ded386472..7c26393d00 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -840,8 +840,7 @@ static int rte_eal_vfio_setup(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); } /* -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 06/15] eal: change rte_exit() output to match rte_log() 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (4 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 07/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (9 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..bcfcd6df6f 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 07/15] log: move handling of syslog facility out of eal 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (5 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 08/15] eal: initialize log before everything else Stephen Hemminger ` (8 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/common/eal_internal_cfg.h | 1 - lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log.c | 2 ++ lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 11 files changed, 70 insertions(+), 65 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index eb079a65a9..918cc013fe 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1877,7 +1830,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa..f53ab8b4aa 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -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 */ diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7b974608e4..a609d40ee0 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 7c26393d00..5aedd348d1 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); @@ -1113,8 +1113,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index a77e590a72..69a8fc8d80 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..4b24e145b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,6 +13,7 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 19d7f9cdb6..879567ba15 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 08/15] eal: initialize log before everything else 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (6 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 07/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 09/15] log: drop syslog support, and make code common Stephen Hemminger ` (7 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a609d40ee0..118c1f593b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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 +581,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 5aedd348d1..fab633976d 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -936,6 +936,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."); @@ -959,9 +968,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); @@ -1113,13 +1119,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_eal_vfio_setup() < 0) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 69a8fc8d80..c9648b7da7 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 09/15] log: drop syslog support, and make code common 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (7 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 08/15] eal: initialize log before everything else Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 10/15] log: add hook for printing log messages Stephen Hemminger ` (6 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 41 +++++------ lib/log/log_freebsd.c | 11 --- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 9 files changed, 23 insertions(+), 179 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 71d8dba731..a5c0c67357 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 918cc013fe..ea45c79d5c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2206,9 +2206,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 4b24e145b6..3fe86ddcd7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -57,9 +57,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -72,8 +69,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -87,17 +82,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -507,14 +492,19 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; - #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); @@ -527,8 +517,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 33a0925c43..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include <rte_common.h> -#include "log_internal.h" - -void -eal_log_init(__rte_unused const char *id) -{ -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 879567ba15..a0341196d4 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 10/15] log: add hook for printing log messages 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (8 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 09/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 11/15] log: add timestamp option Stephen Hemminger ` (5 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/log/log.c | 6 +++++- lib/log/log_private.h | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_private.h diff --git a/lib/log/log.c b/lib/log/log.c index 3fe86ddcd7..48543ee941 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -18,6 +18,7 @@ #include <rte_per_lcore.h> #include "log_internal.h" +#include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS #define strdup _strdup @@ -33,11 +34,13 @@ 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 { @@ -74,6 +77,7 @@ int rte_openlog_stream(FILE *f) { rte_logs.file = f; + rte_logs.print_func = vfprintf; return 0; } @@ -470,7 +474,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; } diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..67d2463b2f --- /dev/null +++ b/lib/log/log_private.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef LOG_PRIVATE_H +#define LOG_PRIVATE_H + +/* Note: same as vfprintf() */ +typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); + +#endif /* LOG_PRIVATE_H */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 11/15] log: add timestamp option 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (9 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 10/15] log: add hook for printing log messages Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 12/15] log: add optional support of syslog Stephen Hemminger ` (4 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test/test_eal_flags.c | 26 +++ doc/guides/prog_guide/log_lib.rst | 26 +++ 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 | 7 +- lib/log/log_internal.h | 9 ++ lib/log/log_private.h | 11 ++ lib/log/log_timestamp.c | 240 ++++++++++++++++++++++++++++ lib/log/meson.build | 6 +- lib/log/version.map | 1 + 13 files changed, 348 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_timestamp.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index a5c0c67357..40dd288d5f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ea45c79d5c..ec3b5c3dfd 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1838,7 +1840,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 --" @@ -1846,7 +1848,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: { @@ -2210,6 +2219,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 118c1f593b..06bccbd026 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index fab633976d..ceaa1f9487 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index c9648b7da7..0fda2abb97 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 48543ee941..6ab856272c 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -21,7 +21,7 @@ #include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -509,6 +509,11 @@ eal_log_syslog(const char *mode __rte_unused) void eal_log_init(const char *id __rte_unused) { + 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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67d2463b2f..67cfe72fc6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -3,7 +3,18 @@ #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 + /* Note: same as vfprintf() */ typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); +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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..b4b0bca6a8 --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> +#include <rte_stdatomic.h> +#include <rte_time.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +#ifndef NS_PER_SEC +#define NS_PER_SEC 1E9 +#endif + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + RTE_ATOMIC(uint64_t) last_monotonic; + RTE_ATOMIC(uint64_t) last_realtime; +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Format a timestamp which shows time between messages. + */ +static ssize_t +format_delta(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct timespec delta; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + previous = rte_atomic_exchange_explicit(&log_time.last_monotonic, + ns, rte_memory_order_seq_cst); + delta = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, *last_tm, tbuf1, tbuf2; + time_t last_sec; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + tm = localtime_r(&now->tv_sec, &tbuf1); + + previous = rte_atomic_exchange_explicit(&log_time.last_realtime, + ns, rte_memory_order_seq_cst); + last_sec = previous / NS_PER_SEC; + last_tm = localtime_r(&last_sec, &tbuf2); + if (tm->tm_min == last_tm->tm_min && + tm->tm_hour == last_tm->tm_hour && + tm->tm_yday == last_tm->tm_yday) { + struct timespec elapsed; + + elapsed = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)elapsed.tv_sec, + (unsigned long)elapsed.tv_nsec / 1000u); + } else { + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + return format_delta(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + log_time.started = now; + rte_atomic_store_explicit(&log_time.last_monotonic, rte_timespec_to_ns(&now), + rte_memory_order_seq_cst); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 891f77a237..04235f6ee5 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,5 +2,9 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files('log.c') +sources = files( + 'log.c', + 'log_timestamp.c', +) + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index a0341196d4..155f8b3bbe 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 12/15] log: add optional support of syslog 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (10 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 11/15] log: add timestamp option Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 13/15] log: add support for systemd journal Stephen Hemminger ` (3 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------ doc/guides/prog_guide/log_lib.rst | 17 ++++ lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 28 +++--- lib/log/log_private.h | 17 ++++ lib/log/log_syslog.c | 88 +++++++++++++++++++ lib/log/meson.build | 4 + lib/log/version.map | 2 +- 9 files changed, 150 insertions(+), 43 deletions(-) create mode 100644 lib/log/log_syslog.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 40dd288d5f..06295030b2 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..abaedc7212 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -83,6 +83,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ec3b5c3dfd..ac1aadbef4 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2215,6 +2215,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 6ab856272c..f748551bc0 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -12,18 +12,19 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> -#include "log_internal.h" -#include "log_private.h" - #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif +#include "log_internal.h" +#include "log_private.h" + struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -496,20 +497,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } -/* Placeholder */ -int -eal_log_syslog(const char *mode __rte_unused) -{ - return -1; -} - /* * Called by rte_eal_init */ void -eal_log_init(const char *id __rte_unused) +eal_log_init(const char *id) { - if (log_timestamp_enabled()) + bool is_terminal; + +#ifdef RTE_EXEC_ENV_WINDOWS + is_terminal = _isatty(_fileno(stderr)); +#else + is_terminal = isatty(STDERR_FILENO); +#endif + + if (log_syslog_enabled(is_terminal)) + log_syslog_open(id, is_terminal); + else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else rte_logs.print_func = vfprintf; diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67cfe72fc6..532a481340 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -17,4 +17,21 @@ 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); +#ifdef RTE_EXEC_ENV_WINDOWS +static inline bool +log_syslog_enabled(bool is_tty __rte_unused) +{ + return false; +} + +static inline void +log_syslog_open(const char *id __rte_unused, bool is_terminal __rte_unused) +{ +} +#else + +bool log_syslog_enabled(bool is_tty); +void log_syslog_open(const char *id, bool is_terminal); +#endif + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..fb69921e05 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_SYSLOG_NONE = 0, /* do not use syslog */ + LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + LOG_SYSLOG_ALWAYS, /* always use syslog */ + LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +} log_syslog_opt; + +int +eal_log_syslog(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_syslog_opt = LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + log_syslog_opt = LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + log_syslog_opt = LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +} + +bool +log_syslog_enabled(bool is_terminal) +{ + switch (log_syslog_opt) { + default: + return false; + + case LOG_SYSLOG_ALWAYS: + case LOG_SYSLOG_BOTH: + return true; + + case LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + +/* + * When syslog is used, the log stream is redirected to a + * pseudo FILE handle that calls these functions. + */ +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +void +log_syslog_open(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + + if (log_syslog_opt == LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; + + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + rte_openlog_stream(log_stream); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 04235f6ee5..4ac232786e 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,4 +7,8 @@ sources = files( 'log_timestamp.c', ) +if not is_windows + sources += files('log_syslog.c') +endif + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 155f8b3bbe..8be6907840 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,7 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_syslog; + eal_log_syslog; # WINDOWS_NO_EXPORT eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 13/15] log: add support for systemd journal 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (11 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 12/15] log: add optional support of syslog Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 14/15] log: colorize log output Stephen Hemminger ` (2 subsequent siblings) 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- doc/guides/prog_guide/log_lib.rst | 14 ++ lib/eal/common/eal_common_options.c | 15 +++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 4 +- lib/log/log_internal.h | 3 + lib/log/log_journal.c | 200 ++++++++++++++++++++++++++++ lib/log/log_private.h | 16 +++ lib/log/meson.build | 4 + lib/log/version.map | 1 + 9 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_journal.c diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index abaedc7212..476dedb097 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -100,6 +100,20 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. +Messages can be redirected to systemd journal which is an enhanced version of syslog with the ``--log-journal`` option. + +There are three possible settings for this option: + +*auto* + If stderr is redirected to journal by ``systemd`` service + then use journal socket to instead of stderr for log. + This is the default. + +*never* + Do not try to use journal. + +*always* + Always try to direct messages to journal socket. Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ac1aadbef4..6184d27ad3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_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 }, @@ -1617,6 +1618,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: case OPT_SYSLOG_NUM: + case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; @@ -1840,6 +1842,16 @@ eal_parse_common_option(int opt, const char *optarg, break; #endif +#ifdef RTE_EXEC_ENV_LINUX + case OPT_LOG_JOURNAL_NUM: + if (eal_log_journal(optarg) < 0) { + EAL_LOG(ERR, "invalid parameters for --" + OPT_LOG_JOURNAL); + return -1; + } + break; +#endif + case OPT_LOG_LEVEL_NUM: if (eal_parse_log_level(optarg) < 0) { EAL_LOG(ERR, @@ -2217,6 +2229,9 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif +#ifdef RTE_EXEC_ENV_LINUX + " --"OPT_LOG_JOURNAL"[=<when>] Enable use of systemd journal\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..c5a1c70288 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -35,6 +35,8 @@ enum { OPT_LCORES_NUM, #define OPT_LOG_LEVEL "log-level" OPT_LOG_LEVEL_NUM, +#define OPT_LOG_JOURNAL "log-journal" + OPT_LOG_JOURNAL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, #define OPT_TRACE "trace" diff --git a/lib/log/log.c b/lib/log/log.c index f748551bc0..96fa651e81 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -511,7 +511,9 @@ eal_log_init(const char *id) is_terminal = isatty(STDERR_FILENO); #endif - if (log_syslog_enabled(is_terminal)) + if (log_journal_enabled()) + log_journal_open(id); + else if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..2475174fce --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,200 @@ +/* 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" + +static enum { + LOG_JOURNAL_NEVER = 0, /* do not use journal */ + LOG_JOURNAL_AUTO, /* use if stderr is set to journal */ + LOG_JOURNAL_ALWAYS, /* always try to use journal */ +} log_journal_opt = LOG_JOURNAL_AUTO; + +static int log_journal_fd = -1; + +int +eal_log_journal(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_journal_opt = LOG_JOURNAL_AUTO; + else if (strcmp(str, "always") == 0) + log_journal_opt = LOG_JOURNAL_ALWAYS; + else if (strcmp(str, "never") == 0) + log_journal_opt = LOG_JOURNAL_NEVER; + else + return -1; + return 0; +} + +/* + * send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +static int +journal_send(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[16]; /* "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(log_journal_fd, iov, n); +} + + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(buf, size); +} + +static int +journal_log_close(__rte_unused void *c) +{ + close(log_journal_fd); + log_journal_fd = -1; + 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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return -1; + } + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + perror("connect"); + close(s); + return -1; + } + + return s; +} + +bool log_journal_enabled(void) +{ + if (log_journal_opt == LOG_JOURNAL_NEVER) + return false; + + if (log_journal_opt == LOG_JOURNAL_AUTO && + !is_journal(STDERR_FILENO)) + return false; + + log_journal_fd = open_journal(); + if (log_journal_fd < 0) + return false; + + return true; +} + +void log_journal_open(const char *id) +{ + FILE *log_stream; + char *syslog_id = NULL; + ssize_t len; + + /* Send identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", + id, getpid()); + if (len == 0) + goto error; + + if (write(log_journal_fd, syslog_id, len) != len) { + perror("write"); + goto error; + } + + free(syslog_id); + + /* redirect other log messages to journal */ + log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) { + rte_openlog_stream(log_stream); + return; + } + +error: + free(syslog_id); + close(log_journal_fd); + log_journal_fd = -1; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 532a481340..d8602681b2 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -34,4 +34,20 @@ bool log_syslog_enabled(bool is_tty); void log_syslog_open(const char *id, bool is_terminal); #endif +#ifdef RTE_EXEC_ENV_LINUX +bool log_journal_enabled(void); +void log_journal_open(const char *id); +#else +static inline bool +log_journal_enabled(void) +{ + return false; +} + +static inline void +log_journal_open(const char *id __rte_unused) +{ +} +#endif /* !RTE_EXEC_ENV_LINUX */ + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 4ac232786e..86e4452b19 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 8be6907840..800d3943bc 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 14/15] log: colorize log output 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (12 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 13/15] log: add support for systemd journal Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 15/15] doc: add release note about log library Stephen Hemminger 2024-09-20 14:47 ` [PATCH v25 00/15] Logging enhancements for 24.11 Patrick Robb 15 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- app/test/test_eal_flags.c | 24 +++++ doc/guides/prog_guide/log_lib.rst | 15 +++ lib/eal/common/eal_common_options.c | 11 +++ lib/eal/common/eal_options.h | 6 +- lib/log/log.c | 19 ++-- lib/log/log_color.c | 148 ++++++++++++++++++++++++++++ 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, 230 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_color.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 06295030b2..6ee56ec97a 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 476dedb097..647c3fc28a 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 6184d27ad3..de19b1c258 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_NUM }, {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM }, @@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[]) case OPT_SYSLOG_NUM: case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: + case OPT_LOG_COLOR_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -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) { @@ -2238,6 +2248,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index c5a1c70288..c0686c2544 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -33,10 +33,12 @@ enum { OPT_HUGE_UNLINK_NUM, #define OPT_LCORES "lcores" OPT_LCORES_NUM, -#define OPT_LOG_LEVEL "log-level" - OPT_LOG_LEVEL_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_LOG_JOURNAL "log-journal" OPT_LOG_JOURNAL_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" diff --git a/lib/log/log.c b/lib/log/log.c index 96fa651e81..8b7b394f49 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -511,14 +511,21 @@ eal_log_init(const char *id) is_terminal = isatty(STDERR_FILENO); #endif - if (log_journal_enabled()) + if (log_journal_enabled()) { log_journal_open(id); - else if (log_syslog_enabled(is_terminal)) + } else if (log_syslog_enabled(is_terminal)) { log_syslog_open(id, is_terminal); - else if (log_timestamp_enabled()) - rte_logs.print_func = log_print_with_timestamp; - else - rte_logs.print_func = vfprintf; + } else if (log_timestamp_enabled()) { + if (log_color_enabled(is_terminal)) + rte_logs.print_func = color_print_with_timestamp; + else + rte_logs.print_func = log_print_with_timestamp; + } else { + if (log_color_enabled(is_terminal)) + rte_logs.print_func = color_print; + else + rte_logs.print_func = vfprintf; + } #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..db11306e55 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, /* default */ + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +/* Standard terminal escape codes for colors and bold */ +static const char * const color_code[] = { + [COLOR_NONE] = "", + [COLOR_RED] = "\033[31m", + [COLOR_GREEN] = "\033[32m", + [COLOR_YELLOW] = "\033[33m", + [COLOR_BLUE] = "\033[34m", + [COLOR_MAGENTA] = "\033[35m", + [COLOR_CYAN] = "\033[36m", + [COLOR_WHITE] = "\033[37m", + [COLOR_BOLD] = "\033[1m", + [COLOR_CLEAR] = "\033[0m", +}; + +__rte_format_printf(3, 4) +static int +color_fprintf(FILE *out, enum color color, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + va_start(args, fmt); + ret = fprintf(out, "%s", color_code[color]); + ret += vfprintf(out, fmt, args); + ret += fprintf(out, "%s", color_code[COLOR_CLEAR]); + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + switch (log_color_mode) { + default: + case LOG_COLOR_NEVER: + return false; + case LOG_COLOR_ALWAYS: + return true; + case LOG_COLOR_AUTO: + return is_terminal; + } +} + +int +color_print(FILE *f, const char *format, va_list ap) +{ + const int level = rte_log_cur_msg_loglevel(); + char *cp, *msg; + char buf[LINE_MAX]; + int ret = 0; + + vsnprintf(buf, LINE_MAX, format, ap); + msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_fprintf(f, COLOR_YELLOW, "%.*s", + (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + ret += fprintf(f, "%s", msg); + else if (level >= (int)RTE_LOG_ERR) + ret += color_fprintf(f, COLOR_BOLD, "%s", msg); + else + ret += color_fprintf(f, COLOR_RED, "%s", msg); + + return ret; +} + +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + color_fprintf(f, COLOR_GREEN, "[%s] ", tsbuf); + + return color_print(f, format, ap); +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 82fdc21ac2..bba7041ea3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index d8602681b2..855e32db90 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -50,4 +50,12 @@ log_journal_open(const char *id __rte_unused) } #endif /* !RTE_EXEC_ENV_LINUX */ +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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 86e4452b19..b3de57b9c7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 800d3943bc..09d8a4289b 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_25 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; # WINDOWS_NO_EXPORT eal_log_level2str; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v25 15/15] doc: add release note about log library 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (13 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 14/15] log: colorize log output Stephen Hemminger @ 2024-09-19 15:04 ` Stephen Hemminger 2024-09-30 20:34 ` Tyler Retzlaff 2024-09-20 14:47 ` [PATCH v25 00/15] Logging enhancements for 24.11 Patrick Robb 15 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-09-19 15:04 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng Significant enough to add some documentation. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- doc/guides/rel_notes/release_24_11.rst | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst index 0ff70d9057..d6fb6c137b 100644 --- a/doc/guides/rel_notes/release_24_11.rst +++ b/doc/guides/rel_notes/release_24_11.rst @@ -55,6 +55,33 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Enhancements to logging library.** + + * Syslog related changes + + * The meaning of the *--syslog* option has changed. + Use of syslog is controlled by the *--syslog* option. + The default is now *auto* which uses syslog only if stderr + is not a terminal device. + + * The syslog facility is now set to **LOG_USER** if stderr is a terminal + and **LOG_DAEMON** otherwise. + + * Syslog is now supported on FreeBSD (but not on Windows). + + * 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. + + * Log messages are now in color if going to a terminal (similar to dmesg). + The default format shows timestamp in green, subsystem in yellow, + and the message is bold, boldface or normal depending on severity. + + * 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. + Removed Items ------------- -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v25 15/15] doc: add release note about log library 2024-09-19 15:04 ` [PATCH v25 15/15] doc: add release note about log library Stephen Hemminger @ 2024-09-30 20:34 ` Tyler Retzlaff 0 siblings, 0 replies; 445+ messages in thread From: Tyler Retzlaff @ 2024-09-30 20:34 UTC (permalink / raw) To: Stephen Hemminger Cc: dev, Morten Brørup, Bruce Richardson, Chengwen Feng On Thu, Sep 19, 2024 at 08:04:21AM -0700, Stephen Hemminger wrote: > Significant enough to add some documentation. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > Acked-by: Bruce Richardson <bruce.richardson@intel.com> > Acked-by: Chengwen Feng <fengchengwen@huawei.com> > --- Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v25 00/15] Logging enhancements for 24.11 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger ` (14 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 15/15] doc: add release note about log library Stephen Hemminger @ 2024-09-20 14:47 ` Patrick Robb 15 siblings, 0 replies; 445+ messages in thread From: Patrick Robb @ 2024-09-20 14:47 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev [-- Attachment #1: Type: text/plain, Size: 101 bytes --] Recheck-request: iol-marvell-Functional putting in a ci lab retest for the failures on this series. [-- Attachment #2: Type: text/html, Size: 168 bytes --] ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 00/15] Log subsystem improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (24 preceding siblings ...) 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 01/15] maintainers: add for log library Stephen Hemminger ` (16 more replies) 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (3 subsequent siblings) 29 siblings, 17 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev; +Cc: 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 syslog if output is going to a terminal. Add myself as maintainer for log because by now have added more than previous authors. v26 - rebase and change release note - by default, do not disable color - support dark mode with colors - when using color format message to string then print to avoid getting multiple threads intermixing on output. Stephen Hemminger (15): maintainers: add for log library windows: make getopt functions have const properties windows: add os shim for localtime_r 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: move handling of syslog facility out of eal eal: initialize log before everything else log: drop syslog support, and make code common log: add hook for printing log messages log: add timestamp option log: add optional support of syslog 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 | 64 ++++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 -- doc/guides/prog_guide/log_lib.rst | 76 +++++- doc/guides/rel_notes/release_24_11.rst | 26 ++ lib/eal/common/eal_common_debug.c | 6 +- lib/eal/common/eal_common_options.c | 135 ++++++---- lib/eal/common/eal_internal_cfg.h | 1 - lib/eal/common/eal_options.h | 7 + lib/eal/freebsd/eal.c | 64 +---- lib/eal/linux/eal.c | 68 +---- lib/eal/windows/eal.c | 49 +--- 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 | 71 ++++-- lib/log/log_color.c | 216 ++++++++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 28 +- lib/log/log_journal.c | 200 +++++++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 61 +++++ lib/log/log_syslog.c | 88 +++++++ lib/log/log_timestamp.c | 240 ++++++++++++++++++ lib/log/log_windows.c | 18 -- lib/log/meson.build | 12 +- lib/log/version.map | 5 +- 27 files changed, 1197 insertions(+), 380 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.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 01/15] maintainers: add for log library 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 02/15] windows: make getopt functions have const properties Stephen Hemminger ` (15 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Chengwen Feng, Bruce Richardson, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6814991735..7141f490b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -186,6 +186,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 02/15] windows: make getopt functions have const properties 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 01/15] maintainers: add for log library Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 03/15] windows: add os shim for localtime_r Stephen Hemminger ` (14 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup, Bruce Richardson, Chengwen Feng, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 03/15] windows: add os shim for localtime_r 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 01/15] maintainers: add for log library Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 02/15] windows: make getopt functions have const properties Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 04/15] eal: make eal_log_level_parse common Stephen Hemminger ` (13 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk, Pallavi Kadam Windows does not have localtime_r but it does have a similar function that can be used instead. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..665c9ac93b 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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_ */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 04/15] eal: make eal_log_level_parse common 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 03/15] windows: add os shim for localtime_r Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (12 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Dmitry Kozlyuk, Pallavi Kadam The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index f1a5e329a5..eb079a65a9 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 1229230063..d3b40e81d8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 54577b7718..40d750ed0d 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 28b78a95a6..a77e590a72 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 05/15] eal: do not duplicate rte_init_alert() messages 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 04/15] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-17 16:47 ` David Marchand 2024-10-16 20:20 ` [PATCH v26 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (11 subsequent siblings) 16 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/freebsd/eal.c | 3 +-- lib/eal/linux/eal.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3b40e81d8..7b974608e4 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 40d750ed0d..c53a051405 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); } /* -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v26 05/15] eal: do not duplicate rte_init_alert() messages 2024-10-16 20:20 ` [PATCH v26 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-10-17 16:47 ` David Marchand 2024-10-17 17:17 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: David Marchand @ 2024-10-17 16:47 UTC (permalink / raw) To: Stephen Hemminger Cc: dev, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng Hello, On Wed, Oct 16, 2024 at 10:24 PM Stephen Hemminger <stephen@networkplumber.org> wrote: > > The message already goes through logging, and does not need > to be printed on stderr. Message level should be ALERT > to match function name. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > Acked-by: Bruce Richardson <bruce.richardson@intel.com> > Acked-by: Chengwen Feng <fengchengwen@huawei.com> > --- > lib/eal/freebsd/eal.c | 3 +-- > lib/eal/linux/eal.c | 3 +-- > 2 files changed, 2 insertions(+), 4 deletions(-) > > diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c > index d3b40e81d8..7b974608e4 100644 > --- a/lib/eal/freebsd/eal.c > +++ b/lib/eal/freebsd/eal.c > @@ -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(). */ > diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c > index 40d750ed0d..c53a051405 100644 > --- a/lib/eal/linux/eal.c > +++ b/lib/eal/linux/eal.c > @@ -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); > } > > /* Any reason why Windows was not changed? I can add the missing bit when applying. -- David Marchand ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v26 05/15] eal: do not duplicate rte_init_alert() messages 2024-10-17 16:47 ` David Marchand @ 2024-10-17 17:17 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-17 17:17 UTC (permalink / raw) To: David Marchand Cc: dev, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng On Thu, 17 Oct 2024 18:47:54 +0200 David Marchand <david.marchand@redhat.com> wrote: > > diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c > > index 40d750ed0d..c53a051405 100644 > > --- a/lib/eal/linux/eal.c > > +++ b/lib/eal/linux/eal.c > > @@ -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); > > } > > > > /* > > Any reason why Windows was not changed? > > I can add the missing bit when applying. No reason that Windows was not changed, just forgot about it. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 06/15] eal: change rte_exit() output to match rte_log() 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 07/15] log: move handling of syslog facility out of eal Stephen Hemminger ` (10 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..bcfcd6df6f 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 07/15] log: move handling of syslog facility out of eal 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 08/15] eal: initialize log before everything else Stephen Hemminger ` (9 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam The syslog facility property is better handled in lib/log rather than in eal. This also allows for changes to what syslog flag means in later steps. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_options.c | 51 ++--------------------------- lib/eal/common/eal_internal_cfg.h | 1 - lib/eal/freebsd/eal.c | 5 ++- lib/eal/linux/eal.c | 7 ++-- lib/eal/windows/eal.c | 6 ++-- lib/log/log.c | 2 ++ lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 ++- lib/log/log_linux.c | 47 ++++++++++++++++++++++++-- lib/log/log_windows.c | 8 ++++- lib/log/version.map | 1 + 11 files changed, 70 insertions(+), 65 deletions(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index eb079a65a9..918cc013fe 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -349,10 +346,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1290,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1877,7 +1830,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa..f53ab8b4aa 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -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 */ diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7b974608e4..a609d40ee0 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index c53a051405..9a0a1cf211 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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,8 +1103,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index a77e590a72..69a8fc8d80 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); @@ -250,7 +250,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); diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..4b24e145b6 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,6 +13,7 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 2dfb0c974b..47aa074da2 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -3,13 +3,56 @@ */ #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <syslog.h> +#include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + /* * default log function */ @@ -45,7 +88,7 @@ static cookie_io_functions_t console_log_func = { * once memzones are available. */ int -eal_log_init(const char *id, int facility) +eal_log_init(const char *id) { FILE *log_stream; @@ -53,7 +96,7 @@ eal_log_init(const char *id, int facility) if (log_stream == NULL) return -1; - openlog(id, LOG_NDELAY | LOG_PID, facility); + openlog(id, LOG_NDELAY | LOG_PID, log_facility); eal_log_set_default(log_stream); diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/version.map b/lib/log/version.map index 19d7f9cdb6..879567ba15 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 08/15] eal: initialize log before everything else 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 07/15] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 09/15] log: drop syslog support, and make code common Stephen Hemminger ` (8 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk, Pallavi Kadam 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_linux.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a609d40ee0..118c1f593b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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 +581,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 9a0a1cf211..62d3d281c4 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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,13 +1109,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_vfio_enable("vfio")) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 69a8fc8d80..c9648b7da7 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -250,9 +250,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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c index 47aa074da2..6d7dc8f3ab 100644 --- a/lib/log/log_linux.c +++ b/lib/log/log_linux.c @@ -87,18 +87,16 @@ static cookie_io_functions_t console_log_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", console_log_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 09/15] log: drop syslog support, and make code common 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 08/15] eal: initialize log before everything else Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 10/15] log: add hook for printing log messages Stephen Hemminger ` (7 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Tyler Retzlaff This patch makes the log setup code common across all platforms. Drops syslog support for now, will come back in later patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test/test_eal_flags.c | 11 ++- lib/eal/common/eal_common_options.c | 3 - lib/log/log.c | 41 +++++------ lib/log/log_freebsd.c | 11 --- lib/log/log_internal.h | 6 -- lib/log/log_linux.c | 102 ---------------------------- lib/log/log_windows.c | 22 ------ lib/log/meson.build | 5 +- lib/log/version.map | 1 - 9 files changed, 23 insertions(+), 179 deletions(-) delete mode 100644 lib/log/log_freebsd.c delete mode 100644 lib/log/log_linux.c delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 71d8dba731..a5c0c67357 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -984,11 +984,10 @@ test_misc_flags(void) const char *argv1[] = {prgname, prefix, mp_flag, "--no-pci"}; /* With -v */ const char *argv2[] = {prgname, prefix, mp_flag, "-v"}; + /* With empty --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv3[] = {prgname, prefix, mp_flag, - "--syslog", "syslog"}; - /* With empty --syslog (should fail) */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; /* With invalid --syslog */ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ @@ -1083,8 +1082,8 @@ test_misc_flags(void) printf("Error - process did not run ok with --syslog 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 with --syslog always flag\n"); goto fail; } if (launch_proc(argv5) == 0) { diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 918cc013fe..ea45c79d5c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -2206,9 +2206,6 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" -#ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" -#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 4b24e145b6..3fe86ddcd7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -57,9 +57,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -72,8 +69,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -87,17 +82,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -507,14 +492,19 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } +/* Placeholder */ +int +eal_log_syslog(const char *mode __rte_unused) +{ + return -1; +} + /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id __rte_unused) { - default_log_stream = default_log; - #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, "Debug dataplane logs available - lower performance\n"); @@ -527,8 +517,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 33a0925c43..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include <rte_common.h> -#include "log_internal.h" - -void -eal_log_init(__rte_unused const char *id) -{ -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 6d7dc8f3ab..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_common.h> -#include <rte_log.h> - -#include "log_internal.h" - -static int log_facility = LOG_DAEMON; - -static const struct { - const char *name; - int value; -} facilitys[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, -}; - -int -eal_log_syslog(const char *name) -{ - unsigned int i; - - for (i = 0; i < RTE_DIM(facilitys); i++) { - if (!strcmp(name, facilitys[i].name)) { - log_facility = facilitys[i].value; - return 0; - } - } - return -1; -} - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) -{ - FILE *log_stream; - - openlog(id, LOG_NDELAY | LOG_PID, log_facility); - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); -} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..891f77a237 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,8 +2,5 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files( - 'log.c', - 'log_' + exec_env + '.c', -) +sources = files('log.c') headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 879567ba15..a0341196d4 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 10/15] log: add hook for printing log messages 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 09/15] log: drop syslog support, and make code common Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 11/15] log: add timestamp option Stephen Hemminger ` (6 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/log/log.c | 6 +++++- lib/log/log_private.h | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_private.h diff --git a/lib/log/log.c b/lib/log/log.c index 3fe86ddcd7..48543ee941 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -18,6 +18,7 @@ #include <rte_per_lcore.h> #include "log_internal.h" +#include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS #define strdup _strdup @@ -33,11 +34,13 @@ 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 { @@ -74,6 +77,7 @@ int rte_openlog_stream(FILE *f) { rte_logs.file = f; + rte_logs.print_func = vfprintf; return 0; } @@ -470,7 +474,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; } diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..67d2463b2f --- /dev/null +++ b/lib/log/log_private.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef LOG_PRIVATE_H +#define LOG_PRIVATE_H + +/* Note: same as vfprintf() */ +typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); + +#endif /* LOG_PRIVATE_H */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 11/15] log: add timestamp option 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 10/15] log: add hook for printing log messages Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 12/15] log: add optional support of syslog Stephen Hemminger ` (5 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk, Pallavi Kadam 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test/test_eal_flags.c | 26 +++ doc/guides/prog_guide/log_lib.rst | 26 +++ 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 | 7 +- lib/log/log_internal.h | 9 ++ lib/log/log_private.h | 11 ++ lib/log/log_timestamp.c | 240 ++++++++++++++++++++++++++++ lib/log/meson.build | 6 +- lib/log/version.map | 1 + 13 files changed, 348 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_timestamp.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index a5c0c67357..40dd288d5f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -1054,6 +1054,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) { @@ -1161,6 +1174,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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..504eefe1d2 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -59,6 +59,32 @@ 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. +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 + + + Using Logging APIs to Generate Log Messages ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ea45c79d5c..ec3b5c3dfd 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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 }, @@ -1616,6 +1617,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; @@ -1838,7 +1840,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 --" @@ -1846,7 +1848,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: { @@ -2210,6 +2219,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 118c1f593b..06bccbd026 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 62d3d281c4..cf2f0fcab9 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index c9648b7da7..0fda2abb97 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 48543ee941..6ab856272c 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -21,7 +21,7 @@ #include "log_private.h" #ifdef RTE_EXEC_ENV_WINDOWS -#define strdup _strdup +#include <rte_os_shim.h> #endif struct rte_log_dynamic_type { @@ -509,6 +509,11 @@ eal_log_syslog(const char *mode __rte_unused) void eal_log_init(const char *id __rte_unused) { + 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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67d2463b2f..67cfe72fc6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -3,7 +3,18 @@ #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 + /* Note: same as vfprintf() */ typedef int (*log_print_t)(FILE *f, const char *fmt, va_list ap); +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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..b4b0bca6a8 --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> +#include <rte_stdatomic.h> +#include <rte_time.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +#ifndef NS_PER_SEC +#define NS_PER_SEC 1E9 +#endif + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + RTE_ATOMIC(uint64_t) last_monotonic; + RTE_ATOMIC(uint64_t) last_realtime; +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Format a timestamp which shows time between messages. + */ +static ssize_t +format_delta(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct timespec delta; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + previous = rte_atomic_exchange_explicit(&log_time.last_monotonic, + ns, rte_memory_order_seq_cst); + delta = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, *last_tm, tbuf1, tbuf2; + time_t last_sec; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + tm = localtime_r(&now->tv_sec, &tbuf1); + + previous = rte_atomic_exchange_explicit(&log_time.last_realtime, + ns, rte_memory_order_seq_cst); + last_sec = previous / NS_PER_SEC; + last_tm = localtime_r(&last_sec, &tbuf2); + if (tm->tm_min == last_tm->tm_min && + tm->tm_hour == last_tm->tm_hour && + tm->tm_yday == last_tm->tm_yday) { + struct timespec elapsed; + + elapsed = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)elapsed.tv_sec, + (unsigned long)elapsed.tv_nsec / 1000u); + } else { + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + return format_delta(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + log_time.started = now; + rte_atomic_store_explicit(&log_time.last_monotonic, rte_timespec_to_ns(&now), + rte_memory_order_seq_cst); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 891f77a237..04235f6ee5 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -2,5 +2,9 @@ # Copyright(c) 2023 Intel Corporation includes += global_inc -sources = files('log.c') +sources = files( + 'log.c', + 'log_timestamp.c', +) + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index a0341196d4..155f8b3bbe 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_syslog; + eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 12/15] log: add optional support of syslog 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 11/15] log: add timestamp option Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 13/15] log: add support for systemd journal Stephen Hemminger ` (4 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff Log to syslog only if option is specified. And if syslog is used then normally only log to syslog, don't duplicate output. Also enables syslog support on FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- app/test/test_eal_flags.c | 5 +- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------ doc/guides/prog_guide/log_lib.rst | 21 ++++- lib/eal/common/eal_common_options.c | 5 +- lib/log/log.c | 28 +++--- lib/log/log_private.h | 17 ++++ lib/log/log_syslog.c | 88 +++++++++++++++++++ lib/log/meson.build | 4 + lib/log/version.map | 2 +- 9 files changed, 151 insertions(+), 46 deletions(-) create mode 100644 lib/log/log_syslog.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 40dd288d5f..06295030b2 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -987,9 +987,10 @@ test_misc_flags(void) /* With empty --syslog */ const char *argv3[] = {prgname, prefix, mp_flag, "--syslog"}; /* With valid --syslog */ - const char *argv4[] = {prgname, prefix, mp_flag, "--syslog", "always"}; + const char *argv4[] = {prgname, prefix, mp_flag, "--syslog=both"}; /* With invalid --syslog */ - const char *argv5[] = {prgname, prefix, mp_flag, "--syslog", "error"}; + const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; + /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 504eefe1d2..6ae40f6a3a 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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 ---------- @@ -83,6 +81,23 @@ To prefix all console messages with ISO format time the syntax is:: /path/to/app --log-timestamp=iso +Log output +~~~~~~~~~~ + +If desired, messages can be redirected to syslog (on Linux and FreeBSD) with the ``--syslog`` +option. There are three possible settings for this option: + +*always* + Redirect all log output to syslog. + +*auto* + Use console if it is a terminal, and use syslog if is not. + +*both* + Print to both console and syslog. + +If ``--syslog`` option is not specified, then only console (stderr) will be used. + Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ec3b5c3dfd..ac1aadbef4 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -2215,6 +2215,9 @@ eal_common_usage(void) " (can be used multiple times)\n" " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" +#ifndef RTE_EXEC_ENV_WINDOWS + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" " Set specific log level\n" diff --git a/lib/log/log.c b/lib/log/log.c index 6ab856272c..f748551bc0 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -12,18 +12,19 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> -#include "log_internal.h" -#include "log_private.h" - #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif +#include "log_internal.h" +#include "log_private.h" + struct rte_log_dynamic_type { const char *name; uint32_t loglevel; @@ -496,20 +497,23 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) return ret; } -/* Placeholder */ -int -eal_log_syslog(const char *mode __rte_unused) -{ - return -1; -} - /* * Called by rte_eal_init */ void -eal_log_init(const char *id __rte_unused) +eal_log_init(const char *id) { - if (log_timestamp_enabled()) + bool is_terminal; + +#ifdef RTE_EXEC_ENV_WINDOWS + is_terminal = _isatty(_fileno(stderr)); +#else + is_terminal = isatty(STDERR_FILENO); +#endif + + if (log_syslog_enabled(is_terminal)) + log_syslog_open(id, is_terminal); + else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else rte_logs.print_func = vfprintf; diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 67cfe72fc6..532a481340 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -17,4 +17,21 @@ 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); +#ifdef RTE_EXEC_ENV_WINDOWS +static inline bool +log_syslog_enabled(bool is_tty __rte_unused) +{ + return false; +} + +static inline void +log_syslog_open(const char *id __rte_unused, bool is_terminal __rte_unused) +{ +} +#else + +bool log_syslog_enabled(bool is_tty); +void log_syslog_open(const char *id, bool is_terminal); +#endif + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..fb69921e05 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static enum { + LOG_SYSLOG_NONE = 0, /* do not use syslog */ + LOG_SYSLOG_AUTO, /* use syslog only if not a terminal */ + LOG_SYSLOG_ALWAYS, /* always use syslog */ + LOG_SYSLOG_BOTH, /* log to both syslog and stderr */ +} log_syslog_opt; + +int +eal_log_syslog(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_syslog_opt = LOG_SYSLOG_AUTO; + else if (strcmp(str, "both") == 0) + log_syslog_opt = LOG_SYSLOG_BOTH; + else if (strcmp(str, "always") == 0) + log_syslog_opt = LOG_SYSLOG_ALWAYS; + else + return -1; + return 0; +} + +bool +log_syslog_enabled(bool is_terminal) +{ + switch (log_syslog_opt) { + default: + return false; + + case LOG_SYSLOG_ALWAYS: + case LOG_SYSLOG_BOTH: + return true; + + case LOG_SYSLOG_AUTO: + return !is_terminal; + } +} + +/* + * When syslog is used, the log stream is redirected to a + * pseudo FILE handle that calls these functions. + */ +static ssize_t +syslog_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + return size; +} + +static int +syslog_log_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t syslog_log_func = { + .write = syslog_log_write, + .close = syslog_log_close, +}; + +void +log_syslog_open(const char *id, bool is_terminal) +{ + int flags = LOG_NDELAY | LOG_PID; + + if (log_syslog_opt == LOG_SYSLOG_BOTH) + flags |= LOG_PERROR; + + openlog(id, flags, is_terminal ? LOG_USER : LOG_DAEMON); + + /* redirect other log messages to syslog as well */ + FILE *log_stream = fopencookie(NULL, "w", syslog_log_func); + if (log_stream != NULL) + rte_openlog_stream(log_stream); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 04235f6ee5..4ac232786e 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -7,4 +7,8 @@ sources = files( 'log_timestamp.c', ) +if not is_windows + sources += files('log_syslog.c') +endif + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 155f8b3bbe..8be6907840 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,7 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_syslog; + eal_log_syslog; # WINDOWS_NO_EXPORT eal_log_timestamp; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 13/15] log: add support for systemd journal 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 12/15] log: add optional support of syslog Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 14/15] log: colorize log output Stephen Hemminger ` (3 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Tyler Retzlaff 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- doc/guides/prog_guide/log_lib.rst | 14 ++ lib/eal/common/eal_common_options.c | 15 +++ lib/eal/common/eal_options.h | 2 + lib/log/log.c | 4 +- lib/log/log_internal.h | 3 + lib/log/log_journal.c | 200 ++++++++++++++++++++++++++++ lib/log/log_private.h | 16 +++ lib/log/meson.build | 4 + lib/log/version.map | 1 + 9 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 lib/log/log_journal.c diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 6ae40f6a3a..925bc70ede 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -98,6 +98,20 @@ option. There are three possible settings for this option: If ``--syslog`` option is not specified, then only console (stderr) will be used. +Messages can be redirected to systemd journal which is an enhanced version of syslog with the ``--log-journal`` option. + +There are three possible settings for this option: + +*auto* + If stderr is redirected to journal by ``systemd`` service + then use journal socket to instead of stderr for log. + This is the default. + +*never* + Do not try to use journal. + +*always* + Always try to direct messages to journal socket. Using Logging APIs to Generate Log Messages diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ac1aadbef4..6184d27ad3 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_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 }, @@ -1617,6 +1618,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: case OPT_SYSLOG_NUM: + case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; @@ -1840,6 +1842,16 @@ eal_parse_common_option(int opt, const char *optarg, break; #endif +#ifdef RTE_EXEC_ENV_LINUX + case OPT_LOG_JOURNAL_NUM: + if (eal_log_journal(optarg) < 0) { + EAL_LOG(ERR, "invalid parameters for --" + OPT_LOG_JOURNAL); + return -1; + } + break; +#endif + case OPT_LOG_LEVEL_NUM: if (eal_parse_log_level(optarg) < 0) { EAL_LOG(ERR, @@ -2217,6 +2229,9 @@ eal_common_usage(void) " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" +#endif +#ifdef RTE_EXEC_ENV_LINUX + " --"OPT_LOG_JOURNAL"[=<when>] Enable use of systemd journal\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..c5a1c70288 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -35,6 +35,8 @@ enum { OPT_LCORES_NUM, #define OPT_LOG_LEVEL "log-level" OPT_LOG_LEVEL_NUM, +#define OPT_LOG_JOURNAL "log-journal" + OPT_LOG_JOURNAL_NUM, #define OPT_LOG_TIMESTAMP "log-timestamp" OPT_LOG_TIMESTAMP_NUM, #define OPT_TRACE "trace" diff --git a/lib/log/log.c b/lib/log/log.c index f748551bc0..96fa651e81 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -511,7 +511,9 @@ eal_log_init(const char *id) is_terminal = isatty(STDERR_FILENO); #endif - if (log_syslog_enabled(is_terminal)) + if (log_journal_enabled()) + log_journal_open(id); + else if (log_syslog_enabled(is_terminal)) log_syslog_open(id, is_terminal); else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..2475174fce --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,200 @@ +/* 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" + +static enum { + LOG_JOURNAL_NEVER = 0, /* do not use journal */ + LOG_JOURNAL_AUTO, /* use if stderr is set to journal */ + LOG_JOURNAL_ALWAYS, /* always try to use journal */ +} log_journal_opt = LOG_JOURNAL_AUTO; + +static int log_journal_fd = -1; + +int +eal_log_journal(const char *str) +{ + if (str == NULL || strcmp(str, "auto") == 0) + log_journal_opt = LOG_JOURNAL_AUTO; + else if (strcmp(str, "always") == 0) + log_journal_opt = LOG_JOURNAL_ALWAYS; + else if (strcmp(str, "never") == 0) + log_journal_opt = LOG_JOURNAL_NEVER; + else + return -1; + return 0; +} + +/* + * send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +static int +journal_send(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[16]; /* "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(log_journal_fd, iov, n); +} + + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(__rte_unused void *c, const char *buf, size_t size) +{ + return journal_send(buf, size); +} + +static int +journal_log_close(__rte_unused void *c) +{ + close(log_journal_fd); + log_journal_fd = -1; + 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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + */ +static bool +is_journal(int fd) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(fd, &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 */ +static int +open_journal(void) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int s; + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return -1; + } + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + perror("connect"); + close(s); + return -1; + } + + return s; +} + +bool log_journal_enabled(void) +{ + if (log_journal_opt == LOG_JOURNAL_NEVER) + return false; + + if (log_journal_opt == LOG_JOURNAL_AUTO && + !is_journal(STDERR_FILENO)) + return false; + + log_journal_fd = open_journal(); + if (log_journal_fd < 0) + return false; + + return true; +} + +void log_journal_open(const char *id) +{ + FILE *log_stream; + char *syslog_id = NULL; + ssize_t len; + + /* Send identifier as first message */ + len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", + id, getpid()); + if (len == 0) + goto error; + + if (write(log_journal_fd, syslog_id, len) != len) { + perror("write"); + goto error; + } + + free(syslog_id); + + /* redirect other log messages to journal */ + log_stream = fopencookie(NULL, "w", journal_log_func); + if (log_stream != NULL) { + rte_openlog_stream(log_stream); + return; + } + +error: + free(syslog_id); + close(log_journal_fd); + log_journal_fd = -1; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 532a481340..d8602681b2 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -34,4 +34,20 @@ bool log_syslog_enabled(bool is_tty); void log_syslog_open(const char *id, bool is_terminal); #endif +#ifdef RTE_EXEC_ENV_LINUX +bool log_journal_enabled(void); +void log_journal_open(const char *id); +#else +static inline bool +log_journal_enabled(void) +{ + return false; +} + +static inline void +log_journal_open(const char *id __rte_unused) +{ +} +#endif /* !RTE_EXEC_ENV_LINUX */ + #endif /* LOG_PRIVATE_H */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 4ac232786e..86e4452b19 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 8be6907840..800d3943bc 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 14/15] log: colorize log output 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (12 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 13/15] log: add support for systemd journal Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 15/15] doc: add release note about log library Stephen Hemminger ` (2 subsequent siblings) 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> log dark --- app/test/test_eal_flags.c | 24 ++++ doc/guides/prog_guide/log_lib.rst | 15 ++ lib/eal/common/eal_common_options.c | 11 ++ lib/eal/common/eal_options.h | 6 +- lib/log/log.c | 19 ++- lib/log/log_color.c | 216 ++++++++++++++++++++++++++++ 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, 298 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_color.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 06295030b2..6ee56ec97a 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 925bc70ede..b533e2d48e 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -57,6 +57,21 @@ 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. +Color output +~~~~~~~~~~~~ + +The log library will highlight important messages. +This is controlled by the ``--log-color`` option. +he optional argument ``when`` can be ``auto``, ``never``, or ``always``. +The default setting is ``auto`` which enables color when the output to +``stderr`` is a terminal. +If the ``when`` argument is omitted, it defaults to ``always``. + +For example to turn off all coloring:: + + /path/to/app --log-color=none + + Log timestamp ~~~~~~~~~~~~~ diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 6184d27ad3..de19b1c258 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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_JOURNAL, 2, NULL, OPT_LOG_JOURNAL_NUM }, {OPT_LOG_TIMESTAMP, 2, NULL, OPT_LOG_TIMESTAMP_NUM }, @@ -1620,6 +1621,7 @@ eal_log_level_parse(int argc, char * const argv[]) case OPT_SYSLOG_NUM: case OPT_LOG_JOURNAL_NUM: case OPT_LOG_TIMESTAMP_NUM: + case OPT_LOG_COLOR_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -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) { @@ -2238,6 +2248,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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index c5a1c70288..c0686c2544 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -33,10 +33,12 @@ enum { OPT_HUGE_UNLINK_NUM, #define OPT_LCORES "lcores" OPT_LCORES_NUM, -#define OPT_LOG_LEVEL "log-level" - OPT_LOG_LEVEL_NUM, +#define OPT_LOG_COLOR "log-color" + OPT_LOG_COLOR_NUM, #define OPT_LOG_JOURNAL "log-journal" OPT_LOG_JOURNAL_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" diff --git a/lib/log/log.c b/lib/log/log.c index 96fa651e81..8b7b394f49 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -511,14 +511,21 @@ eal_log_init(const char *id) is_terminal = isatty(STDERR_FILENO); #endif - if (log_journal_enabled()) + if (log_journal_enabled()) { log_journal_open(id); - else if (log_syslog_enabled(is_terminal)) + } else if (log_syslog_enabled(is_terminal)) { log_syslog_open(id, is_terminal); - else if (log_timestamp_enabled()) - rte_logs.print_func = log_print_with_timestamp; - else - rte_logs.print_func = vfprintf; + } else if (log_timestamp_enabled()) { + if (log_color_enabled(is_terminal)) + rte_logs.print_func = color_print_with_timestamp; + else + rte_logs.print_func = log_print_with_timestamp; + } else { + if (log_color_enabled(is_terminal)) + rte_logs.print_func = color_print; + else + rte_logs.print_func = vfprintf; + } #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..82a9ac8022 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode = LOG_COLOR_NEVER; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +enum log_field { + LOG_FIELD_SUBSYS, + LOG_FIELD_TIME, + LOG_FIELD_ALERT, + LOG_FIELD_ERROR, + LOG_FIELD_INFO, +}; + +static const enum color field_colors[] = { + [LOG_FIELD_SUBSYS] = COLOR_YELLOW, + [LOG_FIELD_TIME] = COLOR_GREEN, + [LOG_FIELD_ALERT] = COLOR_RED, + [LOG_FIELD_ERROR] = COLOR_BOLD, + [LOG_FIELD_INFO] = COLOR_NONE, +}; + +/* If set all colors are bolder */ +static bool dark_mode; + +/* Standard terminal escape codes for colors and bold */ +static const uint8_t color_esc_code[] = { + [COLOR_RED] = 31, + [COLOR_GREEN] = 32, + [COLOR_YELLOW] = 33, + [COLOR_BLUE] = 34, + [COLOR_MAGENTA] = 35, + [COLOR_CYAN] = 36, + [COLOR_WHITE] = 37, + [COLOR_BOLD] = 1, +}; + +__rte_format_printf(4, 5) +static int +color_snprintf(char *buf, size_t len, enum log_field field, + const char *fmt, ...) +{ + enum color color = field_colors[field]; + uint8_t esc = color_esc_code[color]; + va_list args; + int ret = 0; + + va_start(args, fmt); + if (esc == 0) { + ret = vsnprintf(buf, len, fmt, args); + } else { + ret = snprintf(buf, len, + dark_mode ? "\e[1;%um" : "\e[%um", esc); + ret += vsnprintf(buf + ret, len - ret, fmt, args); + ret += snprintf(buf + ret, len - ret, "%s", "\e[0m"); + } + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + char *env, *sep; + + /* Set dark mode using the defacto heuristics used by other programs */ + env = getenv("COLORFGBG"); + if (env) { + sep = strrchr(env, ';'); + if (sep && + ((sep[1] >= '0' && sep[1] <= '6') || sep[1] == '8') && + sep[2] == '\0') + dark_mode = true; + } + + switch (log_color_mode) { + case LOG_COLOR_ALWAYS: + return true; + case LOG_COLOR_AUTO: + return is_terminal; + default: + return false; + + } +} + +/* Look ast the current message level to determine color of field */ +static enum log_field +color_msg_field(void) +{ + const int level = rte_log_cur_msg_loglevel(); + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + return LOG_FIELD_INFO; + else if (level >= (int)RTE_LOG_ERR) + return LOG_FIELD_ERROR; + else + return LOG_FIELD_ALERT; +} + +__rte_format_printf(3, 0) +static int +color_fmt_msg(char *out, size_t len, const char *format, va_list ap) +{ + enum log_field field = color_msg_field(); + char buf[LINE_MAX]; + int ret = 0; + + /* format raw message */ + vsnprintf(buf, sizeof(buf), format, ap); + const char *msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + const char *cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_snprintf(out, len, LOG_FIELD_SUBSYS, + "%.*s", (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + ret += color_snprintf(out + ret, len - ret, field, "%s", msg); + return ret; +} + +__rte_format_printf(2, 0) +int +color_print(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + + /* format raw message */ + int ret = color_fmt_msg(out, sizeof(out), format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} + +__rte_format_printf(2, 0) +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + char tsbuf[128]; + int ret = 0; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + ret = color_snprintf(out, sizeof(out), + LOG_FIELD_TIME, "[%s] ", tsbuf); + + ret += color_fmt_msg(out + ret, sizeof(out) - ret, format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 82fdc21ac2..bba7041ea3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index d8602681b2..855e32db90 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -50,4 +50,12 @@ log_journal_open(const char *id __rte_unused) } #endif /* !RTE_EXEC_ENV_LINUX */ +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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 86e4452b19..b3de57b9c7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 800d3943bc..09d8a4289b 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_25 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; # WINDOWS_NO_EXPORT eal_log_level2str; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v26 15/15] doc: add release note about log library 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (13 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 14/15] log: colorize log output Stephen Hemminger @ 2024-10-16 20:20 ` Stephen Hemminger 2024-10-18 17:07 ` [PATCH v26 00/15] Log subsystem improvements David Marchand 2024-10-20 7:16 ` Baruch Even 16 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-16 20:20 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng Significant enough to add some documentation. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- doc/guides/rel_notes/release_24_11.rst | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst index acc512c70a..5c8a0af1d0 100644 --- a/doc/guides/rel_notes/release_24_11.rst +++ b/doc/guides/rel_notes/release_24_11.rst @@ -276,6 +276,32 @@ 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 related changes + + * The meaning of the *--syslog* option has changed. + Use of syslog is controlled by the *--syslog* option. + The default is now *auto* which uses syslog only if stderr + is not a terminal device. + + * The syslog facility is now set to **LOG_USER** if stderr is a terminal + and **LOG_DAEMON** otherwise. + + * Syslog 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 optionally marked with colors. + + ABI Changes ----------- -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v26 00/15] Log subsystem improvements 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (14 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 15/15] doc: add release note about log library Stephen Hemminger @ 2024-10-18 17:07 ` David Marchand 2024-10-18 17:45 ` Stephen Hemminger 2024-10-20 7:16 ` Baruch Even 16 siblings, 1 reply; 445+ messages in thread From: David Marchand @ 2024-10-18 17:07 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev Hello Stephen, On Wed, Oct 16, 2024 at 10:24 PM Stephen Hemminger <stephen@networkplumber.org> wrote: > > 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 > syslog if output is going to a terminal. > > Add myself as maintainer for log because by now have added > more than previous authors. Thanks for the series. Overall, it looks good, but I am too short on time for merging in rc1 and I have some comments. I'll consider merging it in rc2. - The main point is the "automatic" aspect but we want to provide some way to force where the logs end up. With this series, the user has --syslog (whose meaning is changed) and --log-journal options to affect where the logs go. Can we get a single option? Like maybe --log-destination=console|syslog|journal|auto ? - I don't really understand why changing the --syslog is better. We lose the ability to select the syslog facility. Either this feature was useless, and I would rather deprecate or remove it explicitly (and the --syslog with it). Or we should keep it as is for compat reason. - The color and timestamping options only affect the console output, which is not clear with the --log-color / --log-timestamp names. Maybe we can enhance with some other name? - Did you test redirecting all logs to an external logging function? I suppose it still works, but it is important not to break such feature for OVS. -- David Marchand ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v26 00/15] Log subsystem improvements 2024-10-18 17:07 ` [PATCH v26 00/15] Log subsystem improvements David Marchand @ 2024-10-18 17:45 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-18 17:45 UTC (permalink / raw) To: David Marchand; +Cc: dev On Fri, 18 Oct 2024 19:07:18 +0200 David Marchand <david.marchand@redhat.com> wrote: > Hello Stephen, > > On Wed, Oct 16, 2024 at 10:24 PM Stephen Hemminger > <stephen@networkplumber.org> wrote: > > > > 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 > > syslog if output is going to a terminal. > > > > Add myself as maintainer for log because by now have added > > more than previous authors. > > Thanks for the series. > > Overall, it looks good, but I am too short on time for merging in rc1 > and I have some comments. > I'll consider merging it in rc2. > > > - The main point is the "automatic" aspect but we want to provide some > way to force where the logs end up. > With this series, the user has --syslog (whose meaning is changed) and > --log-journal options to affect where the logs go. > Can we get a single option? > Like maybe --log-destination=console|syslog|journal|auto ? That could work. The goal here is to do the right thing without options. And reduce the duplication. Right now, applications end up logging to both console and syslog. > > - I don't really understand why changing the --syslog is better. > We lose the ability to select the syslog facility. > Either this feature was useless, and I would rather deprecate or > remove it explicitly (and the --syslog with it). > Or we should keep it as is for compat reason. Syslog facility really was pretty useless. The number of facilities is too small and there never was a good reason to have it. Maybe keep old option syntax as fallback? > > - The color and timestamping options only affect the console output, > which is not clear with the --log-color / --log-timestamp names. > Maybe we can enhance with some other name? Timestamp is unneeded with syslog or journal since they do it already. It is possible to force timestamp or color when going to a file (by setting log stream). Did consider that options could be: --color and --timestamp but seemed better to keep all log related options together. > > - Did you test redirecting all logs to an external logging function? > I suppose it still works, but it is important not to break such feature for OVS. Did not have test for that, should be put in functional tests. I flip/flopped on default for color. I like the auto mode and it might make users see errors more. But concerned that things like CI which are capturing via pseudo-terminals might get color and not know what to do with it. Final version defaults to off. ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v26 00/15] Log subsystem improvements 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger ` (15 preceding siblings ...) 2024-10-18 17:07 ` [PATCH v26 00/15] Log subsystem improvements David Marchand @ 2024-10-20 7:16 ` Baruch Even 16 siblings, 0 replies; 445+ messages in thread From: Baruch Even @ 2024-10-20 7:16 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev [-- Attachment #1: Type: text/plain, Size: 6030 bytes --] Hi, I'm not sure about the proper way to do a code review here, feel free to educate me if there is a better way to do it. I couldn't find the actual patches text in the mail and patchwork has no interface to write comments on the line itself but I may very well have missed something. https://patches.dpdk.org/project/dpdk/patch/20241016202343.190653-13-stephen@networkplumber.org/ Why not provide an option to disable the syslog with --syslog=none? It will allow overriding a previous setting if one was given as well. (the same applies to the --log-journal option) https://patches.dpdk.org/project/dpdk/patch/20241016202343.190653-15-stephen@networkplumber.org/ You have both --log-color=never and --log-color=none, you probably need to make up your mind, my vote would be with none for better compatibility with the syslog/journal options I made above. But I don't care that much about it. Would also be good to document about the dark mode option so people don't need to find it only in the code. Baruch On Wed, Oct 16, 2024 at 11:24 PM Stephen Hemminger < stephen@networkplumber.org> wrote: > 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 > syslog if output is going to a terminal. > > Add myself as maintainer for log because by now have added > more than previous authors. > > v26 - rebase and change release note > - by default, do not disable color > - support dark mode with colors > - when using color format message to string then print > to avoid getting multiple threads intermixing on output. > > Stephen Hemminger (15): > maintainers: add for log library > windows: make getopt functions have const properties > windows: add os shim for localtime_r > 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: move handling of syslog facility out of eal > eal: initialize log before everything else > log: drop syslog support, and make code common > log: add hook for printing log messages > log: add timestamp option > log: add optional support of syslog > 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 | 64 ++++- > doc/guides/linux_gsg/linux_eal_parameters.rst | 27 -- > doc/guides/prog_guide/log_lib.rst | 76 +++++- > doc/guides/rel_notes/release_24_11.rst | 26 ++ > lib/eal/common/eal_common_debug.c | 6 +- > lib/eal/common/eal_common_options.c | 135 ++++++---- > lib/eal/common/eal_internal_cfg.h | 1 - > lib/eal/common/eal_options.h | 7 + > lib/eal/freebsd/eal.c | 64 +---- > lib/eal/linux/eal.c | 68 +---- > lib/eal/windows/eal.c | 49 +--- > 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 | 71 ++++-- > lib/log/log_color.c | 216 ++++++++++++++++ > lib/log/log_freebsd.c | 12 - > lib/log/log_internal.h | 28 +- > lib/log/log_journal.c | 200 +++++++++++++++ > lib/log/log_linux.c | 61 ----- > lib/log/log_private.h | 61 +++++ > lib/log/log_syslog.c | 88 +++++++ > lib/log/log_timestamp.c | 240 ++++++++++++++++++ > lib/log/log_windows.c | 18 -- > lib/log/meson.build | 12 +- > lib/log/version.map | 5 +- > 27 files changed, 1197 insertions(+), 380 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.45.2 > > -- Baruch Even Platform Technical Lead at WEKA E baruch@weka.io* *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> [-- Attachment #2: Type: text/html, Size: 10512 bytes --] ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 00/14] Log subsystem changes 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (25 preceding siblings ...) 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 01/14] maintainers: add for log library Stephen Hemminger ` (13 more replies) 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (2 subsequent siblings) 29 siblings, 14 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev; +Cc: 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. v27 - review feedback - consolidate and simplify - keep the meaning of --syslog=facility the same as before. v26 - rebase and change release note - by default, do not disable color - support dark mode with colors - when using color format message to string then print to avoid getting multiple threads intermixing on output. Stephen Hemminger (14): 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: move handling of syslog facility out of eal eal: initialize log before everything else log: add hook for printing log messages log: modify syslog handling 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 ++++- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 -- doc/guides/prog_guide/log_lib.rst | 57 +++- doc/guides/rel_notes/release_24_11.rst | 19 ++ 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 | 64 +---- 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 | 76 ++++-- lib/log/log_color.c | 216 +++++++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 28 +- lib/log/log_journal.c | 154 +++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 36 +++ lib/log/log_syslog.c | 106 ++++++++ lib/log/log_timestamp.c | 245 ++++++++++++++++++ lib/log/log_windows.c | 18 -- lib/log/meson.build | 12 +- lib/log/version.map | 5 +- 27 files changed, 1114 insertions(+), 382 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.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 01/14] maintainers: add for log library 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 02/14] windows: make getopt functions have const properties Stephen Hemminger ` (12 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Chengwen Feng, Bruce Richardson, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index cd78bc7db1..a504b8fc54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -186,6 +186,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 02/14] windows: make getopt functions have const properties 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 01/14] maintainers: add for log library Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 03/14] windows: update os shim Stephen Hemminger ` (11 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 03/14] windows: update os shim 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 01/14] maintainers: add for log library Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 02/14] windows: make getopt functions have const properties Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 04/14] eal: make eal_log_level_parse common Stephen Hemminger ` (10 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ lib/log/log.c | 7 +++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..665c9ac93b 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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_ */ diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..7416c82b34 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 04/14] eal: make eal_log_level_parse common 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (2 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 03/14] windows: update os shim Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 05/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (9 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Dmitry Kozlyuk The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index f1a5e329a5..eb079a65a9 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 1229230063..d3b40e81d8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 54577b7718..40d750ed0d 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 28b78a95a6..a77e590a72 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 05/14] eal: do not duplicate rte_init_alert() messages 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (3 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 04/14] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 06/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (8 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3b40e81d8..7b974608e4 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 40d750ed0d..c53a051405 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); } /* diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index a77e590a72..93f099a968 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 06/14] eal: change rte_exit() output to match rte_log() 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (4 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 05/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 07/14] log: move handling of syslog facility out of eal Stephen Hemminger ` (7 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..bcfcd6df6f 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 07/14] log: move handling of syslog facility out of eal 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (5 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 06/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 08/14] eal: initialize log before everything else Stephen Hemminger ` (6 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff, Dmitry Kozlyuk The syslog facility property is better handled in lib/log rather than in eal. This also add syslog support to FreeBSD. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_options.c | 53 ++-------------- lib/eal/common/eal_internal_cfg.h | 1 - lib/eal/freebsd/eal.c | 5 +- lib/eal/linux/eal.c | 7 +-- lib/eal/windows/eal.c | 6 +- lib/log/log.c | 2 + lib/log/log_freebsd.c | 2 +- lib/log/log_internal.h | 5 +- lib/log/log_linux.c | 61 ------------------ lib/log/log_syslog.c | 98 +++++++++++++++++++++++++++++ lib/log/log_windows.c | 8 ++- lib/log/meson.build | 6 +- lib/log/version.map | 1 + 13 files changed, 130 insertions(+), 125 deletions(-) delete mode 100644 lib/log/log_linux.c create mode 100644 lib/log/log_syslog.c diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index eb079a65a9..71c672e93e 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -93,7 +90,9 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, +#ifndef RTE_EXEC_ENV_WINDOWS {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, +#endif {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -349,10 +348,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1292,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1617,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1877,7 +1832,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa..f53ab8b4aa 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -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 */ diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7b974608e4..a609d40ee0 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index c53a051405..9a0a1cf211 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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,8 +1103,7 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name, - internal_conf->syslog_facility) < 0) { + if (eal_log_init(program_invocation_short_name) < 0) { rte_eal_init_alert("Cannot init logging."); rte_errno = ENOMEM; rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 93f099a968..cd8420a82c 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 7416c82b34..d41ca2ed31 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,6 +13,7 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> #ifdef RTE_EXEC_ENV_WINDOWS diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 698d3c5423..953e371bee 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -6,7 +6,7 @@ #include "log_internal.h" int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..cb15cdff08 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id, int facility); +int eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. @@ -30,6 +30,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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 2dfb0c974b..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_log.h> - -#include "log_internal.h" - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -int -eal_log_init(const char *id, int facility) -{ - FILE *log_stream; - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - - openlog(id, LOG_NDELAY | LOG_PID, facility); - - eal_log_set_default(log_stream); - - return 0; -} diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..c1f25d2686 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" + +static int log_facility = LOG_DAEMON; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + +/* + * default log function + */ +static ssize_t +log_syslog_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + + return size; +} + +static int +log_syslog_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t log_syslog_func = { + .write = log_syslog_write, + .close = log_syslog_close, +}; + +/* + * set the log to default function, called during eal init process, + * once memzones are available. + */ +int +eal_log_init(const char *id) +{ + FILE *log_stream; + + log_stream = fopencookie(NULL, "w+", log_syslog_func); + if (log_stream == NULL) + return -1; + + openlog(id, LOG_NDELAY | LOG_PID | LOG_PERROR, log_facility); + + eal_log_set_default(log_stream); + + return 0; +} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a6a0889550..a3a756351d 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -6,9 +6,15 @@ #include <rte_log.h> #include "log_internal.h" +int +eal_log_syslog(const char *name __rte_unused) +{ + return -1; /* not used */ +} + /* set the log to default function, called during eal init process. */ int -eal_log_init(__rte_unused const char *id, __rte_unused int facility) +eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..160cf34f50 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 19d7f9cdb6..879567ba15 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -30,5 +30,6 @@ INTERNAL { eal_log_save_pattern; eal_log_save_regexp; eal_log_set_default; + eal_log_syslog; rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 08/14] eal: initialize log before everything else 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (6 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 07/14] log: move handling of syslog facility out of eal Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 09/14] log: add hook for printing log messages Stephen Hemminger ` (5 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/freebsd/eal.c | 12 +++++++++--- lib/eal/linux/eal.c | 19 +++++++++---------- lib/eal/windows/eal.c | 8 ++++++-- lib/log/log_freebsd.c | 3 +-- lib/log/log_internal.h | 2 +- lib/log/log_syslog.c | 14 ++++++-------- lib/log/log_windows.c | 4 +--- 7 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a609d40ee0..118c1f593b 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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,14 @@ 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 +581,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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 9a0a1cf211..62d3d281c4 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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,13 +1109,6 @@ rte_eal_init(int argc, char **argv) #endif } - if (eal_log_init(program_invocation_short_name) < 0) { - rte_eal_init_alert("Cannot init logging."); - rte_errno = ENOMEM; - rte_atomic_store_explicit(&run_once, 0, rte_memory_order_relaxed); - return -1; - } - #ifdef VFIO_PRESENT if (rte_vfio_enable("vfio")) { rte_eal_init_alert("Cannot init VFIO"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index cd8420a82c..33f044d7cc 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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."); diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c index 953e371bee..33a0925c43 100644 --- a/lib/log/log_freebsd.c +++ b/lib/log/log_freebsd.c @@ -5,8 +5,7 @@ #include <rte_common.h> #include "log_internal.h" -int +void eal_log_init(__rte_unused const char *id) { - return 0; } diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index cb15cdff08..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -14,7 +14,7 @@ * Initialize the default log stream. */ __rte_internal -int eal_log_init(const char *id); +void eal_log_init(const char *id); /* * Determine where log data is written when no call to rte_openlog_stream. diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c index c1f25d2686..ce34fa4f22 100644 --- a/lib/log/log_syslog.c +++ b/lib/log/log_syslog.c @@ -81,18 +81,16 @@ static cookie_io_functions_t log_syslog_func = { * set the log to default function, called during eal init process, * once memzones are available. */ -int +void eal_log_init(const char *id) { FILE *log_stream; - log_stream = fopencookie(NULL, "w+", log_syslog_func); - if (log_stream == NULL) - return -1; - openlog(id, LOG_NDELAY | LOG_PID | LOG_PERROR, log_facility); - eal_log_set_default(log_stream); - - return 0; + log_stream = fopencookie(NULL, "w+", log_syslog_func); + if (log_stream != NULL) + eal_log_set_default(log_stream); + else + eal_log_set_default(stderr); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c index a3a756351d..d7c30e4cfa 100644 --- a/lib/log/log_windows.c +++ b/lib/log/log_windows.c @@ -13,12 +13,10 @@ eal_log_syslog(const char *name __rte_unused) } /* set the log to default function, called during eal init process. */ -int +void eal_log_init(__rte_unused const char *id) { rte_openlog_stream(stderr); eal_log_set_default(stderr); - - return 0; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 09/14] log: add hook for printing log messages 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (7 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 08/14] eal: initialize log before everything else Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 10/14] log: modify syslog handling Stephen Hemminger ` (4 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/log/log.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index d41ca2ed31..152aa634c7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -27,16 +27,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 { @@ -78,6 +83,7 @@ int rte_openlog_stream(FILE *f) { rte_logs.file = f; + rte_logs.print_func = vfprintf; return 0; } @@ -484,7 +490,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; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 10/14] log: modify syslog handling 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (8 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 09/14] log: add hook for printing log messages Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 11/14] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Tyler Retzlaff Log to syslog only if option is specified. If no --syslog is given then use console only. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- app/test/test_eal_flags.c | 16 +++---- doc/guides/linux_gsg/linux_eal_parameters.rst | 27 ------------ doc/guides/prog_guide/log_lib.rst | 5 +-- lib/eal/common/eal_common_options.c | 4 +- lib/log/log.c | 43 +++++++++---------- lib/log/log_freebsd.c | 11 ----- lib/log/log_internal.h | 6 --- lib/log/log_private.h | 10 +++++ lib/log/log_syslog.c | 21 ++++----- lib/log/log_windows.c | 22 ---------- lib/log/version.map | 3 +- 11 files changed, 51 insertions(+), 117 deletions(-) delete mode 100644 lib/log/log_freebsd.c create mode 100644 lib/log/log_private.h delete mode 100644 lib/log/log_windows.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 71d8dba731..9fcf0d56e6 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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) { diff --git a/doc/guides/linux_gsg/linux_eal_parameters.rst b/doc/guides/linux_gsg/linux_eal_parameters.rst index ea8f381391..d86f94d8a8 100644 --- a/doc/guides/linux_gsg/linux_eal_parameters.rst +++ b/doc/guides/linux_gsg/linux_eal_parameters.rst @@ -108,30 +108,3 @@ Memory-related options * ``--match-allocations`` Free hugepages back to system exactly as they were originally allocated. - -Other options -~~~~~~~~~~~~~ - -* ``--syslog <syslog facility>`` - - Set syslog facility. Valid syslog facilities are:: - - auth - cron - daemon - ftp - kern - lpr - mail - news - syslog - user - uucp - local0 - local1 - local2 - local3 - local4 - local5 - local6 - local7 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..c87830ac00 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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 ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index 71c672e93e..ca7b702e03 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -91,7 +91,7 @@ eal_long_options[] = { {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, #ifndef RTE_EXEC_ENV_WINDOWS - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, #endif {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, @@ -2209,7 +2209,7 @@ eal_common_usage(void) " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/log/log.c b/lib/log/log.c index 152aa634c7..b863a0b6bc 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -12,15 +12,18 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> #include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> + #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif #include "log_internal.h" +#include "log_private.h" struct rte_log_dynamic_type { const char *name; @@ -61,9 +64,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -76,8 +76,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -92,17 +90,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -513,12 +501,18 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) } /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id) { - default_log_stream = default_log; +#ifndef RTE_EXEC_ENV_WINDOWS + FILE *logf; + + logf = log_syslog_open(id); + if (logf) + rte_openlog_stream(logf); +#endif #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -532,8 +526,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 33a0925c43..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2023 Intel Corporation - */ - -#include <rte_common.h> -#include "log_internal.h" - -void -eal_log_init(__rte_unused const char *id) -{ -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -16,12 +16,6 @@ __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. */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..43e7ff7b01 --- /dev/null +++ b/lib/log/log_private.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef LOG_PRIVATE_H +#define LOG_PRIVATE_H + +#ifndef RTE_EXEC_ENV_WINDOWS +FILE *log_syslog_open(const char *id); +#endif + +#endif /* LOG_PRIVATE_H */ diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c index ce34fa4f22..4a05835068 100644 --- a/lib/log/log_syslog.c +++ b/lib/log/log_syslog.c @@ -5,12 +5,16 @@ #include <stdio.h> #include <string.h> #include <sys/types.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> #include <syslog.h> #include <rte_common.h> #include <rte_log.h> #include "log_internal.h" +#include "log_private.h" static int log_facility = LOG_DAEMON; @@ -77,20 +81,11 @@ static cookie_io_functions_t log_syslog_func = { .close = log_syslog_close, }; -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -void -eal_log_init(const char *id) +FILE * +log_syslog_open(const char *id) { - FILE *log_stream; - openlog(id, LOG_NDELAY | LOG_PID | LOG_PERROR, log_facility); - log_stream = fopencookie(NULL, "w+", log_syslog_func); - if (log_stream != NULL) - eal_log_set_default(log_stream); - else - eal_log_set_default(stderr); + /* redirect other log messages to syslog as well */ + return fopencookie(NULL, "w", log_syslog_func); } diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index d7c30e4cfa..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -1,22 +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" - -int -eal_log_syslog(const char *name __rte_unused) -{ - return -1; /* not used */ -} - -/* set the log to default function, called during eal init process. */ -void -eal_log_init(__rte_unused const char *id) -{ - rte_openlog_stream(stderr); - - eal_log_set_default(stderr); -} diff --git a/lib/log/version.map b/lib/log/version.map index 879567ba15..1637fba3b9 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -29,7 +29,6 @@ INTERNAL { eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; - eal_log_set_default; - eal_log_syslog; + eal_log_syslog; # WINDOWS_NO_EXPORT rte_eal_log_cleanup; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 11/14] log: add timestamp option 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (9 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 10/14] log: modify syslog handling Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 12/14] log: add support for systemd journal Stephen Hemminger ` (2 subsequent siblings) 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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 | 245 ++++++++++++++++++++++++++++ lib/log/meson.build | 1 + lib/log/version.map | 1 + 13 files changed, 346 insertions(+), 7 deletions(-) create mode 100644 lib/log/log_timestamp.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 9fcf0d56e6..e24630edde 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index c87830ac00..82d3b7be2b 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ca7b702e03..a70d63479a 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 118c1f593b..06bccbd026 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 62d3d281c4..cf2f0fcab9 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 33f044d7cc..b1c59945fb 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index b863a0b6bc..5455687e79 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -514,6 +514,11 @@ eal_log_init(const char *id) rte_openlog_stream(logf); #endif + 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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..7c7d44eed2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 43e7ff7b01..53d05f8ac8 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -7,4 +7,10 @@ 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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..8537e32b42 --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,245 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> +#include <rte_stdatomic.h> +#include <rte_time.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +/* Defined in limits.h on Linux */ +#ifndef LINE_MAX +#define LINE_MAX 2048 /* _POSIX2_LINE_MAX */ +#endif + +#ifndef NS_PER_SEC +#define NS_PER_SEC 1E9 +#endif + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + RTE_ATOMIC(uint64_t) last_monotonic; + RTE_ATOMIC(uint64_t) last_realtime; +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Format a timestamp which shows time between messages. + */ +static ssize_t +format_delta(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct timespec delta; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + previous = rte_atomic_exchange_explicit(&log_time.last_monotonic, + ns, rte_memory_order_seq_cst); + delta = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, *last_tm, tbuf1, tbuf2; + time_t last_sec; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + tm = localtime_r(&now->tv_sec, &tbuf1); + + previous = rte_atomic_exchange_explicit(&log_time.last_realtime, + ns, rte_memory_order_seq_cst); + last_sec = previous / NS_PER_SEC; + last_tm = localtime_r(&last_sec, &tbuf2); + if (tm->tm_min == last_tm->tm_min && + tm->tm_hour == last_tm->tm_hour && + tm->tm_yday == last_tm->tm_yday) { + struct timespec elapsed; + + elapsed = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)elapsed.tv_sec, + (unsigned long)elapsed.tv_nsec / 1000u); + } else { + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + return format_delta(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + log_time.started = now; + rte_atomic_store_explicit(&log_time.last_monotonic, rte_timespec_to_ns(&now), + rte_memory_order_seq_cst); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 160cf34f50..4ac232786e 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_timestamp.c', ) if not is_windows diff --git a/lib/log/version.map b/lib/log/version.map index 1637fba3b9..8be6907840 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 12/14] log: add support for systemd journal 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (10 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 11/14] log: add timestamp option Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 13/14] log: colorize log output Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 14/14] doc: add release note about log library Stephen Hemminger 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/log/log.c | 13 ++-- lib/log/log_internal.h | 3 + lib/log/log_journal.c | 154 +++++++++++++++++++++++++++++++++++++++++ lib/log/log_private.h | 14 +++- lib/log/log_syslog.c | 17 ++++- lib/log/meson.build | 4 ++ lib/log/version.map | 1 + 7 files changed, 198 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_journal.c diff --git a/lib/log/log.c b/lib/log/log.c index 5455687e79..343f9d77b7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -506,15 +506,16 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) void eal_log_init(const char *id) { -#ifndef RTE_EXEC_ENV_WINDOWS - FILE *logf; + FILE *logf = NULL; + + if (log_journal_enabled()) + logf = log_journal_open(id); + else if (log_syslog_enabled()) + logf = log_syslog_open(id); - logf = log_syslog_open(id); if (logf) rte_openlog_stream(logf); -#endif - - if (log_timestamp_enabled()) + else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else rte_logs.print_func = vfprintf; diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..43341aa233 --- /dev/null +++ b/lib/log/log_journal.c @@ -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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + * Uses writev() to ensure that whole log message is in one datagram + */ +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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +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()); + + /* 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); + if (log_stream != NULL) + return log_stream; + +error: + close(jfd); + return NULL; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 53d05f8ac8..625f57c0cc 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -3,10 +3,22 @@ #ifndef LOG_PRIVATE_H #define LOG_PRIVATE_H -#ifndef RTE_EXEC_ENV_WINDOWS +#ifdef RTE_EXEC_ENV_WINDOWS +#define log_syslog_enabled() (false) +#define log_syslog_open(id) (NULL) +#else +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 +#define log_journal_enabled() (false) +#define log_journal_open(id) (NULL) +#endif /* !RTE_EXEC_ENV_LINUX */ + bool log_timestamp_enabled(void); ssize_t log_timestamp(char *tsbuf, size_t tsbuflen); diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c index 4a05835068..d911deff44 100644 --- a/lib/log/log_syslog.c +++ b/lib/log/log_syslog.c @@ -16,8 +16,12 @@ #include "log_internal.h" #include "log_private.h" -static int log_facility = LOG_DAEMON; +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; @@ -57,6 +66,12 @@ eal_log_syslog(const char *name) return -1; } +/* syslog is enabled if facility is set */ +bool log_syslog_enabled(void) +{ + return log_facility != 0; /* LOG_KERN is 0 */ +} + /* * default log function */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 4ac232786e..86e4452b19 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 8be6907840..800d3943bc 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 13/14] log: colorize log output 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (11 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 12/14] log: add support for systemd journal Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 2024-10-25 15:49 ` Baruch Even 2024-10-24 3:18 ` [PATCH v27 14/14] doc: add release note about log library Stephen Hemminger 13 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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 | 216 ++++++++++++++++++++++++++++ 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, 308 insertions(+), 4 deletions(-) create mode 100644 lib/log/log_color.c diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e24630edde..cd73711da6 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 82d3b7be2b..a4f880037b 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index a70d63479a..6965666a7c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..87c3c32f86 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/log/log.c b/lib/log/log.c index 343f9d77b7..f1bd408bee 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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, diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..82a9ac8022 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode = LOG_COLOR_NEVER; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +enum log_field { + LOG_FIELD_SUBSYS, + LOG_FIELD_TIME, + LOG_FIELD_ALERT, + LOG_FIELD_ERROR, + LOG_FIELD_INFO, +}; + +static const enum color field_colors[] = { + [LOG_FIELD_SUBSYS] = COLOR_YELLOW, + [LOG_FIELD_TIME] = COLOR_GREEN, + [LOG_FIELD_ALERT] = COLOR_RED, + [LOG_FIELD_ERROR] = COLOR_BOLD, + [LOG_FIELD_INFO] = COLOR_NONE, +}; + +/* If set all colors are bolder */ +static bool dark_mode; + +/* Standard terminal escape codes for colors and bold */ +static const uint8_t color_esc_code[] = { + [COLOR_RED] = 31, + [COLOR_GREEN] = 32, + [COLOR_YELLOW] = 33, + [COLOR_BLUE] = 34, + [COLOR_MAGENTA] = 35, + [COLOR_CYAN] = 36, + [COLOR_WHITE] = 37, + [COLOR_BOLD] = 1, +}; + +__rte_format_printf(4, 5) +static int +color_snprintf(char *buf, size_t len, enum log_field field, + const char *fmt, ...) +{ + enum color color = field_colors[field]; + uint8_t esc = color_esc_code[color]; + va_list args; + int ret = 0; + + va_start(args, fmt); + if (esc == 0) { + ret = vsnprintf(buf, len, fmt, args); + } else { + ret = snprintf(buf, len, + dark_mode ? "\e[1;%um" : "\e[%um", esc); + ret += vsnprintf(buf + ret, len - ret, fmt, args); + ret += snprintf(buf + ret, len - ret, "%s", "\e[0m"); + } + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + char *env, *sep; + + /* Set dark mode using the defacto heuristics used by other programs */ + env = getenv("COLORFGBG"); + if (env) { + sep = strrchr(env, ';'); + if (sep && + ((sep[1] >= '0' && sep[1] <= '6') || sep[1] == '8') && + sep[2] == '\0') + dark_mode = true; + } + + switch (log_color_mode) { + case LOG_COLOR_ALWAYS: + return true; + case LOG_COLOR_AUTO: + return is_terminal; + default: + return false; + + } +} + +/* Look ast the current message level to determine color of field */ +static enum log_field +color_msg_field(void) +{ + const int level = rte_log_cur_msg_loglevel(); + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + return LOG_FIELD_INFO; + else if (level >= (int)RTE_LOG_ERR) + return LOG_FIELD_ERROR; + else + return LOG_FIELD_ALERT; +} + +__rte_format_printf(3, 0) +static int +color_fmt_msg(char *out, size_t len, const char *format, va_list ap) +{ + enum log_field field = color_msg_field(); + char buf[LINE_MAX]; + int ret = 0; + + /* format raw message */ + vsnprintf(buf, sizeof(buf), format, ap); + const char *msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + const char *cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_snprintf(out, len, LOG_FIELD_SUBSYS, + "%.*s", (int)(cp - msg + 1), msg); + msg = cp + 1; + } + + ret += color_snprintf(out + ret, len - ret, field, "%s", msg); + return ret; +} + +__rte_format_printf(2, 0) +int +color_print(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + + /* format raw message */ + int ret = color_fmt_msg(out, sizeof(out), format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} + +__rte_format_printf(2, 0) +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + char tsbuf[128]; + int ret = 0; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + ret = color_snprintf(out, sizeof(out), + LOG_FIELD_TIME, "[%s] ", tsbuf); + + ret += color_fmt_msg(out + ret, sizeof(out) - ret, format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 82fdc21ac2..bba7041ea3 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 625f57c0cc..42babbcac1 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -25,4 +25,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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 86e4452b19..b3de57b9c7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 800d3943bc..09d8a4289b 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_25 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; # WINDOWS_NO_EXPORT eal_log_level2str; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v27 13/14] log: colorize log output 2024-10-24 3:18 ` [PATCH v27 13/14] log: colorize log output Stephen Hemminger @ 2024-10-25 15:49 ` Baruch Even 0 siblings, 0 replies; 445+ messages in thread From: Baruch Even @ 2024-10-25 15:49 UTC (permalink / raw) To: Stephen Hemminger Cc: dev, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff [-- Attachment #1: Type: text/plain, Size: 16983 bytes --] The code has some mentions of `--log-color=none` but only the `never` option is parsed. On Thu, Oct 24, 2024 at 6:22 AM Stephen Hemminger < stephen@networkplumber.org> wrote: > 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. > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > Acked-by: Bruce Richardson <bruce.richardson@intel.com> > Acked-by: Chengwen Feng <fengchengwen@huawei.com> > --- > 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 | 216 ++++++++++++++++++++++++++++ > 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, 308 insertions(+), 4 deletions(-) > create mode 100644 lib/log/log_color.c > > diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c > index e24630edde..cd73711da6 100644 > --- a/app/test/test_eal_flags.c > +++ b/app/test/test_eal_flags.c > @@ -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); > diff --git a/doc/guides/prog_guide/log_lib.rst > b/doc/guides/prog_guide/log_lib.rst > index 82d3b7be2b..a4f880037b 100644 > --- a/doc/guides/prog_guide/log_lib.rst > +++ b/doc/guides/prog_guide/log_lib.rst > @@ -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. > diff --git a/lib/eal/common/eal_common_options.c > b/lib/eal/common/eal_common_options.c > index a70d63479a..6965666a7c 100644 > --- a/lib/eal/common/eal_common_options.c > +++ b/lib/eal/common/eal_common_options.c > @@ -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" > diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h > index e24c9eca53..87c3c32f86 100644 > --- a/lib/eal/common/eal_options.h > +++ b/lib/eal/common/eal_options.h > @@ -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" > diff --git a/lib/log/log.c b/lib/log/log.c > index 343f9d77b7..f1bd408bee 100644 > --- a/lib/log/log.c > +++ b/lib/log/log.c > @@ -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, > diff --git a/lib/log/log_color.c b/lib/log/log_color.c > new file mode 100644 > index 0000000000..82a9ac8022 > --- /dev/null > +++ b/lib/log/log_color.c > @@ -0,0 +1,216 @@ > +/* SPDX-License-Identifier: BSD-3-Clause */ > + > +#include <limits.h> > +#include <stdbool.h> > +#include <stdio.h> > +#include <stdint.h> > +#include <stdarg.h> > +#include <stdlib.h> > +#include <string.h> > + > +#include <rte_common.h> > +#include <rte_log.h> > + > +#ifdef RTE_EXEC_ENV_WINDOWS > +#include <rte_os_shim.h> > +#endif > + > +#include "log_internal.h" > +#include "log_private.h" > + > +enum { > + LOG_COLOR_AUTO = 0, > + LOG_COLOR_NEVER, > + LOG_COLOR_ALWAYS, > +} log_color_mode = LOG_COLOR_NEVER; > + > +enum color { > + COLOR_NONE, > + COLOR_RED, > + COLOR_GREEN, > + COLOR_YELLOW, > + COLOR_BLUE, > + COLOR_MAGENTA, > + COLOR_CYAN, > + COLOR_WHITE, > + COLOR_BOLD, > + COLOR_CLEAR, > +}; > + > +enum log_field { > + LOG_FIELD_SUBSYS, > + LOG_FIELD_TIME, > + LOG_FIELD_ALERT, > + LOG_FIELD_ERROR, > + LOG_FIELD_INFO, > +}; > + > +static const enum color field_colors[] = { > + [LOG_FIELD_SUBSYS] = COLOR_YELLOW, > + [LOG_FIELD_TIME] = COLOR_GREEN, > + [LOG_FIELD_ALERT] = COLOR_RED, > + [LOG_FIELD_ERROR] = COLOR_BOLD, > + [LOG_FIELD_INFO] = COLOR_NONE, > +}; > + > +/* If set all colors are bolder */ > +static bool dark_mode; > + > +/* Standard terminal escape codes for colors and bold */ > +static const uint8_t color_esc_code[] = { > + [COLOR_RED] = 31, > + [COLOR_GREEN] = 32, > + [COLOR_YELLOW] = 33, > + [COLOR_BLUE] = 34, > + [COLOR_MAGENTA] = 35, > + [COLOR_CYAN] = 36, > + [COLOR_WHITE] = 37, > + [COLOR_BOLD] = 1, > +}; > + > +__rte_format_printf(4, 5) > +static int > +color_snprintf(char *buf, size_t len, enum log_field field, > + const char *fmt, ...) > +{ > + enum color color = field_colors[field]; > + uint8_t esc = color_esc_code[color]; > + va_list args; > + int ret = 0; > + > + va_start(args, fmt); > + if (esc == 0) { > + ret = vsnprintf(buf, len, fmt, args); > + } else { > + ret = snprintf(buf, len, > + dark_mode ? "\e[1;%um" : "\e[%um", esc); > + ret += vsnprintf(buf + ret, len - ret, fmt, args); > + ret += snprintf(buf + ret, len - ret, "%s", "\e[0m"); > + } > + va_end(args); > + > + return ret; > +} > + > +/* > + * Controls whether color is enabled: > + * modes are: > + * always - enable color output regardless > + * auto - enable if stderr is a terminal > + * never - color output is disabled. > + */ > +int > +eal_log_color(const char *mode) > +{ > + if (mode == NULL || strcmp(mode, "always") == 0) > + log_color_mode = LOG_COLOR_ALWAYS; > + else if (strcmp(mode, "never") == 0) > + log_color_mode = LOG_COLOR_NEVER; > + else if (strcmp(mode, "auto") == 0) > + log_color_mode = LOG_COLOR_AUTO; > + else > + return -1; > + > + return 0; > +} > + > +bool > +log_color_enabled(bool is_terminal) > +{ > + char *env, *sep; > + > + /* Set dark mode using the defacto heuristics used by other > programs */ > + env = getenv("COLORFGBG"); > + if (env) { > + sep = strrchr(env, ';'); > + if (sep && > + ((sep[1] >= '0' && sep[1] <= '6') || sep[1] == '8') && > + sep[2] == '\0') > + dark_mode = true; > + } > + > + switch (log_color_mode) { > + case LOG_COLOR_ALWAYS: > + return true; > + case LOG_COLOR_AUTO: > + return is_terminal; > + default: > + return false; > + > + } > +} > + > +/* Look ast the current message level to determine color of field */ > +static enum log_field > +color_msg_field(void) > +{ > + const int level = rte_log_cur_msg_loglevel(); > + > + if (level <= 0 || level >= (int)RTE_LOG_INFO) > + return LOG_FIELD_INFO; > + else if (level >= (int)RTE_LOG_ERR) > + return LOG_FIELD_ERROR; > + else > + return LOG_FIELD_ALERT; > +} > + > +__rte_format_printf(3, 0) > +static int > +color_fmt_msg(char *out, size_t len, const char *format, va_list ap) > +{ > + enum log_field field = color_msg_field(); > + char buf[LINE_MAX]; > + int ret = 0; > + > + /* format raw message */ > + vsnprintf(buf, sizeof(buf), format, ap); > + const char *msg = buf; > + > + /* > + * use convention that first part of message (up to the ':' > character) > + * is the subsystem id and should be highlighted. > + */ > + const char *cp = strchr(msg, ':'); > + if (cp) { > + /* print first part in yellow */ > + ret = color_snprintf(out, len, LOG_FIELD_SUBSYS, > + "%.*s", (int)(cp - msg + 1), msg); > + msg = cp + 1; > + } > + > + ret += color_snprintf(out + ret, len - ret, field, "%s", msg); > + return ret; > +} > + > +__rte_format_printf(2, 0) > +int > +color_print(FILE *f, const char *format, va_list ap) > +{ > + char out[LINE_MAX]; > + > + /* format raw message */ > + int ret = color_fmt_msg(out, sizeof(out), format, ap); > + if (fputs(out, f) < 0) > + return -1; > + > + return ret; > +} > + > +__rte_format_printf(2, 0) > +int > +color_print_with_timestamp(FILE *f, const char *format, va_list ap) > +{ > + char out[LINE_MAX]; > + char tsbuf[128]; > + int ret = 0; > + > + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) > + ret = color_snprintf(out, sizeof(out), > + LOG_FIELD_TIME, "[%s] ", tsbuf); > + > + ret += color_fmt_msg(out + ret, sizeof(out) - ret, format, ap); > + if (fputs(out, f) < 0) > + return -1; > + > + return ret; > +} > diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h > index 82fdc21ac2..bba7041ea3 100644 > --- a/lib/log/log_internal.h > +++ b/lib/log/log_internal.h > @@ -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 */ > diff --git a/lib/log/log_private.h b/lib/log/log_private.h > index 625f57c0cc..42babbcac1 100644 > --- a/lib/log/log_private.h > +++ b/lib/log/log_private.h > @@ -25,4 +25,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 */ > diff --git a/lib/log/meson.build b/lib/log/meson.build > index 86e4452b19..b3de57b9c7 100644 > --- a/lib/log/meson.build > +++ b/lib/log/meson.build > @@ -4,6 +4,7 @@ > includes += global_inc > sources = files( > 'log.c', > + 'log_color.c', > 'log_timestamp.c', > ) > > diff --git a/lib/log/version.map b/lib/log/version.map > index 800d3943bc..09d8a4289b 100644 > --- a/lib/log/version.map > +++ b/lib/log/version.map > @@ -25,6 +25,7 @@ DPDK_25 { > INTERNAL { > global: > > + eal_log_color; > eal_log_init; > eal_log_journal; # WINDOWS_NO_EXPORT > eal_log_level2str; > -- > 2.45.2 > > -- Baruch Even Platform Technical Lead at WEKA E baruch@weka.io* *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> [-- Attachment #2: Type: text/html, Size: 23752 bytes --] ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v27 14/14] doc: add release note about log library 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger ` (12 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 13/14] log: colorize log output Stephen Hemminger @ 2024-10-24 3:18 ` Stephen Hemminger 13 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 3:18 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng Significant enough to add some documentation. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- doc/guides/rel_notes/release_24_11.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst index fa4822d928..ec4b7ba2a4 100644 --- a/doc/guides/rel_notes/release_24_11.rst +++ b/doc/guides/rel_notes/release_24_11.rst @@ -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 ----------- -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 00/13] Logging subsystem improvements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (26 preceding siblings ...) 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 01/13] maintainers: add for log library Stephen Hemminger ` (12 more replies) 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger 29 siblings, 13 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev; +Cc: 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. v28 - fix windows build fixup documentation around syslog consolidate syslog patches 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 | 19 ++ 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 | 76 ++++-- lib/log/log_color.c | 214 ++++++++++++++++ lib/log/log_freebsd.c | 12 - lib/log/log_internal.h | 22 +- lib/log/log_journal.c | 154 +++++++++++ lib/log/log_linux.c | 61 ----- lib/log/log_private.h | 53 ++++ lib/log/log_syslog.c | 109 ++++++++ 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, 1158 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 -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 01/13] maintainers: add for log library 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 02/13] windows: make getopt functions have const properties Stephen Hemminger ` (11 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Chengwen Feng, Bruce Richardson, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index cd78bc7db1..a504b8fc54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -186,6 +186,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 02/13] windows: make getopt functions have const properties 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 01/13] maintainers: add for log library Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 03/13] windows: update os shim Stephen Hemminger ` (10 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 03/13] windows: update os shim 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 01/13] maintainers: add for log library Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 02/13] windows: make getopt functions have const properties Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 04/13] eal: make eal_log_level_parse common Stephen Hemminger ` (9 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ lib/log/log.c | 7 +++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..665c9ac93b 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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_ */ diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..7416c82b34 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 04/13] eal: make eal_log_level_parse common 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (2 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 03/13] windows: update os shim Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 05/13] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (8 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Dmitry Kozlyuk The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index f1a5e329a5..eb079a65a9 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 1229230063..d3b40e81d8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 54577b7718..40d750ed0d 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 28b78a95a6..a77e590a72 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 05/13] eal: do not duplicate rte_init_alert() messages 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (3 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 04/13] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 06/13] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (7 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3b40e81d8..7b974608e4 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 40d750ed0d..c53a051405 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); } /* diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index a77e590a72..93f099a968 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 06/13] eal: change rte_exit() output to match rte_log() 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (4 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 05/13] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 07/13] log: rework syslog handling Stephen Hemminger ` (6 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..bcfcd6df6f 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 07/13] log: rework syslog handling 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (5 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 06/13] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 08/13] eal: initialize log before everything else Stephen Hemminger ` (5 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff, Anatoly Burakov, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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 | 45 ++++---- 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 | 100 ++++++++++++++++++ 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 diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 71d8dba731..9fcf0d56e6 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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) { diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index fba467a2ce..9270d9fa3b 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -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 diff --git a/doc/guides/prog_guide/env_abstraction_layer.rst b/doc/guides/prog_guide/env_abstraction_layer.rst index b9fac1839d..9bafa30a0e 100644 --- a/doc/guides/prog_guide/env_abstraction_layer.rst +++ b/doc/guides/prog_guide/env_abstraction_layer.rst @@ -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 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..c87830ac00 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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 ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index eb079a65a9..ca7b702e03 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -93,7 +90,9 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, +#ifndef RTE_EXEC_ENV_WINDOWS + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, +#endif {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -349,10 +348,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1292,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1617,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1877,7 +1832,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; @@ -2254,7 +2209,7 @@ eal_common_usage(void) " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa..f53ab8b4aa 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -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 */ diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7b974608e4..a609d40ee0 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index c53a051405..0c44d0b6e3 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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")) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 93f099a968..cd8420a82c 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 7416c82b34..feadcd6848 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -11,14 +12,18 @@ #include <regex.h> #include <fnmatch.h> #include <sys/queue.h> +#include <unistd.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> + #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif #include "log_internal.h" +#include "log_private.h" struct rte_log_dynamic_type { const char *name; @@ -54,9 +59,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -69,8 +71,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -84,17 +84,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -505,12 +495,18 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) } /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id) { - default_log_stream = default_log; + FILE *logf = NULL; + + if (log_syslog_enabled()) + logf = log_syslog_open(id); + + if (logf) + rte_openlog_stream(logf); #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -524,8 +520,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 698d3c5423..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -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; -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 2dfb0c974b..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_log.h> - -#include "log_internal.h" - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -int -eal_log_init(const char *id, int facility) -{ - FILE *log_stream; - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - - openlog(id, LOG_NDELAY | LOG_PID, facility); - - eal_log_set_default(log_stream); - - return 0; -} diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..bf87b43f7e --- /dev/null +++ b/lib/log/log_private.h @@ -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 */ diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..7d29e3a00f --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static int log_facility; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + +/* syslog is enabled if facility is set */ +bool log_syslog_enabled(void) +{ + return log_facility != 0; /* LOG_KERN is 0 */ +} + +/* + * default log function + */ +static ssize_t +log_syslog_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + + return size; +} + +static int +log_syslog_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t log_syslog_func = { + .write = log_syslog_write, + .close = log_syslog_close, +}; + + +FILE * +log_syslog_open(const char *id) +{ + int option = LOG_CONS | LOG_NDELAY | LOG_PID | LOG_PERROR; + + openlog(id, option, log_facility); + + /* redirect other log messages to syslog as well */ + return fopencookie(NULL, "w", log_syslog_func); +} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index a6a0889550..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -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; -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..160cf34f50 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 19d7f9cdb6..1637fba3b9 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 08/13] eal: initialize log before everything else 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (6 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 07/13] log: rework syslog handling Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 09/13] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a609d40ee0..8631a20eae 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 0c44d0b6e3..62d3d281c4 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index cd8420a82c..33f044d7cc 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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."); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 09/13] log: add hook for printing log messages 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (7 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 08/13] eal: initialize log before everything else Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 10/13] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/log/log.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index feadcd6848..5e1eeb25c7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 10/13] log: add timestamp option 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (8 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 09/13] log: add hook for printing log messages Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 11/13] log: add support for systemd journal Stephen Hemminger ` (2 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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 diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 9fcf0d56e6..e24630edde 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index c87830ac00..82d3b7be2b 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ca7b702e03..a70d63479a 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 8631a20eae..456f91522c 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 62d3d281c4..cf2f0fcab9 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 33f044d7cc..b1c59945fb 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 5e1eeb25c7..7bf4548858 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..8ef195a6ec 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index bf87b43f7e..86eaf3f910 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..b4b0bca6a8 --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> +#include <rte_stdatomic.h> +#include <rte_time.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +#ifndef NS_PER_SEC +#define NS_PER_SEC 1E9 +#endif + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + RTE_ATOMIC(uint64_t) last_monotonic; + RTE_ATOMIC(uint64_t) last_realtime; +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Format a timestamp which shows time between messages. + */ +static ssize_t +format_delta(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct timespec delta; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + previous = rte_atomic_exchange_explicit(&log_time.last_monotonic, + ns, rte_memory_order_seq_cst); + delta = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, *last_tm, tbuf1, tbuf2; + time_t last_sec; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + tm = localtime_r(&now->tv_sec, &tbuf1); + + previous = rte_atomic_exchange_explicit(&log_time.last_realtime, + ns, rte_memory_order_seq_cst); + last_sec = previous / NS_PER_SEC; + last_tm = localtime_r(&last_sec, &tbuf2); + if (tm->tm_min == last_tm->tm_min && + tm->tm_hour == last_tm->tm_hour && + tm->tm_yday == last_tm->tm_yday) { + struct timespec elapsed; + + elapsed = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)elapsed.tv_sec, + (unsigned long)elapsed.tv_nsec / 1000u); + } else { + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + return format_delta(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + log_time.started = now; + rte_atomic_store_explicit(&log_time.last_monotonic, rte_timespec_to_ns(&now), + rte_memory_order_seq_cst); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 160cf34f50..4ac232786e 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_timestamp.c', ) if not is_windows diff --git a/lib/log/version.map b/lib/log/version.map index 1637fba3b9..8be6907840 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 11/13] log: add support for systemd journal 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (9 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 10/13] log: add timestamp option Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-25 15:33 ` Baruch Even 2024-10-24 19:02 ` [PATCH v28 12/13] log: colorize log output Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 13/13] doc: add release note about log library Stephen Hemminger 12 siblings, 1 reply; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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 diff --git a/lib/log/log.c b/lib/log/log.c index 7bf4548858..343f9d77b7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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; diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 8ef195a6ec..731c099984 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..43341aa233 --- /dev/null +++ b/lib/log/log_journal.c @@ -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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + * Uses writev() to ensure that whole log message is in one datagram + */ +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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +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()); + + /* 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); + if (log_stream != NULL) + return log_stream; + +error: + close(jfd); + return NULL; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 86eaf3f910..37895949f6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -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); diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c index 7d29e3a00f..c23b19fe89 100644 --- a/lib/log/log_syslog.c +++ b/lib/log/log_syslog.c @@ -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; diff --git a/lib/log/meson.build b/lib/log/meson.build index 4ac232786e..86e4452b19 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 8be6907840..800d3943bc 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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 ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v28 11/13] log: add support for systemd journal 2024-10-24 19:02 ` [PATCH v28 11/13] log: add support for systemd journal Stephen Hemminger @ 2024-10-25 15:33 ` Baruch Even 2024-10-25 15:56 ` Stephen Hemminger 0 siblings, 1 reply; 445+ messages in thread From: Baruch Even @ 2024-10-25 15:33 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Morten Brørup, Bruce Richardson [-- Attachment #1: Type: text/plain, Size: 10501 bytes --] 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. On Thu, Oct 24, 2024 at 10:09 PM Stephen Hemminger < stephen@networkplumber.org> wrote: > 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 > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> > Acked-by: Morten Brørup <mb@smartsharesystems.com> > Acked-by: Bruce Richardson <bruce.richardson@intel.com> > --- > 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 > > diff --git a/lib/log/log.c b/lib/log/log.c > index 7bf4548858..343f9d77b7 100644 > --- a/lib/log/log.c > +++ b/lib/log/log.c > @@ -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; > diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h > index 8ef195a6ec..731c099984 100644 > --- a/lib/log/log_internal.h > +++ b/lib/log/log_internal.h > @@ -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. > */ > diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c > new file mode 100644 > index 0000000000..43341aa233 > --- /dev/null > +++ b/lib/log/log_journal.c > @@ -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 > + */ > +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 > + */ > +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()); > + > + /* 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); > + if (log_stream != NULL) > + return log_stream; > + > +error: > + close(jfd); > + return NULL; > +} > diff --git a/lib/log/log_private.h b/lib/log/log_private.h > index 86eaf3f910..37895949f6 100644 > --- a/lib/log/log_private.h > +++ b/lib/log/log_private.h > @@ -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); > > diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c > index 7d29e3a00f..c23b19fe89 100644 > --- a/lib/log/log_syslog.c > +++ b/lib/log/log_syslog.c > @@ -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; > diff --git a/lib/log/meson.build b/lib/log/meson.build > index 4ac232786e..86e4452b19 100644 > --- a/lib/log/meson.build > +++ b/lib/log/meson.build > @@ -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') > diff --git a/lib/log/version.map b/lib/log/version.map > index 8be6907840..800d3943bc 100644 > --- a/lib/log/version.map > +++ b/lib/log/version.map > @@ -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 > > -- Baruch Even Platform Technical Lead at WEKA E baruch@weka.io* *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> [-- Attachment #2: Type: text/html, Size: 16543 bytes --] ^ permalink raw reply [flat|nested] 445+ messages in thread
* Re: [PATCH v28 11/13] log: add support for systemd journal 2024-10-25 15:33 ` Baruch Even @ 2024-10-25 15:56 ` Stephen Hemminger 0 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 15:56 UTC (permalink / raw) To: Baruch Even; +Cc: dev, Morten Brørup, Bruce Richardson On Fri, 25 Oct 2024 18:33:40 +0300 Baruch Even <baruch@weka.io> 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. ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 12/13] log: colorize log output 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (10 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 11/13] log: add support for systemd journal Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 13/13] doc: add release note about log library Stephen Hemminger 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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 diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e24630edde..cd73711da6 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 82d3b7be2b..a4f880037b 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index a70d63479a..6965666a7c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..87c3c32f86 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/log/log.c b/lib/log/log.c index 343f9d77b7..f1bd408bee 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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, diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..29bab9db49 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode = LOG_COLOR_NEVER; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +enum log_field { + LOG_FIELD_SUBSYS, + LOG_FIELD_TIME, + LOG_FIELD_ALERT, + LOG_FIELD_ERROR, + LOG_FIELD_INFO, +}; + +static const enum color field_colors[] = { + [LOG_FIELD_SUBSYS] = COLOR_YELLOW, + [LOG_FIELD_TIME] = COLOR_GREEN, + [LOG_FIELD_ALERT] = COLOR_RED, + [LOG_FIELD_ERROR] = COLOR_BOLD, + [LOG_FIELD_INFO] = COLOR_NONE, +}; + +/* If set all colors are bolder */ +static bool dark_mode; + +/* Standard terminal escape codes for colors and bold */ +static const uint8_t color_esc_code[] = { + [COLOR_RED] = 31, + [COLOR_GREEN] = 32, + [COLOR_YELLOW] = 33, + [COLOR_BLUE] = 34, + [COLOR_MAGENTA] = 35, + [COLOR_CYAN] = 36, + [COLOR_WHITE] = 37, + [COLOR_BOLD] = 1, +}; + +__rte_format_printf(4, 5) +static int +color_snprintf(char *buf, size_t len, enum log_field field, + const char *fmt, ...) +{ + enum color color = field_colors[field]; + uint8_t esc = color_esc_code[color]; + va_list args; + int ret = 0; + + va_start(args, fmt); + if (esc == 0) { + ret = vsnprintf(buf, len, fmt, args); + } else { + ret = snprintf(buf, len, + dark_mode ? "\e[1;%um" : "\e[%um", esc); + ret += vsnprintf(buf + ret, len - ret, fmt, args); + ret += snprintf(buf + ret, len - ret, "%s", "\e[0m"); + } + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + char *env, *sep; + + /* Set dark mode using the defacto heuristics used by other programs */ + env = getenv("COLORFGBG"); + if (env) { + sep = strrchr(env, ';'); + if (sep && + ((sep[1] >= '0' && sep[1] <= '6') || sep[1] == '8') && + sep[2] == '\0') + dark_mode = true; + } + + if (log_color_mode == LOG_COLOR_ALWAYS) + return true; + else if (log_color_mode == LOG_COLOR_AUTO) + return is_terminal; + else + return false; +} + +/* Look ast the current message level to determine color of field */ +static enum log_field +color_msg_field(void) +{ + const int level = rte_log_cur_msg_loglevel(); + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + return LOG_FIELD_INFO; + else if (level >= (int)RTE_LOG_ERR) + return LOG_FIELD_ERROR; + else + return LOG_FIELD_ALERT; +} + +__rte_format_printf(3, 0) +static int +color_fmt_msg(char *out, size_t len, const char *format, va_list ap) +{ + enum log_field field = color_msg_field(); + char buf[LINE_MAX]; + int ret = 0; + + /* format raw message */ + vsnprintf(buf, sizeof(buf), format, ap); + const char *msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + const char *cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_snprintf(out, len, LOG_FIELD_SUBSYS, + "%.*s", (int)(cp - msg + 1), msg); + /* skip the first part */ + msg = cp + 1; + } + + ret += color_snprintf(out + ret, len - ret, field, "%s", msg); + return ret; +} + +__rte_format_printf(2, 0) +int +color_print(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + + /* format raw message */ + int ret = color_fmt_msg(out, sizeof(out), format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} + +__rte_format_printf(2, 0) +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + char tsbuf[128]; + int ret = 0; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + ret = color_snprintf(out, sizeof(out), + LOG_FIELD_TIME, "[%s] ", tsbuf); + + ret += color_fmt_msg(out + ret, sizeof(out) - ret, format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 731c099984..00dde59211 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 37895949f6..5755cbf71f 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 86e4452b19..b3de57b9c7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 800d3943bc..09d8a4289b 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_25 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; # WINDOWS_NO_EXPORT eal_log_level2str; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v28 13/13] doc: add release note about log library 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger ` (11 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 12/13] log: colorize log output Stephen Hemminger @ 2024-10-24 19:02 ` Stephen Hemminger 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-24 19:02 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng Significant enough to add some documentation. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- doc/guides/rel_notes/release_24_11.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst index fa4822d928..ec4b7ba2a4 100644 --- a/doc/guides/rel_notes/release_24_11.rst +++ b/doc/guides/rel_notes/release_24_11.rst @@ -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 ----------- -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 00/13] Logging subsystem enhancements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (27 preceding siblings ...) 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 01/13] maintainers: add for log library Stephen Hemminger ` (12 more replies) 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger 29 siblings, 13 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev; +Cc: 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 -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 01/13] maintainers: add for log library 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 02/13] windows: make getopt functions have const properties Stephen Hemminger ` (11 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Chengwen Feng, Bruce Richardson, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index cd78bc7db1..a504b8fc54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -186,6 +186,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 02/13] windows: make getopt functions have const properties 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 01/13] maintainers: add for log library Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 03/13] windows: update os shim Stephen Hemminger ` (10 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 03/13] windows: update os shim 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 01/13] maintainers: add for log library Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 02/13] windows: make getopt functions have const properties Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 04/13] eal: make eal_log_level_parse common Stephen Hemminger ` (9 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/include/rte_os_shim.h | 10 ++++++++++ lib/log/log.c | 7 +++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..665c9ac93b 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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_ */ diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..7416c82b34 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 04/13] eal: make eal_log_level_parse common 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (2 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 03/13] windows: update os shim Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 05/13] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (8 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Dmitry Kozlyuk The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index f1a5e329a5..eb079a65a9 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 1229230063..d3b40e81d8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 54577b7718..40d750ed0d 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 28b78a95a6..a77e590a72 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 05/13] eal: do not duplicate rte_init_alert() messages 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (3 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 04/13] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 06/13] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (7 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3b40e81d8..7b974608e4 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 40d750ed0d..c53a051405 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); } /* diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index a77e590a72..93f099a968 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 06/13] eal: change rte_exit() output to match rte_log() 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (4 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 05/13] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 07/13] log: rework syslog handling Stephen Hemminger ` (6 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..bcfcd6df6f 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 07/13] log: rework syslog handling 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (5 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 06/13] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 08/13] eal: initialize log before everything else Stephen Hemminger ` (5 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff, Anatoly Burakov, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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 diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 71d8dba731..9fcf0d56e6 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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) { diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index fba467a2ce..9270d9fa3b 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -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 diff --git a/doc/guides/prog_guide/env_abstraction_layer.rst b/doc/guides/prog_guide/env_abstraction_layer.rst index b9fac1839d..9bafa30a0e 100644 --- a/doc/guides/prog_guide/env_abstraction_layer.rst +++ b/doc/guides/prog_guide/env_abstraction_layer.rst @@ -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 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..c87830ac00 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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 ------------------------------------------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index eb079a65a9..ca7b702e03 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -93,7 +90,9 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, +#ifndef RTE_EXEC_ENV_WINDOWS + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, +#endif {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -349,10 +348,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1292,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1617,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1877,7 +1832,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; @@ -2254,7 +2209,7 @@ eal_common_usage(void) " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa..f53ab8b4aa 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -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 */ diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7b974608e4..a609d40ee0 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index c53a051405..0c44d0b6e3 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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")) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 93f099a968..cd8420a82c 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 7416c82b34..511ab3b30b 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,13 +13,16 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> + #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif #include "log_internal.h" +#include "log_private.h" struct rte_log_dynamic_type { const char *name; @@ -54,9 +58,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -69,8 +70,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -84,17 +83,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -505,12 +494,18 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) } /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id) { - default_log_stream = default_log; + FILE *logf = NULL; + + if (log_syslog_enabled()) + logf = log_syslog_open(id); + + if (logf) + rte_openlog_stream(logf); #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -524,8 +519,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 698d3c5423..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -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; -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 2dfb0c974b..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_log.h> - -#include "log_internal.h" - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -int -eal_log_init(const char *id, int facility) -{ - FILE *log_stream; - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - - openlog(id, LOG_NDELAY | LOG_PID, facility); - - eal_log_set_default(log_stream); - - return 0; -} diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..bf87b43f7e --- /dev/null +++ b/lib/log/log_private.h @@ -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 */ diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..bc9b996fd6 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <stdbool.h> +#include <stdio.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static int log_facility; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + +/* syslog is enabled if facility is set */ +bool log_syslog_enabled(void) +{ + return log_facility != 0; /* LOG_KERN is 0 */ +} + +/* + * default log function + */ +static ssize_t +log_syslog_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + + return size; +} + +static int +log_syslog_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t log_syslog_func = { + .write = log_syslog_write, + .close = log_syslog_close, +}; + + +FILE * +log_syslog_open(const char *id) +{ + int option = LOG_CONS | LOG_NDELAY | LOG_PID | LOG_PERROR; + + openlog(id, option, log_facility); + + /* redirect other log messages to syslog as well */ + return fopencookie(NULL, "w", log_syslog_func); +} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index a6a0889550..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -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; -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..160cf34f50 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 19d7f9cdb6..1637fba3b9 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 08/13] eal: initialize log before everything else 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (6 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 07/13] log: rework syslog handling Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 09/13] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a609d40ee0..8631a20eae 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 0c44d0b6e3..62d3d281c4 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index cd8420a82c..33f044d7cc 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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."); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 09/13] log: add hook for printing log messages 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (7 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 08/13] eal: initialize log before everything else Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 10/13] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/log/log.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index 511ab3b30b..cc0c61cb22 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 10/13] log: add timestamp option 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (8 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 09/13] log: add hook for printing log messages Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 11/13] log: add support for systemd journal Stephen Hemminger ` (2 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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 diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 9fcf0d56e6..e24630edde 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index c87830ac00..82d3b7be2b 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ca7b702e03..a70d63479a 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 8631a20eae..456f91522c 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 62d3d281c4..cf2f0fcab9 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 33f044d7cc..b1c59945fb 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index cc0c61cb22..854d77887b 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..8ef195a6ec 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index bf87b43f7e..86eaf3f910 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..b4b0bca6a8 --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> +#include <rte_stdatomic.h> +#include <rte_time.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +#ifndef NS_PER_SEC +#define NS_PER_SEC 1E9 +#endif + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + RTE_ATOMIC(uint64_t) last_monotonic; + RTE_ATOMIC(uint64_t) last_realtime; +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Format a timestamp which shows time between messages. + */ +static ssize_t +format_delta(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct timespec delta; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + previous = rte_atomic_exchange_explicit(&log_time.last_monotonic, + ns, rte_memory_order_seq_cst); + delta = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, *last_tm, tbuf1, tbuf2; + time_t last_sec; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + tm = localtime_r(&now->tv_sec, &tbuf1); + + previous = rte_atomic_exchange_explicit(&log_time.last_realtime, + ns, rte_memory_order_seq_cst); + last_sec = previous / NS_PER_SEC; + last_tm = localtime_r(&last_sec, &tbuf2); + if (tm->tm_min == last_tm->tm_min && + tm->tm_hour == last_tm->tm_hour && + tm->tm_yday == last_tm->tm_yday) { + struct timespec elapsed; + + elapsed = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)elapsed.tv_sec, + (unsigned long)elapsed.tv_nsec / 1000u); + } else { + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + return format_delta(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + log_time.started = now; + rte_atomic_store_explicit(&log_time.last_monotonic, rte_timespec_to_ns(&now), + rte_memory_order_seq_cst); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 160cf34f50..4ac232786e 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_timestamp.c', ) if not is_windows diff --git a/lib/log/version.map b/lib/log/version.map index 1637fba3b9..8be6907840 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 11/13] log: add support for systemd journal 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (9 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 10/13] log: add timestamp option Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 12/13] log: colorize log output Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 13/13] doc: add release note about log library Stephen Hemminger 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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 diff --git a/lib/log/log.c b/lib/log/log.c index 854d77887b..db18690055 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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, diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 8ef195a6ec..731c099984 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..f163dc12ae --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,152 @@ +/* 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_log.h> + +#include "log_private.h" + +/* + * Send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + * Uses writev() to ensure that whole log message is in one datagram + */ +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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +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()); + + /* 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); + if (log_stream != NULL) + return log_stream; + +error: + close(jfd); + return NULL; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 86eaf3f910..37895949f6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -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); diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c index bc9b996fd6..15c1f835c8 100644 --- a/lib/log/log_syslog.c +++ b/lib/log/log_syslog.c @@ -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; diff --git a/lib/log/meson.build b/lib/log/meson.build index 4ac232786e..86e4452b19 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 8be6907840..800d3943bc 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 12/13] log: colorize log output 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (10 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 11/13] log: add support for systemd journal Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 13/13] doc: add release note about log library Stephen Hemminger 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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 diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e24630edde..061ddaf97f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 82d3b7be2b..a4f880037b 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index a70d63479a..6965666a7c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..87c3c32f86 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/log/log.c b/lib/log/log.c index db18690055..cd9261e55d 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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 diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..29bab9db49 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode = LOG_COLOR_NEVER; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +enum log_field { + LOG_FIELD_SUBSYS, + LOG_FIELD_TIME, + LOG_FIELD_ALERT, + LOG_FIELD_ERROR, + LOG_FIELD_INFO, +}; + +static const enum color field_colors[] = { + [LOG_FIELD_SUBSYS] = COLOR_YELLOW, + [LOG_FIELD_TIME] = COLOR_GREEN, + [LOG_FIELD_ALERT] = COLOR_RED, + [LOG_FIELD_ERROR] = COLOR_BOLD, + [LOG_FIELD_INFO] = COLOR_NONE, +}; + +/* If set all colors are bolder */ +static bool dark_mode; + +/* Standard terminal escape codes for colors and bold */ +static const uint8_t color_esc_code[] = { + [COLOR_RED] = 31, + [COLOR_GREEN] = 32, + [COLOR_YELLOW] = 33, + [COLOR_BLUE] = 34, + [COLOR_MAGENTA] = 35, + [COLOR_CYAN] = 36, + [COLOR_WHITE] = 37, + [COLOR_BOLD] = 1, +}; + +__rte_format_printf(4, 5) +static int +color_snprintf(char *buf, size_t len, enum log_field field, + const char *fmt, ...) +{ + enum color color = field_colors[field]; + uint8_t esc = color_esc_code[color]; + va_list args; + int ret = 0; + + va_start(args, fmt); + if (esc == 0) { + ret = vsnprintf(buf, len, fmt, args); + } else { + ret = snprintf(buf, len, + dark_mode ? "\e[1;%um" : "\e[%um", esc); + ret += vsnprintf(buf + ret, len - ret, fmt, args); + ret += snprintf(buf + ret, len - ret, "%s", "\e[0m"); + } + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + char *env, *sep; + + /* Set dark mode using the defacto heuristics used by other programs */ + env = getenv("COLORFGBG"); + if (env) { + sep = strrchr(env, ';'); + if (sep && + ((sep[1] >= '0' && sep[1] <= '6') || sep[1] == '8') && + sep[2] == '\0') + dark_mode = true; + } + + if (log_color_mode == LOG_COLOR_ALWAYS) + return true; + else if (log_color_mode == LOG_COLOR_AUTO) + return is_terminal; + else + return false; +} + +/* Look ast the current message level to determine color of field */ +static enum log_field +color_msg_field(void) +{ + const int level = rte_log_cur_msg_loglevel(); + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + return LOG_FIELD_INFO; + else if (level >= (int)RTE_LOG_ERR) + return LOG_FIELD_ERROR; + else + return LOG_FIELD_ALERT; +} + +__rte_format_printf(3, 0) +static int +color_fmt_msg(char *out, size_t len, const char *format, va_list ap) +{ + enum log_field field = color_msg_field(); + char buf[LINE_MAX]; + int ret = 0; + + /* format raw message */ + vsnprintf(buf, sizeof(buf), format, ap); + const char *msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + const char *cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_snprintf(out, len, LOG_FIELD_SUBSYS, + "%.*s", (int)(cp - msg + 1), msg); + /* skip the first part */ + msg = cp + 1; + } + + ret += color_snprintf(out + ret, len - ret, field, "%s", msg); + return ret; +} + +__rte_format_printf(2, 0) +int +color_print(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + + /* format raw message */ + int ret = color_fmt_msg(out, sizeof(out), format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} + +__rte_format_printf(2, 0) +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + char tsbuf[128]; + int ret = 0; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + ret = color_snprintf(out, sizeof(out), + LOG_FIELD_TIME, "[%s] ", tsbuf); + + ret += color_fmt_msg(out + ret, sizeof(out) - ret, format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 731c099984..00dde59211 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 37895949f6..5755cbf71f 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 86e4452b19..b3de57b9c7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 800d3943bc..09d8a4289b 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_25 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; # WINDOWS_NO_EXPORT eal_log_level2str; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v29 13/13] doc: add release note about log library 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger ` (11 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 12/13] log: colorize log output Stephen Hemminger @ 2024-10-25 21:45 ` Stephen Hemminger 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-25 21:45 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng Significant enough to warrant a release note. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- doc/guides/rel_notes/release_24_11.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst index fa4822d928..1d2e60231b 100644 --- a/doc/guides/rel_notes/release_24_11.rst +++ b/doc/guides/rel_notes/release_24_11.rst @@ -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 ----------- -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 00/13] Log library enhancements 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger ` (28 preceding siblings ...) 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 01/13] maintainers: add for log library Stephen Hemminger ` (12 more replies) 29 siblings, 13 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev; +Cc: 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 -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 01/13] maintainers: add for log library 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 02/13] windows: make getopt functions have const properties Stephen Hemminger ` (11 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Chengwen Feng, Bruce Richardson, Thomas Monjalon "You touch it you own it" Add myself as maintainer for log library. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index e25e9465b5..411b948649 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -187,6 +187,7 @@ F: app/test/test_threads.c F: app/test/test_version.c Logging +M: Stephen Hemminger <stephen@networkplumber.org> F: lib/log/ F: doc/guides/prog_guide/log_lib.rst F: app/test/test_logs.c -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 02/13] windows: make getopt functions have const properties 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 01/13] maintainers: add for log library Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 03/13] windows: update os shim Stephen Hemminger ` (10 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Dmitry Kozlyuk, Morten Brørup, Bruce Richardson, Chengwen Feng 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/getopt.c | 23 ++++++++++++----------- lib/eal/windows/include/getopt.h | 8 ++++---- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eal/windows/getopt.c b/lib/eal/windows/getopt.c index a1f51c6c23..50ff71b930 100644 --- a/lib/eal/windows/getopt.c +++ b/lib/eal/windows/getopt.c @@ -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) { diff --git a/lib/eal/windows/include/getopt.h b/lib/eal/windows/include/getopt.h index 6f57af454b..e4cf6873cb 100644 --- a/lib/eal/windows/include/getopt.h +++ b/lib/eal/windows/include/getopt.h @@ -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); -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 03/13] windows: update os shim 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 01/13] maintainers: add for log library Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 02/13] windows: make getopt functions have const properties Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 04/13] eal: make eal_log_level_parse common Stephen Hemminger ` (9 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/windows/include/rte_os_shim.h | 12 ++++++++++++ lib/log/log.c | 7 +++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/eal/windows/include/rte_os_shim.h b/lib/eal/windows/include/rte_os_shim.h index eda8113662..0e74eb19c7 100644 --- a/lib/eal/windows/include/rte_os_shim.h +++ b/lib/eal/windows/include/rte_os_shim.h @@ -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_ */ diff --git a/lib/log/log.c b/lib/log/log.c index 255f757d94..7416c82b34 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 04/13] eal: make eal_log_level_parse common 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (2 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 03/13] windows: update os shim Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 05/13] eal: do not duplicate rte_init_alert() messages Stephen Hemminger ` (8 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Dmitry Kozlyuk The code to parse for log-level option should be same on all OS variants. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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(-) diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index f1a5e329a5..eb079a65a9 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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) diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index 3cc9cb6412..f3f2e104f6 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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); diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 1229230063..d3b40e81d8 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -363,48 +363,6 @@ eal_get_hugepage_mem_size(void) return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX; } -/* 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; - const int old_optreset = optreset; - char * const old_optarg = optarg; - struct internal_config *internal_conf = - eal_get_internal_configuration(); - - argvopt = argv; - optind = 1; - optreset = 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; - optreset = old_optreset; - optarg = old_optarg; -} - /* Parse the argument given in the command line of the application */ static int eal_parse_args(int argc, char **argv) diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 54577b7718..40d750ed0d 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 28b78a95a6..a77e590a72 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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) -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 05/13] eal: do not duplicate rte_init_alert() messages 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (3 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 04/13] eal: make eal_log_level_parse common Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 06/13] eal: change rte_exit() output to match rte_log() Stephen Hemminger ` (7 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk The message already goes through logging, and does not need to be printed on stderr. Message level should be ALERT to match function name. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index d3b40e81d8..7b974608e4 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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(). */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 40d750ed0d..c53a051405 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); } /* diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index a77e590a72..93f099a968 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 06/13] eal: change rte_exit() output to match rte_log() 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (4 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 05/13] eal: do not duplicate rte_init_alert() messages Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 07/13] log: rework syslog handling Stephen Hemminger ` (6 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/eal/common/eal_common_debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/eal/common/eal_common_debug.c b/lib/eal/common/eal_common_debug.c index 3e77995896..bcfcd6df6f 100644 --- a/lib/eal/common/eal_common_debug.c +++ b/lib/eal/common/eal_common_debug.c @@ -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); } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 07/13] log: rework syslog handling 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (5 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 06/13] eal: change rte_exit() output to match rte_log() Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 08/13] eal: initialize log before everything else Stephen Hemminger ` (5 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff, Anatoly Burakov, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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 diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 71d8dba731..9fcf0d56e6 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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) { diff --git a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst index fba467a2ce..9270d9fa3b 100644 --- a/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst +++ b/doc/guides/freebsd_gsg/freebsd_eal_parameters.rst @@ -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 diff --git a/doc/guides/prog_guide/env_abstraction_layer.rst b/doc/guides/prog_guide/env_abstraction_layer.rst index b9fac1839d..9bafa30a0e 100644 --- a/doc/guides/prog_guide/env_abstraction_layer.rst +++ b/doc/guides/prog_guide/env_abstraction_layer.rst @@ -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 diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index ff9d1b54a2..a77ba939a9 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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 ---------- diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index eb079a65a9..ca7b702e03 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -6,9 +6,6 @@ #include <stdlib.h> #include <string.h> #include <pthread.h> -#ifndef RTE_EXEC_ENV_WINDOWS -#include <syslog.h> -#endif #include <ctype.h> #include <limits.h> #include <errno.h> @@ -93,7 +90,9 @@ eal_long_options[] = { {OPT_PROC_TYPE, 1, NULL, OPT_PROC_TYPE_NUM }, {OPT_SOCKET_MEM, 1, NULL, OPT_SOCKET_MEM_NUM }, {OPT_SOCKET_LIMIT, 1, NULL, OPT_SOCKET_LIMIT_NUM }, - {OPT_SYSLOG, 1, NULL, OPT_SYSLOG_NUM }, +#ifndef RTE_EXEC_ENV_WINDOWS + {OPT_SYSLOG, 2, NULL, OPT_SYSLOG_NUM }, +#endif {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VFIO_VF_TOKEN, 1, NULL, OPT_VFIO_VF_TOKEN_NUM }, @@ -349,10 +348,6 @@ eal_reset_internal_config(struct internal_config *internal_cfg) } internal_cfg->base_virtaddr = 0; -#ifdef LOG_DAEMON - internal_cfg->syslog_facility = LOG_DAEMON; -#endif - /* if set to NONE, interrupt mode is determined automatically */ internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE; memset(internal_cfg->vfio_vf_token, 0, @@ -1297,47 +1292,6 @@ eal_parse_lcores(const char *lcores) return ret; } -#ifndef RTE_EXEC_ENV_WINDOWS -static int -eal_parse_syslog(const char *facility, struct internal_config *conf) -{ - int i; - static const struct { - const char *name; - int value; - } map[] = { - { "auth", LOG_AUTH }, - { "cron", LOG_CRON }, - { "daemon", LOG_DAEMON }, - { "ftp", LOG_FTP }, - { "kern", LOG_KERN }, - { "lpr", LOG_LPR }, - { "mail", LOG_MAIL }, - { "news", LOG_NEWS }, - { "syslog", LOG_SYSLOG }, - { "user", LOG_USER }, - { "uucp", LOG_UUCP }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, 0 } - }; - - for (i = 0; map[i].name; i++) { - if (!strcmp(facility, map[i].name)) { - conf->syslog_facility = map[i].value; - return 0; - } - } - return -1; -} -#endif - static void eal_log_usage(void) { @@ -1663,6 +1617,7 @@ eal_log_level_parse(int argc, char * const argv[]) switch (opt) { case OPT_LOG_LEVEL_NUM: + case OPT_SYSLOG_NUM: if (eal_parse_common_option(opt, optarg, internal_conf) < 0) return -1; break; @@ -1877,7 +1832,7 @@ eal_parse_common_option(int opt, const char *optarg, #ifndef RTE_EXEC_ENV_WINDOWS case OPT_SYSLOG_NUM: - if (eal_parse_syslog(optarg, conf) < 0) { + if (eal_log_syslog(optarg) < 0) { EAL_LOG(ERR, "invalid parameters for --" OPT_SYSLOG); return -1; @@ -2254,7 +2209,7 @@ eal_common_usage(void) " --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n" " --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n" #ifndef RTE_EXEC_ENV_WINDOWS - " --"OPT_SYSLOG" Set syslog facility\n" + " --"OPT_SYSLOG"[=<when>] Enable use of syslog\n" #endif " --"OPT_LOG_LEVEL"=<level> Set global log level\n" " --"OPT_LOG_LEVEL"=<type-match>:<level>\n" diff --git a/lib/eal/common/eal_internal_cfg.h b/lib/eal/common/eal_internal_cfg.h index 167ec501fa..f53ab8b4aa 100644 --- a/lib/eal/common/eal_internal_cfg.h +++ b/lib/eal/common/eal_internal_cfg.h @@ -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 */ diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 7b974608e4..a609d40ee0 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index c53a051405..0c44d0b6e3 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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")) { diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 93f099a968..cd8420a82c 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index 7416c82b34..511ab3b30b 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -2,6 +2,7 @@ * Copyright(c) 2010-2014 Intel Corporation */ +#include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <stdarg.h> @@ -12,13 +13,16 @@ #include <fnmatch.h> #include <sys/queue.h> +#include <rte_common.h> #include <rte_log.h> #include <rte_per_lcore.h> + #ifdef RTE_EXEC_ENV_WINDOWS #include <rte_os_shim.h> #endif #include "log_internal.h" +#include "log_private.h" struct rte_log_dynamic_type { const char *name; @@ -54,9 +58,6 @@ TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); static struct rte_eal_opt_loglevel_list opt_loglevel_list = TAILQ_HEAD_INITIALIZER(opt_loglevel_list); -/* Stream to use for logging if rte_logs.file is NULL */ -static FILE *default_log_stream; - /** * This global structure stores some information about the message * that is currently being processed by one lcore @@ -69,8 +70,6 @@ struct log_cur_msg { /* per core log */ static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); -/* default logs */ - /* Change the stream that will be used by logging system */ int rte_openlog_stream(FILE *f) @@ -84,17 +83,7 @@ rte_log_get_stream(void) { FILE *f = rte_logs.file; - if (f == NULL) { - /* - * Grab the current value of stderr here, rather than - * just initializing default_log_stream to stderr. This - * ensures that we will always use the current value - * of stderr, even if the application closes and - * reopens it. - */ - return default_log_stream != NULL ? default_log_stream : stderr; - } - return f; + return (f == NULL) ? stderr : f; } /* Set global log level */ @@ -505,12 +494,18 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) } /* - * Called by environment-specific initialization functions. + * Called by rte_eal_init */ void -eal_log_set_default(FILE *default_log) +eal_log_init(const char *id) { - default_log_stream = default_log; + FILE *logf = NULL; + + if (log_syslog_enabled()) + logf = log_syslog_open(id); + + if (logf) + rte_openlog_stream(logf); #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, @@ -524,8 +519,11 @@ eal_log_set_default(FILE *default_log) void rte_eal_log_cleanup(void) { - if (default_log_stream) { - fclose(default_log_stream); - default_log_stream = NULL; - } + FILE *log_stream = rte_logs.file; + + /* don't close stderr on the application */ + if (log_stream != NULL) + fclose(log_stream); + + rte_logs.file = NULL; } diff --git a/lib/log/log_freebsd.c b/lib/log/log_freebsd.c deleted file mode 100644 index 698d3c5423..0000000000 --- a/lib/log/log_freebsd.c +++ /dev/null @@ -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; -} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 451629f1c1..3c46328e7b 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_linux.c b/lib/log/log_linux.c deleted file mode 100644 index 2dfb0c974b..0000000000 --- a/lib/log/log_linux.c +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <sys/types.h> -#include <syslog.h> - -#include <rte_log.h> - -#include "log_internal.h" - -/* - * default log function - */ -static ssize_t -console_log_write(__rte_unused void *c, const char *buf, size_t size) -{ - ssize_t ret; - - /* write on stderr */ - ret = fwrite(buf, 1, size, stderr); - fflush(stderr); - - /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ - syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); - - return ret; -} - -static int -console_log_close(__rte_unused void *c) -{ - closelog(); - return 0; -} - -static cookie_io_functions_t console_log_func = { - .write = console_log_write, - .close = console_log_close, -}; - -/* - * set the log to default function, called during eal init process, - * once memzones are available. - */ -int -eal_log_init(const char *id, int facility) -{ - FILE *log_stream; - - log_stream = fopencookie(NULL, "w+", console_log_func); - if (log_stream == NULL) - return -1; - - openlog(id, LOG_NDELAY | LOG_PID, facility); - - eal_log_set_default(log_stream); - - return 0; -} diff --git a/lib/log/log_private.h b/lib/log/log_private.h new file mode 100644 index 0000000000..bf87b43f7e --- /dev/null +++ b/lib/log/log_private.h @@ -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 */ diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c new file mode 100644 index 0000000000..bc9b996fd6 --- /dev/null +++ b/lib/log/log_syslog.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <stdbool.h> +#include <stdio.h> +#include <syslog.h> + +#include <rte_common.h> +#include <rte_log.h> + +#include "log_internal.h" +#include "log_private.h" + +static int log_facility; + +static const struct { + const char *name; + int value; +} facilitys[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "kern", LOG_KERN }, + { "lpr", LOG_LPR }, + { "mail", LOG_MAIL }, + { "news", LOG_NEWS }, + { "syslog", LOG_SYSLOG }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, +}; + +int +eal_log_syslog(const char *name) +{ + unsigned int i; + + for (i = 0; i < RTE_DIM(facilitys); i++) { + if (!strcmp(name, facilitys[i].name)) { + log_facility = facilitys[i].value; + return 0; + } + } + return -1; +} + +/* syslog is enabled if facility is set */ +bool log_syslog_enabled(void) +{ + return log_facility != 0; /* LOG_KERN is 0 */ +} + +/* + * default log function + */ +static ssize_t +log_syslog_write(__rte_unused void *c, const char *buf, size_t size) +{ + /* Syslog error levels are from 0 to 7, so subtract 1 to convert */ + syslog(rte_log_cur_msg_loglevel() - 1, "%.*s", (int)size, buf); + + return size; +} + +static int +log_syslog_close(__rte_unused void *c) +{ + closelog(); + return 0; +} + +static cookie_io_functions_t log_syslog_func = { + .write = log_syslog_write, + .close = log_syslog_close, +}; + + +FILE * +log_syslog_open(const char *id) +{ + int option = LOG_CONS | LOG_NDELAY | LOG_PID | LOG_PERROR; + + openlog(id, option, log_facility); + + /* redirect other log messages to syslog as well */ + return fopencookie(NULL, "w", log_syslog_func); +} diff --git a/lib/log/log_windows.c b/lib/log/log_windows.c deleted file mode 100644 index a6a0889550..0000000000 --- a/lib/log/log_windows.c +++ /dev/null @@ -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; -} diff --git a/lib/log/meson.build b/lib/log/meson.build index 0d4319b36f..160cf34f50 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 19d7f9cdb6..1637fba3b9 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 08/13] eal: initialize log before everything else 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (6 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 07/13] log: rework syslog handling Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 09/13] log: add hook for printing log messages Stephen Hemminger ` (4 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Tyler Retzlaff, Morten Brørup, Bruce Richardson, Chengwen Feng, Dmitry Kozlyuk 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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(-) diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index a609d40ee0..8631a20eae 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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; diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 0c44d0b6e3..62d3d281c4 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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"); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index cd8420a82c..33f044d7cc 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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."); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 3c46328e7b..d5fabd7ef7 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 09/13] log: add hook for printing log messages 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (7 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 08/13] eal: initialize log before everything else Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 10/13] log: add timestamp option Stephen Hemminger ` (3 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng This is useful for when decorating log output for console or journal. Provide basic version in this patch. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- lib/log/log.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/log/log.c b/lib/log/log.c index 511ab3b30b..cc0c61cb22 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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; } -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 10/13] log: add timestamp option 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (8 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 09/13] log: add hook for printing log messages Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 11/13] log: add support for systemd journal Stephen Hemminger ` (2 subsequent siblings) 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Tyler Retzlaff, Dmitry Kozlyuk 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 Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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 diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index 9fcf0d56e6..e24630edde 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index a77ba939a9..3843b70016 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index ca7b702e03..a70d63479a 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index f3f2e104f6..e24c9eca53 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/eal/freebsd/eal.c b/lib/eal/freebsd/eal.c index 8631a20eae..456f91522c 100644 --- a/lib/eal/freebsd/eal.c +++ b/lib/eal/freebsd/eal.c @@ -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); diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index 62d3d281c4..cf2f0fcab9 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -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); diff --git a/lib/eal/windows/eal.c b/lib/eal/windows/eal.c index 33f044d7cc..b1c59945fb 100644 --- a/lib/eal/windows/eal.c +++ b/lib/eal/windows/eal.c @@ -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); diff --git a/lib/log/log.c b/lib/log/log.c index cc0c61cb22..854d77887b 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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"); diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index d5fabd7ef7..8ef195a6ec 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index bf87b43f7e..86eaf3f910 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -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 */ diff --git a/lib/log/log_timestamp.c b/lib/log/log_timestamp.c new file mode 100644 index 0000000000..b4b0bca6a8 --- /dev/null +++ b/lib/log/log_timestamp.c @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <rte_common.h> +#include <rte_stdatomic.h> +#include <rte_time.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +#ifndef NS_PER_SEC +#define NS_PER_SEC 1E9 +#endif + +static enum { + LOG_TIMESTAMP_NONE = 0, + LOG_TIMESTAMP_TIME, /* time since start */ + LOG_TIMESTAMP_DELTA, /* time since last message */ + LOG_TIMESTAMP_RELTIME, /* relative time since last message */ + LOG_TIMESTAMP_CTIME, /* Unix standard time format */ + LOG_TIMESTAMP_ISO, /* ISO8601 time format */ +} log_time_format; + +static struct { + struct timespec started; /* when log was initialized */ + RTE_ATOMIC(uint64_t) last_monotonic; + RTE_ATOMIC(uint64_t) last_realtime; +} log_time; + +/* Set the log timestamp format */ +int +eal_log_timestamp(const char *str) +{ + if (str == NULL) + log_time_format = LOG_TIMESTAMP_TIME; + else if (strcmp(str, "notime") == 0) + log_time_format = LOG_TIMESTAMP_NONE; + else if (strcmp(str, "reltime") == 0) + log_time_format = LOG_TIMESTAMP_RELTIME; + else if (strcmp(str, "delta") == 0) + log_time_format = LOG_TIMESTAMP_DELTA; + else if (strcmp(str, "ctime") == 0) + log_time_format = LOG_TIMESTAMP_CTIME; + else if (strcmp(str, "iso") == 0) + log_time_format = LOG_TIMESTAMP_ISO; + else + return -1; + + return 0; +} + +bool +log_timestamp_enabled(void) +{ + return log_time_format != LOG_TIMESTAMP_NONE; +} + +/* Subtract two timespec values and handle wraparound */ +static struct timespec +timespec_sub(const struct timespec *t0, const struct timespec *t1) +{ + struct timespec ts; + + ts.tv_sec = t0->tv_sec - t1->tv_sec; + ts.tv_nsec = t0->tv_nsec - t1->tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000L; + } + return ts; +} + +/* + * Format current timespec into ISO8601 format. + * Surprisingly, can't just use strftime() for this; + * since want microseconds and the timezone offset format differs. + */ +static ssize_t +format_iso8601(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, tbuf; + char dbuf[64]; /* "2024-05-01T22:11:00" */ + char zbuf[16] = { }; /* "+0800" */ + + tm = localtime_r(&now->tv_sec, &tbuf); + + /* make "2024-05-01T22:11:00,123456+0100" */ + if (strftime(dbuf, sizeof(dbuf), "%Y-%m-%dT%H:%M:%S", tm) == 0) + return 0; + + /* convert timezone to +hhmm */ + if (strftime(zbuf, sizeof(zbuf), "%z", tm) == 0) + return 0; + + /* the result for strftime is "+hhmm" but ISO wants "+hh:mm" */ + return snprintf(tsbuf, tsbuflen, "%s,%06lu%.3s:%.2s", + dbuf, now->tv_nsec / 1000u, + zbuf, zbuf + 3); +} + +/* + * Format a timestamp which shows time between messages. + */ +static ssize_t +format_delta(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct timespec delta; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + previous = rte_atomic_exchange_explicit(&log_time.last_monotonic, + ns, rte_memory_order_seq_cst); + delta = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "<%6lu.%06lu>", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); +} + +/* + * Make a timestamp where if the minute, hour or day has + * changed from the last message, then print abbreviated + * "Month day hour:minute" format. + * Otherwise print delta from last printed message as +sec.usec + */ +static ssize_t +format_reltime(char *tsbuf, size_t tsbuflen, const struct timespec *now) +{ + struct tm *tm, *last_tm, tbuf1, tbuf2; + time_t last_sec; + uint64_t ns = rte_timespec_to_ns(now); + uint64_t previous; + + tm = localtime_r(&now->tv_sec, &tbuf1); + + previous = rte_atomic_exchange_explicit(&log_time.last_realtime, + ns, rte_memory_order_seq_cst); + last_sec = previous / NS_PER_SEC; + last_tm = localtime_r(&last_sec, &tbuf2); + if (tm->tm_min == last_tm->tm_min && + tm->tm_hour == last_tm->tm_hour && + tm->tm_yday == last_tm->tm_yday) { + struct timespec elapsed; + + elapsed = rte_ns_to_timespec(ns - previous); + + return snprintf(tsbuf, tsbuflen, "+%3lu.%06lu", + (unsigned long)elapsed.tv_sec, + (unsigned long)elapsed.tv_nsec / 1000u); + } else { + return strftime(tsbuf, tsbuflen, "%b%d %H:%M", tm); + } +} + +/* Format up a timestamp based on current format */ +ssize_t +log_timestamp(char *tsbuf, size_t tsbuflen) +{ + struct timespec now, delta; + + switch (log_time_format) { + case LOG_TIMESTAMP_NONE: + return 0; + + case LOG_TIMESTAMP_TIME: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + delta = timespec_sub(&now, &log_time.started); + + return snprintf(tsbuf, tsbuflen, "%6lu.%06lu", + (unsigned long)delta.tv_sec, + (unsigned long)delta.tv_nsec / 1000u); + + case LOG_TIMESTAMP_DELTA: + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) + return 0; + + return format_delta(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_RELTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_reltime(tsbuf, tsbuflen, &now); + + case LOG_TIMESTAMP_CTIME: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + /* trncate to remove newline from ctime result */ + return snprintf(tsbuf, tsbuflen, "%.24s", ctime(&now.tv_sec)); + + case LOG_TIMESTAMP_ISO: + if (clock_gettime(CLOCK_REALTIME, &now) < 0) + return 0; + + return format_iso8601(tsbuf, tsbuflen, &now); + } + + return 0; +} + +/* print timestamp before message */ +int +log_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char tsbuf[128]; + char msgbuf[LINE_MAX]; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) { + vsnprintf(msgbuf, sizeof(msgbuf), format, ap); + return fprintf(f, "[%s] %s", tsbuf, msgbuf); + } + + /* fall back when timestamp is unavailable */ + return vfprintf(f, format, ap); +} + +RTE_INIT_PRIO(log_timestamp_init, LOG) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + log_time.started = now; + rte_atomic_store_explicit(&log_time.last_monotonic, rte_timespec_to_ns(&now), + rte_memory_order_seq_cst); +} diff --git a/lib/log/meson.build b/lib/log/meson.build index 160cf34f50..4ac232786e 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_timestamp.c', ) if not is_windows diff --git a/lib/log/version.map b/lib/log/version.map index 1637fba3b9..8be6907840 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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; }; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 11/13] log: add support for systemd journal 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (9 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 10/13] log: add timestamp option Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 12/13] log: colorize log output Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 13/13] doc: add release note about log library Stephen Hemminger 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev; +Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson 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/ Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> --- 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 diff --git a/lib/log/log.c b/lib/log/log.c index 854d77887b..db18690055 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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, diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 8ef195a6ec..731c099984 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..f163dc12ae --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,152 @@ +/* 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_log.h> + +#include "log_private.h" + +/* + * Send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + * Uses writev() to ensure that whole log message is in one datagram + */ +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://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +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()); + + /* 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); + if (log_stream != NULL) + return log_stream; + +error: + close(jfd); + return NULL; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 86eaf3f910..37895949f6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -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); diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c index bc9b996fd6..15c1f835c8 100644 --- a/lib/log/log_syslog.c +++ b/lib/log/log_syslog.c @@ -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; diff --git a/lib/log/meson.build b/lib/log/meson.build index 4ac232786e..86e4452b19 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -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') diff --git a/lib/log/version.map b/lib/log/version.map index 8be6907840..800d3943bc 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -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 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 12/13] log: colorize log output 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (10 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 11/13] log: add support for systemd journal Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 13/13] doc: add release note about log library Stephen Hemminger 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng, Tyler Retzlaff 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. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- 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 diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c index e24630edde..061ddaf97f 100644 --- a/app/test/test_eal_flags.c +++ b/app/test/test_eal_flags.c @@ -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); diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst index 3843b70016..748d3836dc 100644 --- a/doc/guides/prog_guide/log_lib.rst +++ b/doc/guides/prog_guide/log_lib.rst @@ -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. diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c index a70d63479a..6965666a7c 100644 --- a/lib/eal/common/eal_common_options.c +++ b/lib/eal/common/eal_common_options.c @@ -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" diff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h index e24c9eca53..87c3c32f86 100644 --- a/lib/eal/common/eal_options.h +++ b/lib/eal/common/eal_options.h @@ -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" diff --git a/lib/log/log.c b/lib/log/log.c index db18690055..cd9261e55d 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -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 diff --git a/lib/log/log_color.c b/lib/log/log_color.c new file mode 100644 index 0000000000..29bab9db49 --- /dev/null +++ b/lib/log/log_color.c @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_log.h> + +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_os_shim.h> +#endif + +#include "log_internal.h" +#include "log_private.h" + +enum { + LOG_COLOR_AUTO = 0, + LOG_COLOR_NEVER, + LOG_COLOR_ALWAYS, +} log_color_mode = LOG_COLOR_NEVER; + +enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_WHITE, + COLOR_BOLD, + COLOR_CLEAR, +}; + +enum log_field { + LOG_FIELD_SUBSYS, + LOG_FIELD_TIME, + LOG_FIELD_ALERT, + LOG_FIELD_ERROR, + LOG_FIELD_INFO, +}; + +static const enum color field_colors[] = { + [LOG_FIELD_SUBSYS] = COLOR_YELLOW, + [LOG_FIELD_TIME] = COLOR_GREEN, + [LOG_FIELD_ALERT] = COLOR_RED, + [LOG_FIELD_ERROR] = COLOR_BOLD, + [LOG_FIELD_INFO] = COLOR_NONE, +}; + +/* If set all colors are bolder */ +static bool dark_mode; + +/* Standard terminal escape codes for colors and bold */ +static const uint8_t color_esc_code[] = { + [COLOR_RED] = 31, + [COLOR_GREEN] = 32, + [COLOR_YELLOW] = 33, + [COLOR_BLUE] = 34, + [COLOR_MAGENTA] = 35, + [COLOR_CYAN] = 36, + [COLOR_WHITE] = 37, + [COLOR_BOLD] = 1, +}; + +__rte_format_printf(4, 5) +static int +color_snprintf(char *buf, size_t len, enum log_field field, + const char *fmt, ...) +{ + enum color color = field_colors[field]; + uint8_t esc = color_esc_code[color]; + va_list args; + int ret = 0; + + va_start(args, fmt); + if (esc == 0) { + ret = vsnprintf(buf, len, fmt, args); + } else { + ret = snprintf(buf, len, + dark_mode ? "\e[1;%um" : "\e[%um", esc); + ret += vsnprintf(buf + ret, len - ret, fmt, args); + ret += snprintf(buf + ret, len - ret, "%s", "\e[0m"); + } + va_end(args); + + return ret; +} + +/* + * Controls whether color is enabled: + * modes are: + * always - enable color output regardless + * auto - enable if stderr is a terminal + * never - color output is disabled. + */ +int +eal_log_color(const char *mode) +{ + if (mode == NULL || strcmp(mode, "always") == 0) + log_color_mode = LOG_COLOR_ALWAYS; + else if (strcmp(mode, "never") == 0) + log_color_mode = LOG_COLOR_NEVER; + else if (strcmp(mode, "auto") == 0) + log_color_mode = LOG_COLOR_AUTO; + else + return -1; + + return 0; +} + +bool +log_color_enabled(bool is_terminal) +{ + char *env, *sep; + + /* Set dark mode using the defacto heuristics used by other programs */ + env = getenv("COLORFGBG"); + if (env) { + sep = strrchr(env, ';'); + if (sep && + ((sep[1] >= '0' && sep[1] <= '6') || sep[1] == '8') && + sep[2] == '\0') + dark_mode = true; + } + + if (log_color_mode == LOG_COLOR_ALWAYS) + return true; + else if (log_color_mode == LOG_COLOR_AUTO) + return is_terminal; + else + return false; +} + +/* Look ast the current message level to determine color of field */ +static enum log_field +color_msg_field(void) +{ + const int level = rte_log_cur_msg_loglevel(); + + if (level <= 0 || level >= (int)RTE_LOG_INFO) + return LOG_FIELD_INFO; + else if (level >= (int)RTE_LOG_ERR) + return LOG_FIELD_ERROR; + else + return LOG_FIELD_ALERT; +} + +__rte_format_printf(3, 0) +static int +color_fmt_msg(char *out, size_t len, const char *format, va_list ap) +{ + enum log_field field = color_msg_field(); + char buf[LINE_MAX]; + int ret = 0; + + /* format raw message */ + vsnprintf(buf, sizeof(buf), format, ap); + const char *msg = buf; + + /* + * use convention that first part of message (up to the ':' character) + * is the subsystem id and should be highlighted. + */ + const char *cp = strchr(msg, ':'); + if (cp) { + /* print first part in yellow */ + ret = color_snprintf(out, len, LOG_FIELD_SUBSYS, + "%.*s", (int)(cp - msg + 1), msg); + /* skip the first part */ + msg = cp + 1; + } + + ret += color_snprintf(out + ret, len - ret, field, "%s", msg); + return ret; +} + +__rte_format_printf(2, 0) +int +color_print(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + + /* format raw message */ + int ret = color_fmt_msg(out, sizeof(out), format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} + +__rte_format_printf(2, 0) +int +color_print_with_timestamp(FILE *f, const char *format, va_list ap) +{ + char out[LINE_MAX]; + char tsbuf[128]; + int ret = 0; + + if (log_timestamp(tsbuf, sizeof(tsbuf)) > 0) + ret = color_snprintf(out, sizeof(out), + LOG_FIELD_TIME, "[%s] ", tsbuf); + + ret += color_fmt_msg(out + ret, sizeof(out) - ret, format, ap); + if (fputs(out, f) < 0) + return -1; + + return ret; +} diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 731c099984..00dde59211 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -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 */ diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 37895949f6..5755cbf71f 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -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 */ diff --git a/lib/log/meson.build b/lib/log/meson.build index 86e4452b19..b3de57b9c7 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -4,6 +4,7 @@ includes += global_inc sources = files( 'log.c', + 'log_color.c', 'log_timestamp.c', ) diff --git a/lib/log/version.map b/lib/log/version.map index 800d3943bc..09d8a4289b 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -25,6 +25,7 @@ DPDK_25 { INTERNAL { global: + eal_log_color; eal_log_init; eal_log_journal; # WINDOWS_NO_EXPORT eal_log_level2str; -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
* [PATCH v30 13/13] doc: add release note about log library 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger ` (11 preceding siblings ...) 2024-10-27 17:24 ` [PATCH v30 12/13] log: colorize log output Stephen Hemminger @ 2024-10-27 17:24 ` Stephen Hemminger 12 siblings, 0 replies; 445+ messages in thread From: Stephen Hemminger @ 2024-10-27 17:24 UTC (permalink / raw) To: dev Cc: Stephen Hemminger, Morten Brørup, Bruce Richardson, Chengwen Feng Significant enough to warrant a release note. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Morten Brørup <mb@smartsharesystems.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Chengwen Feng <fengchengwen@huawei.com> --- doc/guides/rel_notes/release_24_11.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/guides/rel_notes/release_24_11.rst b/doc/guides/rel_notes/release_24_11.rst index 53a5ffebe5..b96042ea14 100644 --- a/doc/guides/rel_notes/release_24_11.rst +++ b/doc/guides/rel_notes/release_24_11.rst @@ -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 ----------- -- 2.45.2 ^ permalink raw reply [flat|nested] 445+ messages in thread
end of thread, other threads:[~2024-10-27 17:27 UTC | newest] Thread overview: 445+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-08-14 17:34 [dpdk-dev] [PATCH] eal: add option to put timestamp on console output Stephen Hemminger 2020-08-14 18:39 ` Dmitry Kozlyuk 2020-08-14 18:45 ` Stephen Hemminger 2020-08-14 19:09 ` Dmitry Kozlyuk 2020-08-14 19:20 ` Stephen Hemminger 2020-08-17 10:37 ` Bruce Richardson 2020-08-17 15:11 ` Stephen Hemminger 2020-10-19 14:11 ` Thomas Monjalon 2020-10-19 15:25 ` Stephen Hemminger 2024-03-21 17:22 ` Thomas Monjalon 2023-03-06 18:18 ` [PATCH v2 0/2] Add option to timestamp console log Stephen Hemminger 2023-03-06 18:18 ` [PATCH v2 1/2] eal: unify logging code for FreeBsd and Linux Stephen Hemminger 2023-03-06 18:18 ` [PATCH v2 2/2] eal: add option to put timestamp on console output Stephen Hemminger 2023-03-07 9:09 ` [PATCH v2 0/2] Add option to timestamp console log Bruce Richardson 2023-03-06 19:28 ` [PATCH v3 " Stephen Hemminger 2023-03-06 19:28 ` [PATCH v3 1/2] eal: unify logging code for FreeBsd and Linux Stephen Hemminger 2023-03-06 19:28 ` [PATCH v3 2/2] eal: add option to put timestamp on console output Stephen Hemminger 2023-03-07 9:35 ` fengchengwen 2023-03-07 16:05 ` Stephen Hemminger 2023-03-07 16:06 ` Stephen Hemminger 2023-03-08 0:36 ` fengchengwen 2023-03-08 2:03 ` Stephen Hemminger 2023-03-09 0:55 ` fengchengwen 2023-03-08 2:51 ` Stephen Hemminger 2023-03-07 7:33 ` [PATCH v3 0/2] Add option to timestamp console log Morten Brørup 2023-03-07 9:12 ` Bruce Richardson 2023-03-07 16:04 ` Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 0/5] Logging related patchs Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 1/5] eal: unify logging code for FreeBsd and Linux Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 2/5] eal: turn off getopt_long error message during eal_log_level Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 3/5] eal: skip stdio on console logging Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 4/5] eal: move logging initialization earlier Stephen Hemminger 2023-06-26 18:42 ` [PATCH v4 5/5] eal: add option to put timestamp on console output Stephen Hemminger 2023-06-27 7:40 ` [PATCH v4 0/5] Logging related patchs Morten Brørup 2023-06-27 14:49 ` Stephen Hemminger 2023-06-27 15:04 ` Morten Brørup 2023-06-27 15:02 ` Bruce Richardson 2023-06-28 17:58 ` [PATCH v5 0/6] Logging related patches Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 1/6] eal: unify logging code for FreeBsd and Linux Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 2/6] eal: turn off getopt_long error message during eal_log_level Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 3/6] eal: fix handling of syslog facility Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 4/6] eal: skip stdio on console logging Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 5/6] eal: allow user to set default log stream before init Stephen Hemminger 2023-06-28 17:58 ` [PATCH v5 6/6] eal: add option to put timestamp on console output Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 0/6] Logging related patches Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 1/6] eal: unify logging code Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 2/6] eal: turn off getopt_long error message during eal_log_level Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 3/6] eal: fix help message for syslog option Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 4/6] eal: skip stdio on console logging Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 5/6] eal: allow user to set default log stream before init Stephen Hemminger 2023-06-29 15:58 ` [PATCH v6 6/6] eal: add option to put timestamp on console output Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 0/5] Logging timetamp and related patches Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 1/5] windows: make getopt functions have const properties Stephen Hemminger 2023-07-10 21:10 ` Tyler Retzlaff 2023-07-05 22:48 ` [PATCH v7 2/5] eal: fix help message for syslog option Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 3/5] eal: unify logging code Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 4/5] eal: allow user to set default log stream before init Stephen Hemminger 2023-07-05 22:48 ` [PATCH v7 5/5] eal: add option to put timestamp on console output Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 0/5] Logging timestamp and related patches Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 1/5] log: unify logging code Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 2/5] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 3/5] eal: allow user to set default log stream before init Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 4/5] eal: add option to put timestamp on console output Stephen Hemminger 2024-03-18 18:30 ` [PATCH v8 5/5] eal: initialize logging before plugins Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 0/5] Logging unification and timestamp Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 1/5] log: unify logging code Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 2/5] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-18 22:02 ` [PATCH v9 3/5] eal: initialize logging before plugins Stephen Hemminger 2024-03-18 22:03 ` [PATCH v9 4/5] eal: allow user to set default log stream before init Stephen Hemminger 2024-03-18 22:03 ` [PATCH v9 5/5] eal: add option to put timestamp on console output Stephen Hemminger 2024-03-19 7:37 ` Morten Brørup 2024-03-19 15:51 ` Stephen Hemminger 2024-03-19 16:13 ` Morten Brørup 2024-03-20 3:33 ` Stephen Hemminger 2024-03-20 8:34 ` Morten Brørup 2024-03-20 14:38 ` Stephen Hemminger 2024-03-20 17:38 ` Morten Brørup 2024-03-21 16:00 ` [PATCH v10 00/10] Logging enhancements Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 01/10] windows: make getopt functions have const properties Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 02/10] log: unify logging code Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 03/10] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-21 17:00 ` Tyler Retzlaff 2024-03-21 16:00 ` [PATCH v10 04/10] eal: initialize log earlier in startup Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 05/10] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 06/10] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-21 17:04 ` Tyler Retzlaff 2024-03-21 16:00 ` [PATCH v10 07/10] eal: allow user to set default log stream before init Stephen Hemminger 2024-03-21 17:07 ` Tyler Retzlaff 2024-03-21 16:00 ` [PATCH v10 08/10] eal: add option to put timestamp on console output Stephen Hemminger 2024-03-21 17:11 ` Tyler Retzlaff 2024-03-21 17:16 ` Stephen Hemminger 2024-03-21 17:49 ` Tyler Retzlaff 2024-03-22 0:30 ` Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 09/10] log: colorize log output Stephen Hemminger 2024-03-21 16:00 ` [PATCH v10 10/10] doc: add documentation of logging options Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 0/9] Logging unification and enhancements Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 1/9] windows: make getopt functions have const properties Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 2/9] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 3/9] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 4/9] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 5/9] log: drop syslog support, and make code common Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 6/9] log: add hook for printing log messages Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 7/9] log: add timestamp option Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 8/9] log: add support for systemd journal Stephen Hemminger 2024-03-24 2:33 ` [PATCH v11 9/9] log: colorize log output Stephen Hemminger 2024-03-24 11:18 ` [PATCH v11 0/9] Logging unification and enhancements Mattias Rönnblom 2024-03-25 20:46 ` [PATCH v12 00/14] " Stephen Hemminger 2024-03-25 20:46 ` [PATCH v12 01/14] windows: make getopt functions have const properties Stephen Hemminger 2024-03-25 20:46 ` [PATCH v12 02/14] windows: add os shim for localtime_r Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 03/14] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 04/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 05/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-27 7:17 ` Tyler Retzlaff 2024-03-25 20:47 ` [PATCH v12 06/14] log: move handling of syslog facility out of eal Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 07/14] eal: initialize log before everything else Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 08/14] log: drop syslog support, and make code common Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 09/14] log: add hook for printing log messages Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 10/14] log: add timestamp option Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 11/14] log: add optional support of syslog Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 12/14] log: add support for systemd journal Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 13/14] log: colorize log output Stephen Hemminger 2024-03-25 20:47 ` [PATCH v12 14/14] maintainers: add for log library Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 00/11] Logging unification and improvements Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 01/11] windows: make getopt functions have const properties Stephen Hemminger 2024-03-26 9:35 ` Morten Brørup 2024-03-26 1:56 ` [PATCH v13 02/11] windows: add os shim for localtime_r Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 03/11] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-26 1:56 ` [PATCH v13 04/11] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 05/11] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 06/11] log: move handling of syslog facility out of eal Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 07/11] eal: initialize log before everything else Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 08/11] log: drop syslog support, and make code common Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 09/11] log: add hook for printing log messages Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 10/11] log: add timestamp option Stephen Hemminger 2024-03-26 1:57 ` [PATCH v13 11/11] log: add optional support of syslog Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 00/15] Logging unification and improvments Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 01/15] maintainers: add for log library Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 05/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 08/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 09/15] eal: initialize log before everything else Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 10/15] log: drop syslog support, and make code common Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 11/15] log: add hook for printing log messages Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 12/15] log: add timestamp option Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 13/15] log: add optional support of syslog Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-26 17:34 ` [PATCH v14 15/15] log: colorize log output Stephen Hemminger 2024-03-27 0:26 ` [PATCH v15 00/15] Logging unification and improvements Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 01/15] maintainers: add for log library Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 05/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 08/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 09/15] eal: initialize log before everything else Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 10/15] log: drop syslog support, and make code common Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 11/15] log: add hook for printing log messages Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 12/15] log: add timestamp option Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 13/15] log: add optional support of syslog Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-27 0:27 ` [PATCH v15 15/15] log: colorize log output Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 00/15] Logging unification and improvements Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 01/15] maintainers: add for log library Stephen Hemminger 2024-03-27 16:52 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-03-27 16:56 ` Tyler Retzlaff 2024-03-27 17:30 ` Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger 2024-03-27 17:08 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 05/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-27 17:11 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-27 17:11 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-27 17:12 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 08/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 09/15] eal: initialize log before everything else Stephen Hemminger 2024-03-27 17:14 ` Tyler Retzlaff 2024-03-27 16:45 ` [PATCH v16 10/15] log: drop syslog support, and make code common Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 11/15] log: add hook for printing log messages Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 12/15] log: add timestamp option Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 13/15] log: add optional support of syslog Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-27 16:45 ` [PATCH v16 15/15] log: colorize log output Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 00/15] Logging unification and improvements Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 01/15] maintainers: add for log library Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 05/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 08/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 09/15] eal: initialize log before everything else Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 10/15] log: drop syslog support, and make code common Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 11/15] log: add hook for printing log messages Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 12/15] log: add timestamp option Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 13/15] log: add optional support of syslog Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-27 23:28 ` [PATCH v17 15/15] log: colorize log output Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 00/15] Logging unification and improvements Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 01/15] maintainers: add for log library Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 05/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 08/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 09/15] eal: initialize log before everything else Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 10/15] log: drop syslog support, and make code common Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 11/15] log: add hook for printing log messages Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 12/15] log: add timestamp option Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 13/15] log: add optional support of syslog Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-28 23:49 ` [PATCH v18 15/15] log: colorize log output Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 00/15] Logging unification and improvements Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 01/15] maintainers: add for log library Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 04/15] windows: common wrapper for vasprintf and asprintf Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 05/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 06/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 07/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 08/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 09/15] eal: initialize log before everything else Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 10/15] log: drop syslog support, and make code common Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 11/15] log: add hook for printing log messages Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 12/15] log: add timestamp option Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 13/15] log: add optional support of syslog Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 14/15] log: add support for systemd journal Stephen Hemminger 2024-03-30 3:00 ` [PATCH v19 15/15] log: colorize log output Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 00/14] Logging unification and improvements Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 01/14] maintainers: add for log library Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 02/14] windows: make getopt functions have const properties Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 03/14] windows: add os shim for localtime_r Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 04/14] eal: make eal_log_level_parse common Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 05/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 06/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 07/14] log: move handling of syslog facility out of eal Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 08/14] eal: initialize log before everything else Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 09/14] log: drop syslog support, and make code common Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 10/14] log: add hook for printing log messages Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 11/14] log: add timestamp option Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 12/14] log: add optional support of syslog Stephen Hemminger 2024-03-30 16:42 ` [PATCH v20 13/14] log: add support for systemd journal Stephen Hemminger 2024-04-01 11:18 ` Luca Boccassi 2024-03-30 16:42 ` [PATCH v20 14/14] log: colorize log output Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 00/14] Log library unification ane enhancements Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 01/14] maintainers: add for log library Stephen Hemminger 2024-06-06 5:35 ` Morten Brørup 2024-06-04 0:44 ` [PATCH v21 02/14] windows: make getopt functions have const properties Stephen Hemminger 2024-06-04 2:31 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 03/14] windows: add os shim for localtime_r Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 04/14] eal: make eal_log_level_parse common Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 05/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 06/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 07/14] log: move handling of syslog facility out of eal Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 08/14] eal: initialize log before everything else Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 09/14] log: drop syslog support, and make code common Stephen Hemminger 2024-06-04 2:30 ` Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 10/14] log: add hook for printing log messages Stephen Hemminger 2024-06-04 0:44 ` [PATCH v21 11/14] log: add timestamp option Stephen Hemminger 2024-06-04 2:33 ` Stephen Hemminger 2024-06-04 0:45 ` [PATCH v21 12/14] log: add optional support of syslog Stephen Hemminger 2024-06-04 2:34 ` Stephen Hemminger 2024-06-04 0:45 ` [PATCH v21 13/14] log: add support for systemd journal Stephen Hemminger 2024-06-04 2:35 ` Stephen Hemminger 2024-06-04 0:45 ` [PATCH v21 14/14] log: colorize log output Stephen Hemminger 2024-06-04 2:37 ` Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 00/15] Logging improvements Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 01/15] maintainers: add for log library Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 04/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 07/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 08/15] eal: initialize log before everything else Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 09/15] log: drop syslog support, and make code common Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 10/15] log: add hook for printing log messages Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 11/15] log: add timestamp option Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 12/15] log: add optional support of syslog Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 13/15] log: add support for systemd journal Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 14/15] log: colorize log output Stephen Hemminger 2024-09-17 20:35 ` [PATCH v22 15/15] doc: add release note about log library Stephen Hemminger 2024-09-18 4:38 ` Morten Brørup 2024-09-18 4:56 ` [PATCH v23 00/15] Logging improvements Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 01/15] maintainers: add for log library Stephen Hemminger 2024-09-18 7:01 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-09-18 7:04 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-09-18 7:09 ` fengchengwen 2024-09-18 15:25 ` Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 04/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-09-18 7:18 ` fengchengwen 2024-09-18 15:24 ` Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-09-18 7:18 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-09-18 7:23 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 07/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-09-18 7:25 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 08/15] eal: initialize log before everything else Stephen Hemminger 2024-09-18 7:30 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 09/15] log: drop syslog support, and make code common Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 10/15] log: add hook for printing log messages Stephen Hemminger 2024-09-18 7:32 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 11/15] log: add timestamp option Stephen Hemminger 2024-09-18 7:37 ` fengchengwen 2024-09-18 15:05 ` Stephen Hemminger 2024-09-19 1:20 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 12/15] log: add optional support of syslog Stephen Hemminger 2024-09-18 7:41 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 13/15] log: add support for systemd journal Stephen Hemminger 2024-09-18 4:56 ` [PATCH v23 14/15] log: colorize log output Stephen Hemminger 2024-09-18 7:43 ` fengchengwen 2024-09-18 4:56 ` [PATCH v23 15/15] doc: add release note about log library Stephen Hemminger 2024-09-18 7:44 ` fengchengwen 2024-09-18 8:27 ` [PATCH v23 00/15] Logging improvements Bruce Richardson 2024-09-18 20:51 ` [PATCH v24 00/15] Logging enhancements for 24.11 Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 01/15] maintainers: add for log library Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-09-19 1:07 ` fengchengwen 2024-09-18 20:52 ` [PATCH v24 04/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-09-19 1:09 ` fengchengwen 2024-09-18 20:52 ` [PATCH v24 07/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 08/15] eal: initialize log before everything else Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 09/15] log: drop syslog support, and make code common Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 10/15] log: add hook for printing log messages Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 11/15] log: add timestamp option Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 12/15] log: add optional support of syslog Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 13/15] log: add support for systemd journal Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 14/15] log: colorize log output Stephen Hemminger 2024-09-18 20:52 ` [PATCH v24 15/15] doc: add release note about log library Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 00/15] Logging enhancements for 24.11 Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 01/15] maintainers: add for log library Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 04/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 07/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 08/15] eal: initialize log before everything else Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 09/15] log: drop syslog support, and make code common Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 10/15] log: add hook for printing log messages Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 11/15] log: add timestamp option Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 12/15] log: add optional support of syslog Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 13/15] log: add support for systemd journal Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 14/15] log: colorize log output Stephen Hemminger 2024-09-19 15:04 ` [PATCH v25 15/15] doc: add release note about log library Stephen Hemminger 2024-09-30 20:34 ` Tyler Retzlaff 2024-09-20 14:47 ` [PATCH v25 00/15] Logging enhancements for 24.11 Patrick Robb 2024-10-16 20:20 ` [PATCH v26 00/15] Log subsystem improvements Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 01/15] maintainers: add for log library Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 02/15] windows: make getopt functions have const properties Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 03/15] windows: add os shim for localtime_r Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 04/15] eal: make eal_log_level_parse common Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 05/15] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-10-17 16:47 ` David Marchand 2024-10-17 17:17 ` Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 06/15] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 07/15] log: move handling of syslog facility out of eal Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 08/15] eal: initialize log before everything else Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 09/15] log: drop syslog support, and make code common Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 10/15] log: add hook for printing log messages Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 11/15] log: add timestamp option Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 12/15] log: add optional support of syslog Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 13/15] log: add support for systemd journal Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 14/15] log: colorize log output Stephen Hemminger 2024-10-16 20:20 ` [PATCH v26 15/15] doc: add release note about log library Stephen Hemminger 2024-10-18 17:07 ` [PATCH v26 00/15] Log subsystem improvements David Marchand 2024-10-18 17:45 ` Stephen Hemminger 2024-10-20 7:16 ` Baruch Even 2024-10-24 3:18 ` [PATCH v27 00/14] Log subsystem changes Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 01/14] maintainers: add for log library Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 02/14] windows: make getopt functions have const properties Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 03/14] windows: update os shim Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 04/14] eal: make eal_log_level_parse common Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 05/14] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 06/14] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 07/14] log: move handling of syslog facility out of eal Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 08/14] eal: initialize log before everything else Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 09/14] log: add hook for printing log messages Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 10/14] log: modify syslog handling Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 11/14] log: add timestamp option Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 12/14] log: add support for systemd journal Stephen Hemminger 2024-10-24 3:18 ` [PATCH v27 13/14] log: colorize log output Stephen Hemminger 2024-10-25 15:49 ` Baruch Even 2024-10-24 3:18 ` [PATCH v27 14/14] doc: add release note about log library Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 00/13] Logging subsystem improvements Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 01/13] maintainers: add for log library Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 02/13] windows: make getopt functions have const properties Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 03/13] windows: update os shim Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 04/13] eal: make eal_log_level_parse common Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 05/13] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 06/13] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 07/13] log: rework syslog handling Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 08/13] eal: initialize log before everything else Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 09/13] log: add hook for printing log messages Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 10/13] log: add timestamp option Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 11/13] log: add support for systemd journal Stephen Hemminger 2024-10-25 15:33 ` Baruch Even 2024-10-25 15:56 ` Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 12/13] log: colorize log output Stephen Hemminger 2024-10-24 19:02 ` [PATCH v28 13/13] doc: add release note about log library Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 00/13] Logging subsystem enhancements Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 01/13] maintainers: add for log library Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 02/13] windows: make getopt functions have const properties Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 03/13] windows: update os shim Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 04/13] eal: make eal_log_level_parse common Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 05/13] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 06/13] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 07/13] log: rework syslog handling Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 08/13] eal: initialize log before everything else Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 09/13] log: add hook for printing log messages Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 10/13] log: add timestamp option Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 11/13] log: add support for systemd journal Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 12/13] log: colorize log output Stephen Hemminger 2024-10-25 21:45 ` [PATCH v29 13/13] doc: add release note about log library Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 00/13] Log library enhancements Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 01/13] maintainers: add for log library Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 02/13] windows: make getopt functions have const properties Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 03/13] windows: update os shim Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 04/13] eal: make eal_log_level_parse common Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 05/13] eal: do not duplicate rte_init_alert() messages Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 06/13] eal: change rte_exit() output to match rte_log() Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 07/13] log: rework syslog handling Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 08/13] eal: initialize log before everything else Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 09/13] log: add hook for printing log messages Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 10/13] log: add timestamp option Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 11/13] log: add support for systemd journal Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 12/13] log: colorize log output Stephen Hemminger 2024-10-27 17:24 ` [PATCH v30 13/13] doc: add release note about log library Stephen Hemminger
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).