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 52CF245BB9; Thu, 24 Oct 2024 05:21:55 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B116C4339F; Thu, 24 Oct 2024 05:20:59 +0200 (CEST) Received: from mail-pg1-f181.google.com (mail-pg1-f181.google.com [209.85.215.181]) by mails.dpdk.org (Postfix) with ESMTP id 7C66543372 for ; Thu, 24 Oct 2024 05:20:48 +0200 (CEST) Received: by mail-pg1-f181.google.com with SMTP id 41be03b00d2f7-7e6cbf6cd1dso251039a12.3 for ; Wed, 23 Oct 2024 20:20:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1729740048; x=1730344848; 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=KKs4ANf37SuNXjqv1HKK5rsL+Y52KOeBJS2n3DcOUa4=; b=qeIYiHhaBRFeZ1sdpOikdH7FRKU/ti8G1d+p5CjO5QcH6JImIjTtblzd96iVL7WeX3 7RxZDsKOrl9MGDacuAxPR2oOg2fq76d/SJLfSD0nHl0/dQnsm9gbeEzo7chIwAvws1WO 1tEZ+CHA7WXLqTwGnwScwyBNY7AGXt6GOHPR+BVqIYBiGlff1wYslIsg3D3NBDG8mMa5 lISARyP00bkQpTDUyJYssDgUQ9/0G9420QTht7jEHbTFK0DXJsBwFOV++Faxo5J9GS/o umj1nghy8i4VfN19sdxIkj1OkOCAXca1hH70Js97g/JQMVzM+kFpif08LtDvz95O5cJS Bwug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729740048; x=1730344848; 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=KKs4ANf37SuNXjqv1HKK5rsL+Y52KOeBJS2n3DcOUa4=; b=GHoXHDKspvgpOZc7f41nriZHBVVhzz7dg4ZR5z25LhjWwyVmbwg89fdYsmPLD0bGzG Dnfs99k16aH5lIU9b2SkMEim8KbDQj4Terv0KituqrKliLgwk46hej/EIXFZnU8xISvh 6ci54OfuTN44EqxzVnsQzZ06kLOlOpq2PWB2N7cTiMp3uwg18p5bXholS5Vetpo5B/Uh ku1A2Q4tFqKWPZ86fF/OHECKknwKZZ04fB7dd4UvyHQw4f5aztvwiIODEXw07UW5Zm+N L/mz+pXLeFbsN5IgnLaF/yEyxGWudoF+aCzWuks076oQEKJppWVfRVQ9SB9ncE2dzmOO zQSA== X-Gm-Message-State: AOJu0YwfOolXvG2YwfnFN7QFmQTqTetEvwGFkBf3xuKtftuAJYbAYawp VOqBZY3JLWnmZVkb04Zj1yWi0spCyoOlt0ecssmunuevFenhbsfcYUIYV0hP0huCxAbA8MCX4h/ e X-Google-Smtp-Source: AGHT+IFrky853HGDu2Lf/EksDxVIbOiwRvMx9q9WWQmpN6NMdlsEcDT6SIur3cxzRvLbR9qqgmaacw== X-Received: by 2002:a05:6a21:7702:b0:1d9:a94:8d90 with SMTP id adf61e73a8af0-1d978b3ea6dmr5994667637.27.1729740047585; Wed, 23 Oct 2024 20:20:47 -0700 (PDT) Received: from hermes.local (204-195-96-226.wavecable.com. [204.195.96.226]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-71ec1324d41sm6999533b3a.57.2024.10.23.20.20.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Oct 2024 20:20:47 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , =?UTF-8?q?Morten=20Br=C3=B8rup?= , Bruce Richardson Subject: [PATCH v27 12/14] log: add support for systemd journal Date: Wed, 23 Oct 2024 20:18:50 -0700 Message-ID: <20241024032026.415122-13-stephen@networkplumber.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241024032026.415122-1-stephen@networkplumber.org> References: <20200814173441.23086-1-stephen@networkplumber.org> <20241024032026.415122-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 | 13 ++-- lib/log/log_internal.h | 3 + lib/log/log_journal.c | 154 +++++++++++++++++++++++++++++++++++++++++ lib/log/log_private.h | 14 +++- lib/log/log_syslog.c | 17 ++++- lib/log/meson.build | 4 ++ lib/log/version.map | 1 + 7 files changed, 198 insertions(+), 8 deletions(-) create mode 100644 lib/log/log_journal.c diff --git a/lib/log/log.c b/lib/log/log.c index 5455687e79..343f9d77b7 100644 --- a/lib/log/log.c +++ b/lib/log/log.c @@ -506,15 +506,16 @@ rte_log(uint32_t level, uint32_t logtype, const char *format, ...) void eal_log_init(const char *id) { -#ifndef RTE_EXEC_ENV_WINDOWS - FILE *logf; + FILE *logf = NULL; + + if (log_journal_enabled()) + logf = log_journal_open(id); + else if (log_syslog_enabled()) + logf = log_syslog_open(id); - logf = log_syslog_open(id); if (logf) rte_openlog_stream(logf); -#endif - - if (log_timestamp_enabled()) + else if (log_timestamp_enabled()) rte_logs.print_func = log_print_with_timestamp; else rte_logs.print_func = vfprintf; diff --git a/lib/log/log_internal.h b/lib/log/log_internal.h index 7c7d44eed2..82fdc21ac2 100644 --- a/lib/log/log_internal.h +++ b/lib/log/log_internal.h @@ -29,6 +29,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..43341aa233 --- /dev/null +++ b/lib/log/log_journal.c @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "log_internal.h" +#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 53d05f8ac8..625f57c0cc 100644 --- a/lib/log/log_private.h +++ b/lib/log/log_private.h @@ -3,10 +3,22 @@ #ifndef LOG_PRIVATE_H #define LOG_PRIVATE_H -#ifndef RTE_EXEC_ENV_WINDOWS +#ifdef RTE_EXEC_ENV_WINDOWS +#define log_syslog_enabled() (false) +#define log_syslog_open(id) (NULL) +#else +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 +#define log_journal_enabled() (false) +#define log_journal_open(id) (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 4a05835068..d911deff44 100644 --- a/lib/log/log_syslog.c +++ b/lib/log/log_syslog.c @@ -16,8 +16,12 @@ #include "log_internal.h" #include "log_private.h" -static int log_facility = LOG_DAEMON; +static int log_facility; +/* + * Usable list of facilities + * Skip kern, mark, and security + */ static const struct { const char *name; int value; @@ -48,6 +52,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; @@ -57,6 +66,12 @@ eal_log_syslog(const char *name) return -1; } +/* syslog is enabled if facility is set */ +bool log_syslog_enabled(void) +{ + return log_facility != 0; /* LOG_KERN is 0 */ +} + /* * default log function */ 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