get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 138760,
    "url": "http://patches.dpdk.org/api/patches/138760/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20240324024109.306614-8-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": "<20240324024109.306614-8-stephen@networkplumber.org>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20240324024109.306614-8-stephen@networkplumber.org",
    "date": "2024-03-24T02:33:29",
    "name": "[v11,7/9] log: add timestamp option",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "02e04533ba834f22bfefcb8857219170a39ab795",
    "submitter": {
        "id": 27,
        "url": "http://patches.dpdk.org/api/people/27/?format=api",
        "name": "Stephen Hemminger",
        "email": "stephen@networkplumber.org"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20240324024109.306614-8-stephen@networkplumber.org/mbox/",
    "series": [
        {
            "id": 31607,
            "url": "http://patches.dpdk.org/api/series/31607/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=31607",
            "date": "2024-03-24T02:33:22",
            "name": "Logging unification and enhancements",
            "version": 11,
            "mbox": "http://patches.dpdk.org/series/31607/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/138760/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/138760/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 21CD143D36;\n\tSun, 24 Mar 2024 03:42:15 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id D1D764069F;\n\tSun, 24 Mar 2024 03:41:32 +0100 (CET)",
            "from mail-pj1-f53.google.com (mail-pj1-f53.google.com\n [209.85.216.53]) by mails.dpdk.org (Postfix) with ESMTP id B58B2402EC\n for <dev@dpdk.org>; Sun, 24 Mar 2024 03:41:26 +0100 (CET)",
            "by mail-pj1-f53.google.com with SMTP id\n 98e67ed59e1d1-29de4c33441so2337750a91.1\n for <dev@dpdk.org>; Sat, 23 Mar 2024 19:41:26 -0700 (PDT)",
            "from hermes.local (204-195-123-203.wavecable.com. [204.195.123.203])\n by smtp.gmail.com with ESMTPSA id\n q17-20020a17090311d100b001dc3c4e7a12sm2244980plh.14.2024.03.23.19.41.25\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Sat, 23 Mar 2024 19:41:25 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1711248086;\n x=1711852886; 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=KMFs2nnZQjuUChC7i9aa4h6YtbRdRwzjMnZM5qcjWqY=;\n b=U2N5SLEK+6Q5gVCOzH2HwAomBMst83XK6/5F0ph8Zaa9X/jpbWu3JFtT4ZZ7htznfJ\n JOycA3Rha5uhT8hZ6bbNcLhKDVN0Y9rVae5c1onpL2OOsLBAene2vVf1ovhmIUAUzIam\n 6W61R5EGEnuM4E6fvb7Er3my9MniE4GYSWxPEnEDMpfmUsMjrPLCxYcQ4CvU8EBDGLKM\n Z9/vMTH9/icY5TuiNOKPbGGN7JX3Igci2VZqaNtZL/0kIn/wytee/uXTafBXnJpNVDeb\n lEC+sy8rxfn9O8MBhFZAcwQq7Wm460L1UI6Q2fvDn3aIknIMmZwXZAJrLYSnXtTpPGMI\n ZSoQ==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1711248086; x=1711852886;\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=KMFs2nnZQjuUChC7i9aa4h6YtbRdRwzjMnZM5qcjWqY=;\n b=bwmE/BXqhBVL+sCAkOpVO+CuC2Gpp9XzgVN4gGkABpL6birck2pjTYpi7mWtA0JVMC\n Q1uYCXx446wjOdbaI0Zqvub/s2+Emcham6oaPVMMLp8HafFPf1bJMxSYqx8PG5+zcFH+\n P6zKKvS0MF5BQijaYGjaxfw/N9c7RuqjUlO0Di4fo8QtOnp2wjGqZaMbPYMd2CH6Ck7I\n uigSkG1vawg6XdR81+EmVp6H7DLaZdrFf7SYArra8qJsyoJHeysTpH9eXh1/hw/5gUVI\n pg9rq1Jhm8wfpb6rtvjCRC8xoe0YR4FmgqLruqzlYEgeWhNk8Lk01AEeoyGLXQDaqXa7\n kJ4g==",
        "X-Gm-Message-State": "AOJu0YwgKButONUkiJ9HsitisJA0nev5kkkIWnAwlQOf+BbNgz0lACBC\n UW0SVgj/c5wq/nKwzKzz+5UEEd8t1YYShnV+yJKW6cWl3qnTlWx14y4IP4FMN4qQha0pjg3c6rn\n F",
        "X-Google-Smtp-Source": "\n AGHT+IH+gwzOM+SwucIHLDpTB1zs9pHHoGcuuo6q0q5Pu097fJB2KPNhwQbb7o0WduGQ490GLYpEKw==",
        "X-Received": "by 2002:a05:6a20:7344:b0:1a3:c4ea:f528 with SMTP id\n v4-20020a056a20734400b001a3c4eaf528mr115537pzc.43.1711248085879;\n Sat, 23 Mar 2024 19:41:25 -0700 (PDT)",
        "From": "Stephen Hemminger <stephen@networkplumber.org>",
        "To": "dev@dpdk.org",
        "Cc": "Stephen Hemminger <stephen@networkplumber.org>",
        "Subject": "[PATCH v11 7/9] log: add timestamp option",
        "Date": "Sat, 23 Mar 2024 19:33:29 -0700",
        "Message-ID": "<20240324024109.306614-8-stephen@networkplumber.org>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<20240324024109.306614-1-stephen@networkplumber.org>",
        "References": "<20200814173441.23086-1-stephen@networkplumber.org>\n <20240324024109.306614-1-stephen@networkplumber.org>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "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": "When debugging driver or startup issues, it is useful to have\na timestamp on each message printed. The messages in syslog\nalready have a timestamp, but often syslog is not available\nduring testing.\n\nThere are multiple timestamp formats similar to Linux dmesg.\nThe default is time relative since startup (when first\nstep of logging initialization is done by constructor).\nOther alternative formats are delta, ctime, reltime and iso formats.\n\nExample:\n$ dpdk-testpmd --log-timestamp -- -i\n[     0.008610] EAL: Detected CPU lcores: 8\n[     0.008634] EAL: Detected NUMA nodes: 1\n[     0.008792] EAL: Detected static linkage of DPDK\n[     0.010620] EAL: Multi-process socket /var/run/dpdk/rte/mp_socket\n[     0.012618] EAL: Selected IOVA mode 'VA'\n[     0.016675] testpmd: No probed ethernet devices\nInteractive-mode selected\n\nSigned-off-by: Stephen Hemminger <stephen@networkplumber.org>\n---\n app/test/test_eal_flags.c           |  17 +++\n doc/guides/prog_guide/log_lib.rst   |  26 +++++\n lib/eal/common/eal_common_options.c |  14 ++-\n lib/eal/common/eal_options.h        |   2 +\n lib/log/log.c                       | 168 +++++++++++++++++++++++++++-\n lib/log/log_internal.h              |   9 ++\n lib/log/version.map                 |   1 +\n 7 files changed, 234 insertions(+), 3 deletions(-)",
    "diff": "diff --git a/app/test/test_eal_flags.c b/app/test/test_eal_flags.c\nindex bea5465168..def74e34d5 100644\n--- a/app/test/test_eal_flags.c\n+++ b/app/test/test_eal_flags.c\n@@ -1048,6 +1048,14 @@ test_misc_flags(void)\n \tconst char * const argv22[] = {prgname, prefix, mp_flag,\n \t\t\t\t       \"--huge-worker-stack=512\"};\n \n+\t/* Try running with --log-timestamp */\n+\tconst char * const argv23[] = {prgname, prefix, mp_flag,\n+\t\t\t\t       \"--log-timestamp\" };\n+\n+\t/* Try running with --log-timestamp=iso */\n+\tconst char * const argv24[] = {prgname, prefix, mp_flag,\n+\t\t\t\t       \"--log-timestamp=iso\" };\n+\n \t/* run all tests also applicable to FreeBSD first */\n \n \tif (launch_proc(argv0) == 0) {\n@@ -1143,6 +1151,15 @@ test_misc_flags(void)\n \t\tprintf(\"Error - process did not run ok with --huge-worker-stack=size parameter\\n\");\n \t\tgoto fail;\n \t}\n+\tif (launch_proc(argv23) != 0) {\n+\t\tprintf(\"Error - process did not run ok with --log-timestamp parameter\\n\");\n+\t\tgoto fail;\n+\t}\n+\tif (launch_proc(argv24) != 0) {\n+\t\tprintf(\"Error - process did not run ok with --log-timestamp=iso parameter\\n\");\n+\t\tgoto fail;\n+\t}\n+\n \n \trmdir(hugepath_dir3);\n \trmdir(hugepath_dir2);\ndiff --git a/doc/guides/prog_guide/log_lib.rst b/doc/guides/prog_guide/log_lib.rst\nindex 17ed8426b2..83949cce35 100644\n--- a/doc/guides/prog_guide/log_lib.rst\n+++ b/doc/guides/prog_guide/log_lib.rst\n@@ -58,6 +58,32 @@ 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+Console timestamp\n+~~~~~~~~~~~~~~~~~\n+\n+An optional timestamp can be added before each message when printing on the console\n+by adding the ``--log-timestamp`` option.\n+For example::\n+\n+\t/path/to/app --log-level=lib.*:debug --log-timestamp\n+\n+Multiple timestamp alternative timestamp formats are available:\n+\n+.. csv-table:: Log time stamp format\n+   :header: \"Format\", \"Description\", \"Example\"\n+   :widths: 6, 30, 32\n+\n+   \"ctime\", \"Unix ctime\", \"``[Wed Mar 20 07:26:12 2024]``\"\n+   \"delta\", \"Offset since last\", \"``[<    3.162373>]``\"\n+   \"reltime\", \"Seconds since last or time if minute changed\", \"``[  +3.001791]`` or ``[Mar20 07:26:12]``\"\n+   \"iso\", \"ISO-8601\", \"``[2024-03-20T07:26:12−07:00]``\"\n+\n+To prefix all console messages with ISO format time the syntax is::\n+\n+\t/path/to/app --log-timestamp=iso\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 73167d4603..bc6d87266d 100644\n--- a/lib/eal/common/eal_common_options.c\n+++ b/lib/eal/common/eal_common_options.c\n@@ -74,6 +74,7 @@ eal_long_options[] = {\n \t{OPT_IOVA_MODE,\t        1, NULL, OPT_IOVA_MODE_NUM        },\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_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@@ -1614,6 +1615,7 @@ eal_log_level_parse(int argc, char * const argv[])\n \n \t\tswitch (opt) {\n \t\tcase OPT_LOG_LEVEL_NUM:\n+\t\tcase OPT_LOG_TIMESTAMP_NUM:\n \t\t\tif (eal_parse_common_option(opt, optarg, internal_conf) < 0)\n \t\t\t\treturn -1;\n \t\t\tbreak;\n@@ -1831,7 +1833,7 @@ eal_parse_common_option(int opt, const char *optarg,\n \t\t}\n \t\tbreak;\n \n-\tcase OPT_LOG_LEVEL_NUM: {\n+\tcase OPT_LOG_LEVEL_NUM:\n \t\tif (eal_parse_log_level(optarg) < 0) {\n \t\t\tEAL_LOG(ERR,\n \t\t\t\t\"invalid parameters for --\"\n@@ -1839,7 +1841,14 @@ eal_parse_common_option(int opt, const char *optarg,\n \t\t\treturn -1;\n \t\t}\n \t\tbreak;\n-\t}\n+\n+\tcase OPT_LOG_TIMESTAMP_NUM:\n+\t\tif (eal_log_timestamp(optarg) < 0) {\n+\t\t\tEAL_LOG(ERR, \"invalid parameters for --\"\n+\t\t\t\tOPT_LOG_TIMESTAMP);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tbreak;\n \n #ifndef RTE_EXEC_ENV_WINDOWS\n \tcase OPT_TRACE_NUM: {\n@@ -2204,6 +2213,7 @@ eal_common_usage(void)\n \t       \"  --\"OPT_LOG_LEVEL\"=<type-match>:<level>\\n\"\n \t       \"                      Set specific log level\\n\"\n \t       \"  --\"OPT_LOG_LEVEL\"=help    Show log types and levels\\n\"\n+\t       \"  --\"OPT_LOG_TIMESTAMP\"     Timestamp log output\\n\"\n #ifndef RTE_EXEC_ENV_WINDOWS\n \t       \"  --\"OPT_TRACE\"=<regex-match>\\n\"\n \t       \"                      Enable trace based on regular expression trace name.\\n\"\ndiff --git a/lib/eal/common/eal_options.h b/lib/eal/common/eal_options.h\nindex 6b204d6698..197b7b25ef 100644\n--- a/lib/eal/common/eal_options.h\n+++ b/lib/eal/common/eal_options.h\n@@ -35,6 +35,8 @@ enum {\n \tOPT_LCORES_NUM,\n #define OPT_LOG_LEVEL         \"log-level\"\n \tOPT_LOG_LEVEL_NUM,\n+#define OPT_LOG_TIMESTAMP     \"log-timestamp\"\n+\tOPT_LOG_TIMESTAMP_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 4cc871911c..bd488dff1b 100644\n--- a/lib/log/log.c\n+++ b/lib/log/log.c\n@@ -11,6 +11,7 @@\n #include <regex.h>\n #include <fnmatch.h>\n #include <sys/queue.h>\n+#include <unistd.h>\n \n #include <rte_log.h>\n #include <rte_per_lcore.h>\n@@ -18,7 +19,7 @@\n #include \"log_internal.h\"\n \n #ifdef RTE_EXEC_ENV_WINDOWS\n-#define strdup _strdup\n+#include <rte_os_shim.h>\n #endif\n \n struct rte_log_dynamic_type {\n@@ -26,6 +27,15 @@ struct rte_log_dynamic_type {\n \tuint32_t loglevel;\n };\n \n+enum eal_log_time_format {\n+\tEAL_LOG_TIMESTAMP_NONE = 0,\n+\tEAL_LOG_TIMESTAMP_TIME,\t\t/* time since start */\n+\tEAL_LOG_TIMESTAMP_DELTA,\t/* time since last message */\n+\tEAL_LOG_TIMESTAMP_RELTIME,\n+\tEAL_LOG_TIMESTAMP_CTIME,\n+\tEAL_LOG_TIMESTAMP_ISO,\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@@ -35,6 +45,12 @@ static struct rte_logs {\n \tuint32_t level; /**< Log level. */\n \tFILE *file;     /**< Output file set by rte_openlog_stream, or NULL. */\n \tlog_print_t print_func;\n+\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+\tstruct tm last_tm;\t   /*  in local time format */\n+\n \tsize_t dynamic_types_len;\n \tstruct rte_log_dynamic_type *dynamic_types;\n } rte_logs = {\n@@ -362,6 +378,9 @@ RTE_INIT_PRIO(log_init, LOG)\n {\n \tuint32_t i;\n \n+\tclock_gettime(CLOCK_MONOTONIC, &rte_logs.started);\n+\trte_logs.previous = rte_logs.started;\n+\n \trte_log_set_global_level(RTE_LOG_DEBUG);\n \n \trte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID,\n@@ -513,6 +532,132 @@ rte_eal_log_cleanup(void)\n \t}\n }\n \n+/* Set the log timestamp format */\n+int\n+eal_log_timestamp(const char *str)\n+{\n+\tif (str == NULL)\n+\t\trte_logs.time_format = EAL_LOG_TIMESTAMP_TIME;\n+\telse if (strcmp(str, \"notime\") == 0)\n+\t\trte_logs.time_format = EAL_LOG_TIMESTAMP_NONE;\n+\telse if (strcmp(str, \"reltime\") == 0)\n+\t\trte_logs.time_format = EAL_LOG_TIMESTAMP_RELTIME;\n+\telse if (strcmp(str, \"delta\") == 0)\n+\t\trte_logs.time_format = EAL_LOG_TIMESTAMP_DELTA;\n+\telse if (strcmp(str, \"ctime\") == 0)\n+\t\trte_logs.time_format =  EAL_LOG_TIMESTAMP_CTIME;\n+\telse if (strcmp(str, \"iso\") == 0)\n+\t\trte_logs.time_format = EAL_LOG_TIMESTAMP_ISO;\n+\telse\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n+/* Subtract two timespec values and handle wraparound */\n+static struct timespec\n+timespec_sub(const struct timespec *t0, const struct timespec *t1)\n+{\n+\tstruct timespec ts;\n+\n+\tts.tv_sec = t0->tv_sec - t1->tv_sec;\n+\tts.tv_nsec = t0->tv_nsec - t1->tv_nsec;\n+\tif (ts.tv_nsec < 0) {\n+\t\tts.tv_sec--;\n+\t\tts.tv_nsec += 1000000000L;\n+\t}\n+\treturn ts;\n+}\n+\n+/* Format up a timestamp based on current format */\n+static ssize_t\n+format_timestamp(char *tsbuf, size_t tsbuflen)\n+{\n+\tstruct timespec now, delta;\n+\tstruct tm *tm;\n+\n+\tswitch (rte_logs.time_format) {\n+\tcase EAL_LOG_TIMESTAMP_NONE:\n+\t\treturn 0;\n+\n+\tcase EAL_LOG_TIMESTAMP_TIME:\n+\t\tif (clock_gettime(CLOCK_MONOTONIC, &now) < 0)\n+\t\t\treturn 0;\n+\n+\t\tdelta = timespec_sub(&now, &rte_logs.started);\n+\n+\t\treturn snprintf(tsbuf, tsbuflen, \"%6lu.%06lu\",\n+\t\t\t\t(unsigned long)delta.tv_sec,\n+\t\t\t\t(unsigned long)delta.tv_nsec / 1000u);\n+\n+\tcase EAL_LOG_TIMESTAMP_DELTA:\n+\t\tif (clock_gettime(CLOCK_MONOTONIC, &now) < 0)\n+\t\t\treturn 0;\n+\n+\t\tdelta = timespec_sub(&now, &rte_logs.previous);\n+\t\trte_logs.previous = now;\n+\n+\t\treturn snprintf(tsbuf, tsbuflen, \"<%6lu.%06lu>\",\n+\t\t\t\t(unsigned long)delta.tv_sec,\n+\t\t\t\t(unsigned long)delta.tv_nsec / 1000u);\n+\n+\tcase EAL_LOG_TIMESTAMP_RELTIME:\n+\t\tif (clock_gettime(CLOCK_REALTIME, &now) < 0)\n+\t\t\treturn 0;\n+\n+\t\ttm = localtime(&now.tv_sec);\n+\t\tdelta = timespec_sub(&now, &rte_logs.previous);\n+\t\trte_logs.previous = now;\n+\n+\t\t/* if minute, day, hour hasn't changed then print delta */\n+\t\tif (tm->tm_min != rte_logs\n+.last_tm.tm_min ||\n+\t\t    tm->tm_hour != rte_logs.last_tm.tm_hour ||\n+\t\t    tm->tm_yday != rte_logs.last_tm.tm_yday) {\n+\t\t\trte_logs.last_tm = *tm;\n+\t\t\treturn strftime(tsbuf, tsbuflen, \"%b%d %H:%M\", tm);\n+\t\t} else {\n+\t\t\treturn snprintf(tsbuf, tsbuflen, \"+%4lu.%06lu\",\n+\t\t\t\t\t(unsigned long)delta.tv_sec,\n+\t\t\t\t\t(unsigned long)delta.tv_nsec / 1000u);\n+\t\t}\n+\n+\tcase EAL_LOG_TIMESTAMP_CTIME:\n+\t\tif (clock_gettime(CLOCK_REALTIME, &now) < 0)\n+\t\t\treturn 0;\n+\n+\t\t/* trncate to remove newline from ctime result */\n+\t\treturn snprintf(tsbuf, tsbuflen, \"%.24s\", ctime(&now.tv_sec));\n+\n+\tcase EAL_LOG_TIMESTAMP_ISO: {\n+\t\tchar dbuf[64]; /* \"2024-05-01T22:11:00\" */\n+\t\tchar zbuf[16]; /* \"+0800\" */\n+\n+\t\tif (clock_gettime(CLOCK_REALTIME, &now) < 0)\n+\t\t\treturn 0;\n+\n+\t\ttm = localtime(&now.tv_sec);\n+\n+\t\t/* make \"2024-05-01T22:11:00,123456+0100\" */\n+\t\tif (strftime(dbuf, sizeof(dbuf), \"%Y-%m-%dT%H:%M:%S\", tm) == 0)\n+\t\t\treturn 0;\n+\n+\t\t/* convert timezone to +HH:MM */\n+\t\tif (strftime(zbuf, sizeof(zbuf), \"%z\", tm) == 0)\n+\t\t\treturn 0;\n+\t\t/* insert : required in ISO */\n+\t\tmemmove(zbuf + 3, zbuf + 4, 2);\n+\t\tzbuf[3] = ':';\n+\t\tzbuf[6] = '\\0';\n+\n+\t\treturn snprintf(tsbuf, tsbuflen, \"%s,%06lu%s\",\n+\t\t\t\tdbuf, now.tv_nsec / 1000u, zbuf);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n /* default log print function */\n __rte_format_printf(3, 0)\n static int\n@@ -522,10 +667,31 @@ log_print(FILE *f, uint32_t level __rte_unused,\n \treturn vfprintf(f, format, ap);\n }\n \n+/* print timestamp before message */\n+__rte_format_printf(3, 0)\n+static int\n+log_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\tfprintf(f, \"[%s] \", tsbuf);\n+\n+\treturn log_print(f, level, format, ap);\n+}\n+\n /* initialize logging */\n void\n eal_log_init(const char *id __rte_unused)\n {\n+\t/* skip if user has already setup a log stream */\n+\tif (rte_logs.file != NULL)\n+\t\treturn;\n+\n+\tif (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE)\n+\t\trte_logs.print_func = log_print_with_timestamp;\n+\n #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG\n \tRTE_LOG(NOTICE, EAL,\n \t\t\"Debug dataplane logs available - lower performance\\n\");\ndiff --git a/lib/log/log_internal.h b/lib/log/log_internal.h\nindex 4f1ffe999e..3544ae49ac 100644\n--- a/lib/log/log_internal.h\n+++ b/lib/log/log_internal.h\n@@ -5,8 +5,10 @@\n #ifndef LOG_INTERNAL_H\n #define LOG_INTERNAL_H\n \n+#include <stdbool.h>\n #include <stdio.h>\n #include <stdint.h>\n+#include <time.h>\n \n #include <rte_compat.h>\n \n@@ -42,4 +44,11 @@ const char *eal_log_level2str(uint32_t level);\n __rte_internal\n void rte_eal_log_cleanup(void);\n \n+/*\n+ * Add timestamp to console logs\n+ */\n+__rte_internal\n+int eal_log_timestamp(const char *fmt);\n+\n+\n #endif /* LOG_INTERNAL_H */\ndiff --git a/lib/log/version.map b/lib/log/version.map\nindex 0648f8831a..7fd5b39e3a 100644\n--- a/lib/log/version.map\n+++ b/lib/log/version.map\n@@ -30,5 +30,6 @@ INTERNAL {\n \teal_log_save_pattern;\n \teal_log_save_regexp;\n \teal_log_set_default;\n+\teal_log_timestamp;\n \trte_eal_log_cleanup;\n };\n",
    "prefixes": [
        "v11",
        "7/9"
    ]
}