get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/138783/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 138783,
    "url": "http://patchwork.dpdk.org/api/patches/138783/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20240325205405.669897-14-stephen@networkplumber.org/",
    "project": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20240325205405.669897-14-stephen@networkplumber.org>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20240325205405.669897-14-stephen@networkplumber.org",
    "date": "2024-03-25T20:47:10",
    "name": "[v12,13/14] log: colorize log output",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "636db0d6f6e1b5be538ce4a18a76fc6b8f5bd8a9",
    "submitter": {
        "id": 27,
        "url": "http://patchwork.dpdk.org/api/people/27/?format=api",
        "name": "Stephen Hemminger",
        "email": "stephen@networkplumber.org"
    },
    "delegate": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20240325205405.669897-14-stephen@networkplumber.org/mbox/",
    "series": [
        {
            "id": 31616,
            "url": "http://patchwork.dpdk.org/api/series/31616/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=31616",
            "date": "2024-03-25T20:46:57",
            "name": "Logging unification and enhancements",
            "version": 12,
            "mbox": "http://patchwork.dpdk.org/series/31616/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/138783/comments/",
    "check": "success",
    "checks": "http://patchwork.dpdk.org/api/patches/138783/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 1525743D49;\n\tMon, 25 Mar 2024 21:55:45 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id B6DC9410E3;\n\tMon, 25 Mar 2024 21:54:36 +0100 (CET)",
            "from mail-pl1-f171.google.com (mail-pl1-f171.google.com\n [209.85.214.171])\n by mails.dpdk.org (Postfix) with ESMTP id 6435640E8A\n for <dev@dpdk.org>; Mon, 25 Mar 2024 21:54:30 +0100 (CET)",
            "by mail-pl1-f171.google.com with SMTP id\n d9443c01a7336-1def59b537cso30429885ad.2\n for <dev@dpdk.org>; Mon, 25 Mar 2024 13:54:30 -0700 (PDT)",
            "from hermes.local (204-195-123-203.wavecable.com. [204.195.123.203])\n by smtp.gmail.com with ESMTPSA id\n b18-20020a170903229200b001e0b5eee802sm3164487plh.123.2024.03.25.13.54.28\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Mon, 25 Mar 2024 13:54:29 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1711400069;\n x=1712004869; darn=dpdk.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=OOaaujGe+00hpSdaw3PAIH5SQJM8MJfQdAEByjbeKCo=;\n b=YojyvEaX9hrZA1x+vrL5WfF61Ls6E9W+WNMtUY3VELwisLvEuS2UhvfnI/oiyWdhMU\n ZqNhN9Gr4zZLGAiz7T1joeMMxSrhbr4ZGSVSCCAiMPGu8cs+P2FI6TTLTiM2lSs1c0jX\n CCs6NAzwedVKkOg7nNZrlbCCggT+xlz8a64MOZWUn7kzhTO4Z2QywagixlaPqcbplwrC\n CyVAFkP4RJxI3joDTIsEakx+E/EBc+KZJb5+t/Bt+x4na0R9xpxmhBmz9rHXIpU526hH\n Sef0Z1KjyzSscHG1x7h3HhjH0Wq7cHsPNPgv4X2FkzhW2AsDB9uvPEaz9Ts3xk+DugVx\n fY1A==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1711400069; x=1712004869;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n :subject:date:message-id:reply-to;\n bh=OOaaujGe+00hpSdaw3PAIH5SQJM8MJfQdAEByjbeKCo=;\n b=bs8E9UHy4s0I0LdG+xVHqj7zKOe+G/iQsvXti314eV6JHJb3UhwPeE5nFNxnbSVc+W\n qyvb1ZLoZfGQ4Hfgq/NUDqzv50Emxgoi1xm1ezPDDKtVuulohV+goTOiovadRVayXKkf\n PxoVy7lS1p3aXPg66Kcr3xI20km5lbFLQApDtewHTqG2nirq19KdhCrHPF541u7kPfiY\n tWhJyoYaubOygRJWoBjtGLFoEO4T6PAodXoMGnRxJ6LJok5in9zvD2tIuSvlagJFsVTG\n m6LR/HR2A77XU2VcmN0dstMjBuDZ05XVzRXiO5FDgcaKIeXtTs9w6v3VDv2G1R/K2RQr\n wiQA==",
        "X-Gm-Message-State": "AOJu0YzcRgP5Coiokre6G64l5F9f2F5PYxzQ/3ucu+Eed5q4FsKglhmr\n ZN835MKlMUEM0APJ2ziPCTSPkUWdhZGMRj5IHGB76VsFRrrbUIOLkuRd/tUXhC14arPHyMnbCjs\n i",
        "X-Google-Smtp-Source": "\n AGHT+IHjhaGck0/6Lk9bPD+wrZDyXpecevnjidmllq/KVDso0t+hzuWyWJ+lC7/wyKafaIWp1mw/ow==",
        "X-Received": "by 2002:a17:903:2308:b0:1e0:b862:5330 with SMTP id\n d8-20020a170903230800b001e0b8625330mr4987349plh.54.1711400069492;\n Mon, 25 Mar 2024 13:54:29 -0700 (PDT)",
        "From": "Stephen Hemminger <stephen@networkplumber.org>",
        "To": "dev@dpdk.org",
        "Cc": "Stephen Hemminger <stephen@networkplumber.org>",
        "Subject": "[PATCH v12 13/14] log: colorize log output",
        "Date": "Mon, 25 Mar 2024 13:47:10 -0700",
        "Message-ID": "<20240325205405.669897-14-stephen@networkplumber.org>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<20240325205405.669897-1-stephen@networkplumber.org>",
        "References": "<20200814173441.23086-1-stephen@networkplumber.org>\n <20240325205405.669897-1-stephen@networkplumber.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "Like dmesg, colorize the log output (unless redirected to file).\nTimestamp is green, the subsystem is in yellow and the message\nis red if urgent, boldface if an error, and normal for info and\ndebug messages.\n\nSigned-off-by: Stephen Hemminger <stephen@networkplumber.org>\n---\n doc/guides/prog_guide/log_lib.rst   |  16 ++-\n lib/eal/common/eal_common_options.c |   1 +\n lib/eal/common/eal_options.h        |   2 +\n lib/log/log.c                       | 158 +++++++++++++++++++++++++++-\n lib/log/log_internal.h              |   5 +\n lib/log/version.map                 |   1 +\n 6 files changed, 178 insertions(+), 5 deletions(-)",
    "diff": "diff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst\nindex abaedc7212..40727ebaae 100644\n--- a/doc/guides/prog_guide/log_lib.rst\n+++ b/doc/guides/prog_guide/log_lib.rst\n@@ -59,6 +59,21 @@ For example::\n \n Within an application, the same result can be got using the ``rte_log_set_level_pattern()`` or ``rte_log_set_level_regex()`` APIs.\n \n+Color output\n+~~~~~~~~~~~~\n+\n+The log library will highlight important messages.\n+This is controlled by the ``--log-color`` option.\n+he optional argument ``when`` can be ``auto``, ``never``, or ``always``.\n+The default setting is ``auto`` which enables color when the output to\n+``stderr`` is a terminal.\n+If the ``when`` argument is omitted, it defaults to ``always``.\n+\n+For example to turn off all coloring::\n+\n+\t/path/to/app --log-color=none\n+\n+\n Log timestamp\n ~~~~~~~~~~~~~\n \n@@ -101,7 +116,6 @@ option. There are three possible settings for this option:\n If ``--syslog`` option is not specified, then only console (stderr) will be used.\n \n \n-\n Using Logging APIs to Generate Log Messages\n -------------------------------------------\n \ndiff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c\nindex 6f0fd151c1..23b536b7a0 100644\n--- a/lib/eal/common/eal_common_options.c\n+++ b/lib/eal/common/eal_common_options.c\n@@ -75,6 +75,7 @@ eal_long_options[] = {\n \t{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },\n \t{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },\n \t{OPT_LOG_TIMESTAMP,     2, NULL, OPT_LOG_TIMESTAMP_NUM    },\n+\t{OPT_LOG_COLOR,\t\t1, NULL, OPT_LOG_COLOR_NUM\t  },\n \t{OPT_TRACE,             1, NULL, OPT_TRACE_NUM            },\n \t{OPT_TRACE_DIR,         1, NULL, OPT_TRACE_DIR_NUM        },\n \t{OPT_TRACE_BUF_SIZE,    1, NULL, OPT_TRACE_BUF_SIZE_NUM   },\ndiff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h\nindex e24c9eca53..5a63c1dd3a 100644\n--- a/lib/eal/common/eal_options.h\n+++ b/lib/eal/common/eal_options.h\n@@ -37,6 +37,8 @@ enum {\n \tOPT_LOG_LEVEL_NUM,\n #define OPT_LOG_TIMESTAMP     \"log-timestamp\"\n \tOPT_LOG_TIMESTAMP_NUM,\n+#define OPT_LOG_COLOR\t      \"log-color\"\n+\tOPT_LOG_COLOR_NUM,\n #define OPT_TRACE             \"trace\"\n \tOPT_TRACE_NUM,\n #define OPT_TRACE_DIR         \"trace-dir\"\ndiff --git a/lib/log/log.c b/lib/log/log.c\nindex 0f7bdb3f25..26a63024be 100644\n--- a/lib/log/log.c\n+++ b/lib/log/log.c\n@@ -23,6 +23,7 @@\n #include <sys/un.h>\n #endif\n \n+#include <rte_common.h>\n #include <rte_log.h>\n #include <rte_per_lcore.h>\n \n@@ -49,6 +50,12 @@ enum eal_log_syslog {\n \tEAL_LOG_SYSLOG_BOTH,\t\t/* log to both syslog and stderr */\n };\n \n+enum eal_log_color {\n+\tEAL_LOG_COLOR_AUTO = 0,\t/* default */\n+\tEAL_LOG_COLOR_NEVER,\n+\tEAL_LOG_COLOR_ALWAYS,\n+};\n+\n typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap);\n static int log_print(FILE *f, uint32_t level, const char *format, va_list ap);\n \n@@ -64,6 +71,7 @@ static struct rte_logs {\n #endif\n \tlog_print_t print_func;\n \n+\tenum eal_log_color color_mode;\n \tenum eal_log_time_format time_format;\n \tstruct timespec started;   /* when log was initialized */\n \tstruct timespec previous;  /* when last msg was printed */\n@@ -715,6 +723,74 @@ format_timestamp(char *tsbuf, size_t tsbuflen)\n \treturn 0;\n }\n \n+enum color {\n+\tCOLOR_NONE,\n+\tCOLOR_RED,\n+\tCOLOR_GREEN,\n+\tCOLOR_YELLOW,\n+\tCOLOR_BLUE,\n+\tCOLOR_MAGENTA,\n+\tCOLOR_CYAN,\n+\tCOLOR_WHITE,\n+\tCOLOR_BOLD,\n+\tCOLOR_CLEAR\n+};\n+\n+static const char * const color_code[] = {\n+\t[COLOR_NONE]\t= \"\",\n+\t[COLOR_RED]\t= \"\\e[31m\",\n+\t[COLOR_GREEN]\t= \"\\e[32m\",\n+\t[COLOR_YELLOW]\t= \"\\e[33m\",\n+\t[COLOR_BLUE]\t= \"\\e[34m\",\n+\t[COLOR_MAGENTA] = \"\\e[35m\",\n+\t[COLOR_CYAN]    = \"\\e[36m\",\n+\t[COLOR_WHITE]\t= \"\\e[37m\",\n+\t[COLOR_BOLD]\t= \"\\e[1m\",\n+\t[COLOR_CLEAR]\t= \"\\e[0m\",\n+};\n+\n+__rte_format_printf(3, 4)\n+static int color_fprintf(FILE *out, enum color color, const char *fmt, ...)\n+{\n+\tva_list args;\n+\tint ret = 0;\n+\n+\tva_start(args, fmt);\n+\tret = fprintf(out, \"%s\", color_code[color]);\n+\tret += vfprintf(out, fmt, args);\n+\tret += fprintf(out, \"%s\", color_code[COLOR_CLEAR]);\n+\n+\treturn ret;\n+}\n+\n+static ssize_t\n+color_log_write(FILE *f, int level, char *msg)\n+{\n+\tchar *cp;\n+\tssize_t ret = 0;\n+\n+\t/*\n+\t * use convention that first part of message (up to the ':' character)\n+\t * is the subsystem id and should be highlighted.\n+\t */\n+\tcp = strchr(msg, ':');\n+\tif (cp) {\n+\t\t/* print first part in yellow */\n+\t\tret = color_fprintf(stderr, COLOR_YELLOW, \"%.*s\",\n+\t\t\t\t    (int)(cp - msg + 1), msg);\n+\t\tmsg = cp + 1;\n+\t}\n+\n+\tif (level <= 0 || level >= (int)RTE_LOG_INFO)\n+\t\tret += fprintf(f, \"%s\", msg);\n+\telse if (level >= (int)RTE_LOG_ERR)\n+\t\tret += color_fprintf(f, COLOR_BOLD, \"%s\", msg);\n+\telse\n+\t\tret += color_fprintf(f, COLOR_RED, \"%s\", msg);\n+\n+\treturn ret;\n+}\n+\n /* default log print function */\n __rte_format_printf(3, 0)\n static int\n@@ -871,16 +947,79 @@ open_journal(const char *id)\n }\n #endif\n \n+__rte_format_printf(3, 0)\n+static int\n+color_print(FILE *f, uint32_t level, const char *format, va_list ap)\n+{\n+\tchar *buf = NULL;\n+\n+\t/* need to make temporary buffer for color scan */\n+\tif (vasprintf(&buf, format, ap) > 0)\n+\t\treturn color_log_write(f, level, buf);\n+\n+\t/* if vasprintf fails, print without color */\n+\treturn log_print(f, level, format, ap);\n+}\n+\n+__rte_format_printf(3, 0)\n+static int\n+color_print_with_timestamp(FILE *f, uint32_t level,\n+\t\t\t   const char *format, va_list ap)\n+{\n+\tchar tsbuf[128];\n+\n+\tif (format_timestamp(tsbuf, sizeof(tsbuf)) > 0)\n+\t\tcolor_fprintf(f, COLOR_GREEN, \"[%s] \", tsbuf);\n+\n+\treturn color_print(f, level, format, ap);\n+}\n+\n+/*\n+ * Controls whether color is enabled:\n+ * modes are:\n+ *   always - enable color output regardless\n+ *   auto - enable if stderr is a terminal\n+ *   never - color output is disabled.\n+ */\n+int\n+eal_log_color(const char *mode)\n+{\n+\tif (mode == NULL || strcmp(mode, \"always\") == 0)\n+\t\trte_logs.color_mode = EAL_LOG_COLOR_ALWAYS;\n+\telse if (strcmp(mode, \"never\") == 0)\n+\t\trte_logs.color_mode = EAL_LOG_COLOR_NEVER;\n+\telse if (strcmp(mode, \"auto\") == 0)\n+\t\trte_logs.color_mode = EAL_LOG_COLOR_AUTO;\n+\telse\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n+static inline bool\n+use_color(bool is_terminal)\n+{\n+\tswitch (rte_logs.color_mode) {\n+\tdefault:\n+\tcase EAL_LOG_COLOR_NEVER:\n+\t\treturn false;\n+\tcase EAL_LOG_COLOR_ALWAYS:\n+\t\treturn true;\n+\tcase EAL_LOG_COLOR_AUTO:\n+\t\treturn is_terminal;\n+\t}\n+\n+}\n \n /* Choose how log output is directed */\n static void\n log_output_selection(const char *id)\n {\n+\tbool is_terminal = isatty(STDERR_FILENO);\n+\n #ifdef RTE_EXEC_ENV_WINDOWS\n \tRTE_SET_USED(id);\n #else\n-\tbool is_terminal = isatty(STDERR_FILENO);\n-\n \t/* If stderr is redirected to systemd journal then upgrade */\n \tif (using_journal()) {\n \t\tint jfd = open_journal(id);\n@@ -911,8 +1050,19 @@ log_output_selection(const char *id)\n \t\treturn;\n \t}\n #endif\n-\tif (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE)\n-\t\trte_logs.print_func = log_print_with_timestamp;\n+\n+\tif (use_color(is_terminal)) {\n+\t\tif (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE)\n+\t\t\trte_logs.print_func = color_print;\n+\t\telse\n+\t\t\trte_logs.print_func = color_print_with_timestamp;\n+\t} else {\n+\t\tif (rte_logs.time_format == EAL_LOG_TIMESTAMP_NONE)\n+\t\t\trte_logs.print_func = log_print;\n+\t\telse\n+\t\t\trte_logs.print_func = log_print_with_timestamp;\n+\t}\n+\n }\n \n /*\ndiff --git a/lib/log/log_internal.h b/lib/log/log_internal.h\nindex 7c7d44eed2..525e1397fd 100644\n--- a/lib/log/log_internal.h\n+++ b/lib/log/log_internal.h\n@@ -47,5 +47,10 @@ void rte_eal_log_cleanup(void);\n __rte_internal\n int eal_log_timestamp(const char *fmt);\n \n+/*\n+ * Enable or disable color in log messages\n+ */\n+__rte_internal\n+int eal_log_color(const char *mode);\n \n #endif /* LOG_INTERNAL_H */\ndiff --git a/lib/log/version.map b/lib/log/version.map\nindex 14d6681a5f..7fa79b20ff 100644\n--- a/lib/log/version.map\n+++ b/lib/log/version.map\n@@ -25,6 +25,7 @@ DPDK_24 {\n INTERNAL {\n \tglobal:\n \n+\teal_log_color;\n \teal_log_init;\n \teal_log_level2str;\n \teal_log_save_pattern;\n",
    "prefixes": [
        "v12",
        "13/14"
    ]
}