@@ -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);
@@ -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
~~~~~~~~~~~~~
@@ -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"
@@ -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"
@@ -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,
new file mode 100644
@@ -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);
+}
@@ -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 */
@@ -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 */
@@ -4,6 +4,7 @@
includes += global_inc
sources = files(
'log.c',
+ 'log_color.c',
'log_timestamp.c',
)
@@ -25,6 +25,7 @@ DPDK_25 {
INTERNAL {
global:
+ eal_log_color;
eal_log_init;
eal_log_journal; # WINDOWS_NO_EXPORT
eal_log_level2str;