get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 138666,
    "url": "http://patches.dpdk.org/api/patches/138666/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20240321161146.340421-10-stephen@networkplumber.org/",
    "project": {
        "id": 1,
        "url": "http://patches.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": "<20240321161146.340421-10-stephen@networkplumber.org>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20240321161146.340421-10-stephen@networkplumber.org",
    "date": "2024-03-21T16:00:25",
    "name": "[v10,09/10] log: colorize log output",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b5494511d0b606947c4a7408c51b27591a2e2c44",
    "submitter": {
        "id": 27,
        "url": "http://patches.dpdk.org/api/people/27/?format=api",
        "name": "Stephen Hemminger",
        "email": "stephen@networkplumber.org"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20240321161146.340421-10-stephen@networkplumber.org/mbox/",
    "series": [
        {
            "id": 11658,
            "url": "http://patches.dpdk.org/api/series/11658/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=11658",
            "date": "2020-08-14T17:34:41",
            "name": "eal: add option to put timestamp on console output",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/11658/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/138666/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/138666/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 D272043D17;\n\tThu, 21 Mar 2024 17:18:11 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id B7B2B42DC3;\n\tThu, 21 Mar 2024 17:18:11 +0100 (CET)",
            "from mail-il1-f175.google.com (mail-il1-f175.google.com\n [209.85.166.175])\n by mails.dpdk.org (Postfix) with ESMTP id C320B427E1\n for <dev@dpdk.org>; Thu, 21 Mar 2024 17:18:10 +0100 (CET)",
            "by mail-il1-f175.google.com with SMTP id\n e9e14a558f8ab-3667770b8e8so5259695ab.0\n for <dev@dpdk.org>; Thu, 21 Mar 2024 09:18:10 -0700 (PDT)",
            "from hermes.local (204-195-123-203.wavecable.com. [204.195.123.203])\n by smtp.gmail.com with ESMTPSA id\n w62-20020a638241000000b005e485fbd455sm41815pgd.45.2024.03.21.09.12.02\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Thu, 21 Mar 2024 09:12:03 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1711037890;\n x=1711642690; 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=hqeA3Z23W4oIs9rPBGRyEAa5ziQrrAlyT6cOMR/IRh4=;\n b=xmB3WlkZHTRcBiP0UGDeGDCER4s5eXYuwiXL3A7KLqBQHRbWRMhbkwLaFbBgQKHJsH\n QOv3ftSohVP8ibj/RhfD4Y58Cz04hnRtHMO1dWjGkaDFmxbz/wgxtck+iRFcIzlp0sz7\n hIZT4CfSTnKZ3azcCY0p6s3OlI7HBLuEy90bslNRPmTDHsOgZcI616BQBdqf2zcSiJhn\n odVjCNaGfB4FLkeKZgD8exJCUhy+xX4HrUzDbNswBCKc8RVZy8Mqd9icaquwowewE7On\n HBOUIDLV+kYd5OxhSRkz/I8ibEheLjlDkjPVYGYeZUXgVKcyG2XsZcdirI2pMA7hm9c4\n DGMQ==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1711037890; x=1711642690;\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=hqeA3Z23W4oIs9rPBGRyEAa5ziQrrAlyT6cOMR/IRh4=;\n b=QaHiJukyODUoPx4Ip9dkxsCqvptG4ob3AfbFvmR/gSViCtv0ILTbfrSHYA0EvMPboI\n GfXo0opxHQCUOPDBpMibvt1Xp8WiAU5boOTgOyuajsBIJ2YtLclIFsksXARVPFk+cRMn\n ex39BeLPFeM1v0wsNpwZtqpoH+qS5Cz0rVToMhF0UR/uynGSoMOTaAu9+eIdr0ToyRa+\n xmyY8QRnH/mc3INrTnWjbH5SAUT9lUrAidajNXH9KlL8ApVzVgt/1ZUNbMMA1d9DPOpf\n SlF26Mh0j8YDHpwtjoqQp6ZUYMNFDFiagr8l8bdhmq3JRivFaoPkybBawINcwxKA7SJg\n uE+Q==",
        "X-Gm-Message-State": "AOJu0YxsK2re/WukUaNT/nzlkQ6vUuGHsIQnGrjUizLzel54p/a9DUke\n dUna33MMLZms8yKU2sJQiPM8b28XHM8fb1s/155wnXhgE7Dvb9qIL6a1eDNZqt1qG/U3UZvD9FP\n 7",
        "X-Google-Smtp-Source": "\n AGHT+IGHtaDJDZ0pm0a43uDe66akgR1s1xQHZZt8UiuJygLdpGIKY5Gm6hGwU1pKxIViFnHerwWzfQ==",
        "X-Received": "by 2002:a05:6a20:dda4:b0:1a3:3c9b:182 with SMTP id\n kw36-20020a056a20dda400b001a33c9b0182mr5368109pzb.57.1711037523643;\n Thu, 21 Mar 2024 09:12:03 -0700 (PDT)",
        "From": "Stephen Hemminger <stephen@networkplumber.org>",
        "To": "dev@dpdk.org",
        "Cc": "Stephen Hemminger <stephen@networkplumber.org>",
        "Subject": "[PATCH v10 09/10] log: colorize log output",
        "Date": "Thu, 21 Mar 2024 09:00:25 -0700",
        "Message-ID": "<20240321161146.340421-10-stephen@networkplumber.org>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<20240321161146.340421-1-stephen@networkplumber.org>",
        "References": "<20200814173441.23086-1-stephen@networkplumber.org>\n <20240321161146.340421-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 lib/eal/common/eal_common_options.c |  10 +++\n lib/eal/common/eal_options.h        |   2 +\n lib/log/log_internal.h              |   5 ++\n lib/log/log_unix.c                  | 132 +++++++++++++++++++++++++---\n lib/log/log_windows.c               |   6 ++\n lib/log/version.map                 |   1 +\n 6 files changed, 146 insertions(+), 10 deletions(-)",
    "diff": "diff --git a/lib/eal/common/eal_common_options.c b/lib/eal/common/eal_common_options.c\nindex 4e2c3d0f255c..522634f1dcfa 100644\n--- a/lib/eal/common/eal_common_options.c\n+++ b/lib/eal/common/eal_common_options.c\n@@ -78,6 +78,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   },\n@@ -1910,6 +1911,15 @@ eal_parse_common_option(int opt, const char *optarg,\n \t\t}\n \t\tbreak;\n \n+\n+\tcase OPT_LOG_COLOR_NUM:\n+\t\tif (eal_log_color(optarg) < 0) {\n+\t\t\tEAL_LOG(ERR, \"invalid parameters for --\"\n+\t\t\t\tOPT_LOG_COLOR);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tbreak;\n+\n \tcase OPT_TRACE_NUM: {\n \t\tif (eal_trace_args_save(optarg) < 0) {\n \t\t\tEAL_LOG(ERR, \"invalid parameters for --\"\ndiff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h\nindex e24c9eca53ca..5a63c1dd3a32 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_internal.h b/lib/log/log_internal.h\nindex 0e18d147cf98..b90c668f4668 100644\n--- a/lib/log/log_internal.h\n+++ b/lib/log/log_internal.h\n@@ -52,5 +52,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/log_unix.c b/lib/log/log_unix.c\nindex cb8f17bc83ef..1af93795fec5 100644\n--- a/lib/log/log_unix.c\n+++ b/lib/log/log_unix.c\n@@ -11,6 +11,7 @@\n #include <time.h>\n #include <unistd.h>\n \n+#include <rte_common.h>\n #include <rte_log.h>\n \n #include \"log_internal.h\"\n@@ -24,15 +25,113 @@ enum eal_log_time_format {\n \tEAL_LOG_TIMESTAMP_ISO,\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 static struct {\n+\tenum eal_log_color color_mode;\n \tenum eal_log_time_format time_format;\n+\tbool show_color;\n \tstruct timespec start_time;\n \tstruct timespec last_time;\n \tstruct tm last_tm;\n } log = {\n+\t.color_mode = EAL_LOG_COLOR_AUTO,\n \t.time_format = EAL_LOG_TIMESTAMP_NONE,\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, const char *msg, size_t size)\n+{\n+\tsize_t i;\n+\tssize_t ret = 0;\n+\n+\t/* find first : delimiter in message */\n+\tfor (i = 0; i < size; i++) {\n+\t\tif (msg[i] == ':') {\n+\t\t\t++i;  /* put colon in the color */\n+\t\t\tret = color_fprintf(stderr, COLOR_YELLOW, \"%.*s\", (int)i, msg);\n+\t\t\tmsg += i;\n+\t\t\tsize -= i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (level <= 0 || level >= (int)RTE_LOG_INFO)\n+\t\tret += fprintf(f, \"%.*s\", (int)size, msg);\n+\telse if (level >= (int)RTE_LOG_ERR)\n+\t\tret += color_fprintf(f, COLOR_BOLD, \"%.*s\", (int)size, msg);\n+\telse\n+\t\tret += color_fprintf(f, COLOR_RED, \"%.*s\", (int)size, msg);\n+\n+\treturn ret;\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\tlog.color_mode = EAL_LOG_COLOR_ALWAYS;\n+\telse if (strcmp(mode, \"never\") == 0)\n+\t\tlog.color_mode = EAL_LOG_COLOR_NEVER;\n+\telse if (strcmp(mode, \"auto\") == 0)\n+\t\tlog.color_mode = EAL_LOG_COLOR_AUTO;\n+\telse\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n int\n eal_log_timestamp(const char *str)\n {\n@@ -153,18 +252,28 @@ console_log_timestamp(char *tsbuf, size_t tsbuflen)\n static ssize_t\n console_log_write(__rte_unused void *c, const char *msg, size_t size)\n {\n-\tchar buf[128];\n+\tint level = rte_log_cur_msg_loglevel();\n+\tchar tsbuf[128] = \"\";\n \tssize_t ret;\n \n-\tret = console_log_timestamp(buf, sizeof(buf));\n-\tif (ret == 0)\n-\t\tret = fwrite(msg, 1, size, stderr);\n-\telse\n-\t\tret = fprintf(stderr, \"[%s] %.*s\", buf, (int)size, msg);\n+\tret = console_log_timestamp(tsbuf, sizeof(tsbuf));\n+\tif (ret == 0) {\n+\t\tif (log.show_color)\n+\t\t\tret = color_log_write(stderr, level, msg, size);\n+\t\telse\n+\t\t\tret = fwrite(msg, 1, size, stderr);\n+\t} else {\n+\t\tif (log.show_color) {\n+\t\t\tcolor_fprintf(stderr, COLOR_GREEN, \"[%s] \", tsbuf);\n+\t\t\tret = color_log_write(stderr, level, msg, size);\n+\t\t} else {\n+\t\t\tret = fprintf(stderr, \"[%s] %.*s\", tsbuf, (int)size, msg);\n+\t\t}\n+\t}\n \tfflush(stderr);\n \n \t/* Syslog error levels are from 0 to 7, so subtract 1 to convert */\n-\tsyslog(rte_log_cur_msg_loglevel() - 1, \"%.*s\", (int)size, msg);\n+\tsyslog(level - 1, \"%.*s\", (int)size, msg);\n \n \treturn ret;\n }\n@@ -190,13 +299,16 @@ eal_log_init(const char *id, int facility)\n {\n \tFILE *log_stream;\n \n-\tclock_gettime(CLOCK_MONOTONIC, &log.start_time);\n-\tlog.last_time = log.start_time;\n-\n \t/* skip if user has already setup a log stream */\n \tif (eal_log_get_default())\n \t\treturn 0;\n \n+\tlog.show_color = (log.color_mode == EAL_LOG_COLOR_ALWAYS) ||\n+\t\t(log.color_mode == EAL_LOG_COLOR_AUTO && isatty(STDERR_FILENO));\n+\n+\tclock_gettime(CLOCK_MONOTONIC, &log.start_time);\n+\tlog.last_time = log.start_time;\n+\n \tlog_stream = fopencookie(NULL, \"w+\", console_log_func);\n \tif (log_stream == NULL)\n \t\treturn -1;\ndiff --git a/lib/log/log_windows.c b/lib/log/log_windows.c\nindex 8aa68a181bec..1cb72f519a91 100644\n--- a/lib/log/log_windows.c\n+++ b/lib/log/log_windows.c\n@@ -12,6 +12,12 @@ eal_log_timestamp(__rte_unused const char *fmt)\n \treturn -1; /* not implemented */\n }\n \n+int\n+eal_log_color(__rte_unused const char *mode)\n+{\n+\treturn -1; /* not implemented */\n+}\n+\n /* set the log to default function, called during eal init process. */\n int\n eal_log_init(__rte_unused const char *id, __rte_unused int facility)\ndiff --git a/lib/log/version.map b/lib/log/version.map\nindex 697cdb3cb1b2..1fe6955427b7 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_get_default;\n \teal_log_init;\n \teal_log_level2str;\n",
    "prefixes": [
        "v10",
        "09/10"
    ]
}