From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2553E45BF5; Sun, 27 Oct 2024 18:27:35 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id ED86D40A80; Sun, 27 Oct 2024 18:26:46 +0100 (CET) Received: from mail-pl1-f181.google.com (mail-pl1-f181.google.com [209.85.214.181]) by mails.dpdk.org (Postfix) with ESMTP id BF0D54067C for ; Sun, 27 Oct 2024 18:26:36 +0100 (CET) Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-20cb7139d9dso30552445ad.1 for ; Sun, 27 Oct 2024 10:26:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1730049996; x=1730654796; 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=hM2IJ/+D8R/H6VdT2xTLWvu2GGbUspxzAfNTf2+g+Og=; b=a2IYMFi08LjY4LPbDDvRIRB79NUMPEYb9CpGR+NLRFIYJm4gj+igfgvUVWW0fDvT30 lAhjacaYcJ3qKaeKjMp3MVsAKf1ElUmAW/LR+kuSg9av5S6h3WQm9nqHqsHzfeOvSmFm 20Fd36Jy+QivTH8lS+Ci453n2Ze0YZVjMZqi+N/2/vECTxY0nRQE5zDUpWQ8eGgGmCi6 j3s75ziQhXC7VtUs4tlBs3lVcN101pM/JeeXu8kco38j4TzMe640YYBYu46YVRFQuU/8 OIPbi7YKJUtKA0aAo4RNjbHt/Adh5b2svBJt25EIxakfoxOuEJVmbSklyzBUEx9wWy/c HpGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730049996; x=1730654796; 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=hM2IJ/+D8R/H6VdT2xTLWvu2GGbUspxzAfNTf2+g+Og=; b=CDV0LK9h5AOBelfUZvEgl4+icN7r1c+2sc2urdCxDa8Aae6kGeeDtPDgG1QvQ05Chz phRJhKgNBaCkSGa+3HYnW16OajXVCzppHHUa82DKKTY3wCluQwJW0de8VK3wqLTzP008 1fKON5lmzio+Zh7wLw59dklPqn207QScKHb534FUrk0WEg1JSc6joer89O6CfOSlAILO s6YBfvJsXGHc/LdpNz1yjSxAYVN3ion2w4ShsUXOVo6SyAiA4bcciGjJ5c92SGk2A1wA y8y8SME+BckzBpg1EEBCS2g6ynJCoKtIx73Fm6z/ieeHNV+95BjSO3nivY6IxRZRTyaH vU3w== X-Gm-Message-State: AOJu0Yw/eypYjirCaOEN3MbMaW7h5PRRiG0nBEH/L8J5NgcbdTZ5qMPa Ey+6vOn5spMJEP/CSK52t5H1zd6yXC26oiOhIuwg6zClm8wOJ9mbHq7pPTKn+hy3dWfKeZNCo1E IV12VIQ== X-Google-Smtp-Source: AGHT+IG4/XcDbiPbFnKul3ZqxDs1gm9ttFKKZ73WkdABS1JIXqdO/Dk2gA1jmO3w7mZzPak08Drjwg== X-Received: by 2002:a17:902:d489:b0:20c:ca42:e231 with SMTP id d9443c01a7336-210c6876d84mr99622715ad.6.1730049995908; Sun, 27 Oct 2024 10:26:35 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-210bbf71d50sm37754465ad.72.2024.10.27.10.26.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Oct 2024 10:26:35 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , =?UTF-8?q?Morten=20Br=C3=B8rup?= , Bruce Richardson Subject: [PATCH v30 11/13] log: add support for systemd journal Date: Sun, 27 Oct 2024 10:24:41 -0700 Message-ID: <20241027172616.176175-12-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241027172616.176175-1-stephen@networkplumber.org> References: <20200814173441.23086-1-stephen@networkplumber.org> <20241027172616.176175-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 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 Acked-by: Morten Brørup Acked-by: Bruce Richardson --- lib/log/log.c | 32 +++++---- lib/log/log_internal.h | 3 + lib/log/log_journal.c | 152 +++++++++++++++++++++++++++++++++++++++++ lib/log/log_private.h | 14 ++++ lib/log/log_syslog.c | 9 +++ lib/log/meson.build | 4 ++ lib/log/version.map | 1 + 7 files changed, 203 insertions(+), 12 deletions(-) create mode 100644 lib/log/log_journal.c diff --git a/lib/log/log.c b/lib/log/log.c index 854d77887b..db18690055 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -505,18 +505,26 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) void eal_log_init(const char *id) { - FILE *logf = NULL; - - if (log_syslog_enabled()) - logf = log_syslog_open(id); - - if (logf) - rte_openlog_stream(logf); - - if (log_timestamp_enabled()) - rte_logs.print_func = log_print_with_timestamp; - else - rte_logs.print_func = vfprintf; + /* If user has already set a log stream, then use it. */ + if (rte_logs.file == NULL) { + FILE *logf = NULL; + + /* if stderr is assocated with systemd environment */ + if (log_journal_enabled()) + logf = log_journal_open(id); + /* If --syslog option was passed */ + else if (log_syslog_enabled()) + logf = log_syslog_open(id); + + /* if either syslog or journal is used, then no special handling */ + if (logf) + rte_openlog_stream(logf); + + else if (log_timestamp_enabled()) + rte_logs.print_func = log_print_with_timestamp; + else + rte_logs.print_func = vfprintf; + } #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG RTE_LOG(NOTICE, EAL, diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 8ef195a6ec..731c099984 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -35,6 +35,9 @@ int eal_log_save_pattern(const char *pattern, uint32_t level); __rte_internal int eal_log_syslog(const char *name); +__rte_internal +int eal_log_journal(const char *opt); + /* * Convert log level to string. */ diff --git a/lib/log/log_journal.c b/lib/log/log_journal.c new file mode 100644 index 0000000000..f163dc12ae --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "log_private.h" + +/* + * Send structured message using journal protocol + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + * + * Uses writev() to ensure that whole log message is in one datagram + */ +static int +journal_send(int fd, const char *buf, size_t len) +{ + struct iovec iov[4]; + unsigned int n = 0; + int priority = rte_log_cur_msg_loglevel() - 1; + char msg[] = "MESSAGE="; + char newline = '\n'; + char pbuf[32]; /* "PRIORITY=N\n" */ + + iov[n].iov_base = msg; + iov[n++].iov_len = strlen(msg); + + iov[n].iov_base = (char *)(uintptr_t)buf; + iov[n++].iov_len = len; + + /* if message doesn't end with newline, one will be applied. */ + if (buf[len - 1] != '\n') { + iov[n].iov_base = &newline; + iov[n++].iov_len = 1; + } + + /* priority value between 0 ("emerg") and 7 ("debug") */ + iov[n].iov_base = pbuf; + iov[n++].iov_len = snprintf(pbuf, sizeof(pbuf), + "PRIORITY=%d\n", priority); + return writev(fd, iov, n); +} + + +/* wrapper for log stream to put messages into journal */ +static ssize_t +journal_log_write(void *c, const char *buf, size_t size) +{ + int fd = (uintptr_t)c; + + return journal_send(fd, buf, size); +} + +static int +journal_log_close(void *c) +{ + int fd = (uintptr_t)c; + + close(fd); + return 0; +} + +static cookie_io_functions_t journal_log_func = { + .write = journal_log_write, + .close = journal_log_close, +}; + +/* + * Check if stderr is going to system journal. + * This is the documented way to handle systemd journal + * + * See: https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ + */ +bool +log_journal_enabled(void) +{ + char *jenv, *endp = NULL; + struct stat st; + unsigned long dev, ino; + + jenv = getenv("JOURNAL_STREAM"); + if (jenv == NULL) + return false; + + if (fstat(STDERR_FILENO, &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 */ +FILE *log_journal_open(const char *id) +{ + char syslog_id[PATH_MAX]; + FILE *log_stream; + int len; + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + int jfd = -1; + + len = snprintf(syslog_id, sizeof(syslog_id), + "SYSLOG_IDENTIFIER=%s\nSYSLOG_PID=%u", id, getpid()); + + /* Detect truncation of message and fallback to no journal */ + if (len >= (int)sizeof(syslog_id)) + return NULL; + + jfd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (jfd < 0) { + perror("socket"); + goto error; + } + + if (connect(jfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + perror("connect"); + goto error; + } + + /* Send identifier as first message */ + if (write(jfd, syslog_id, len) != len) { + perror("write"); + goto error; + } + + /* redirect other log messages to journal */ + log_stream = fopencookie((void *)(uintptr_t)jfd, "w", journal_log_func); + if (log_stream != NULL) + return log_stream; + +error: + close(jfd); + return NULL; +} diff --git a/lib/log/log_private.h b/lib/log/log_private.h index 86eaf3f910..37895949f6 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -22,6 +22,20 @@ bool log_syslog_enabled(void); FILE *log_syslog_open(const char *id); #endif +#ifdef RTE_EXEC_ENV_LINUX +bool log_journal_enabled(void); +FILE *log_journal_open(const char *id); +#else +static inline bool log_journal_enabled(void) +{ + return false; +} +static inline FILE *log_journal_open(const char *id __rte_unused) +{ + return NULL; +} +#endif /* !RTE_EXEC_ENV_LINUX */ + bool log_timestamp_enabled(void); ssize_t log_timestamp(char *tsbuf, size_t tsbuflen); diff --git a/lib/log/log_syslog.c b/lib/log/log_syslog.c index bc9b996fd6..15c1f835c8 100644 --- a/lib/log/log_syslog.c +++ b/lib/log/log_syslog.c @@ -17,6 +17,10 @@ static int log_facility; +/* + * Usable list of facilities + * Skip kern, mark, and security + */ static const struct { const char *name; int value; @@ -47,6 +51,11 @@ eal_log_syslog(const char *name) { unsigned int i; + if (name == NULL) { + log_facility = LOG_DAEMON; + return 0; + } + for (i = 0; i < RTE_DIM(facilitys); i++) { if (!strcmp(name, facilitys[i].name)) { log_facility = facilitys[i].value; diff --git a/lib/log/meson.build b/lib/log/meson.build index 4ac232786e..86e4452b19 100644 --- a/lib/log/meson.build +++ b/lib/log/meson.build @@ -11,4 +11,8 @@ if not is_windows sources += files('log_syslog.c') endif +if is_linux + sources += files('log_journal.c') +endif + headers = files('rte_log.h') diff --git a/lib/log/version.map b/lib/log/version.map index 8be6907840..800d3943bc 100644 --- a/lib/log/version.map +++ b/lib/log/version.map @@ -26,6 +26,7 @@ INTERNAL { global: eal_log_init; + eal_log_journal; # WINDOWS_NO_EXPORT eal_log_level2str; eal_log_save_pattern; eal_log_save_regexp; -- 2.45.2