From patchwork Wed Mar 27 23:28:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 138950 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: 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]) by inbox.dpdk.org (Postfix) with ESMTP id DFA8C43D5B; Thu, 28 Mar 2024 00:31:42 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 115DF42DDC; Thu, 28 Mar 2024 00:30:36 +0100 (CET) Received: from mail-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.175]) by mails.dpdk.org (Postfix) with ESMTP id AD87442686 for ; Thu, 28 Mar 2024 00:30:23 +0100 (CET) Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-1dde26f7e1dso3685295ad.1 for ; Wed, 27 Mar 2024 16:30:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1711582223; x=1712187023; darn=dpdk.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=46SG9RLhZSJQXgtr6/M3XC3YSSvsoh/NwdGR6vHqARE=; b=LlYNJ61GxDnA6f+xbsfhh05DlXRYD6Y0arcp2i7rVtwSIHwPmnp12LK1zgNoeslyx0 TegC2nhi6/2UPZ2xJj1OaaS8D3qG8jZ6QlYMODV7XENETrJrzWZlktPmYfJzoUG6FD8I X8YnVRJh1zA9cUt4o91qFzOhyEbomhLdS4dZCAPBrb4eDJuAe4SXB60VTWe1p2YnoNB0 8AxP9zHKKdfLxrmLBonCj2RH3EFjEx/wUYhRhm/rnygTGh3QrUEZmVYPFRCaEF5c/IiY rsirPM3qjl/iPH1SFwd60ZpFiiASq22GL4wKnxPSr62D+AB/2SbEp3LkKsfRBNM48YaL CtMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1711582223; x=1712187023; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=46SG9RLhZSJQXgtr6/M3XC3YSSvsoh/NwdGR6vHqARE=; b=ft0ed8RsLrsU3jineZVdt2RFiQ5g4bEvRdNEgPFCBQ14Mjk8hRzmYw/iynwwZ4Z1ee 4Tf2Z5Pd8kWBHOv+KExY6AFKRnXpZ7vBakK+KtTkjbsJoAw2G5TUhOOJQ3YjVmJA2AMU l7UT20b5ws8c4Xt1+IsRXqx6QmSUBxKb3xFiTUST7KsQWONoEq3dNZq5tMmmxi2449Sw IPscxlNzwXKsuIIMksbE/DcQNnr3yimFdvBNCxMGkxeHtyy3TW9mBc9lPWeCqyIBsrMZ UMG/rCjpJqN4egSM+xCB1liNWZtUkpWN2lnD6quygdAA9IT/gIuw4hVSbYNY76InuzQp 6EtQ== X-Gm-Message-State: AOJu0Yy6lGFVwh3nCzeLVYWFtIhzxLII8QUFOo1whoS7MbIi/Ak1duVd 6u+1PbP8T6CV1gACcF3491cq1jJnBxfuenLCCZLrtKuzBVwifKTTgNzOp2D3RC6KGqeGcvWQYb+ i X-Google-Smtp-Source: AGHT+IFpzR+9hFarHvs5Kdpq7TTfXFdWUGVtVXZABCubNep/KJGTGIAdKfpb1xlTkN1YhzTtGBzuCQ== X-Received: by 2002:a17:902:ab89:b0:1e0:f550:82ba with SMTP id f9-20020a170902ab8900b001e0f55082bamr986330plr.59.1711582222904; Wed, 27 Mar 2024 16:30:22 -0700 (PDT) Received: from hermes.local (204-195-123-203.wavecable.com. [204.195.123.203]) by smtp.gmail.com with ESMTPSA id n15-20020a170902e54f00b001e0fdc6e4ebsm80772plf.175.2024.03.27.16.30.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Mar 2024 16:30:22 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Subject: [PATCH v17 14/15] log: add support for systemd journal Date: Wed, 27 Mar 2024 16:28:37 -0700 Message-ID: <20240327233001.83505-15-stephen@networkplumber.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240327233001.83505-1-stephen@networkplumber.org> References: <20200814173441.23086-1-stephen@networkplumber.org> <20240327233001.83505-1-stephen@networkplumber.org> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org 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 --- 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 #else #include +#include +#include +#include +#include #endif #include @@ -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;