From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124])
	by inbox.dpdk.org (Postfix) with ESMTP id 6CEA643D36;
	Sun, 24 Mar 2024 03:42:22 +0100 (CET)
Received: from mails.dpdk.org (localhost [127.0.0.1])
	by mails.dpdk.org (Postfix) with ESMTP id 08B89406B8;
	Sun, 24 Mar 2024 03:41:34 +0100 (CET)
Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com
 [209.85.214.171])
 by mails.dpdk.org (Postfix) with ESMTP id 5A08E402EC
 for <dev@dpdk.org>; Sun, 24 Mar 2024 03:41:27 +0100 (CET)
Received: by mail-pl1-f171.google.com with SMTP id
 d9443c01a7336-1e034607879so25623615ad.0
 for <dev@dpdk.org>; Sat, 23 Mar 2024 19:41:27 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=networkplumber-org.20230601.gappssmtp.com; s=20230601; t=1711248086;
 x=1711852886; 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=LCYp3m42AR3Bl02fdCxypzjKxWlwIQYVWzlmXEvqwJo=;
 b=taSHpVp6ukoNZ58mie4uRfNcPRx2b4/Ts8/x3i5VS9xXxdztmpR3u7BTYq7RILS49M
 KeKv+1Dowf1ZSsjtQBHI9UkpkZZ7ewbEuWiMOcp7UsRQ4l4oAkgDUXsKDXj8/y2tq1n2
 ynkCUa0HBgHgxXV3t2V3Kt9miYlZr97Mz7AjOk3Z1CIeCZoRnZhWd6Mitx6+Cd4I6ox1
 dxwBxvUVlLhNmFHRHaIAP8uXuy2sl1PtBxVgZhfcTCaEw3KV61VCfUzmoS6V5+yFr7H/
 +5C8k+yqlw4IvwpsoA4uBKojlLb8jzERX/cL7B9FLrdo7uQ3YhlXyfp358+jbM+qbbz+
 te1A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1711248086; x=1711852886;
 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=LCYp3m42AR3Bl02fdCxypzjKxWlwIQYVWzlmXEvqwJo=;
 b=mljAY7rwuh5WgABwt2BxboQiO+aSK9NMkA5qf+whQ0Az87SH9i7YLywsqBttjB0idz
 r1Ynkb0xl5wV+CfaVDA/0/AJk/Qwk+qGT0tCG5QIO600iF0NTKcY4kxP3gtjoPzdIVx9
 2G6zKGvYw8DvUeFCoZk6Vtaqd2o4+jEWEnp/NCux1n2z5OvXEG7p0R6UFmnEdaC/2mTe
 ra3nsSQ1UWqXteU8O5nwytSH13FJiW8l6oJD9TbBoY/FJjflAKKrBMgJi2JnYqanzriM
 pqC0j1Vd3PiOWnR8dxh7ToofTSIWorgr3xTU5PVkpT0pC8zFCKsO6GxZcrMzPDBAaBQ4
 vCtw==
X-Gm-Message-State: AOJu0YywQ/Em0Is0WhgKwn/nWtmXvwn75+fZwzNPUTB/MhFHMpfsFwKt
 c6f1KNb89ZOUjBNtwUlHfkvh25zVshqerot6LSHFejYeoKRZf6q59e4ydLqjtuITFUcSXXr/bcS
 d
X-Google-Smtp-Source: AGHT+IF7XgmNXk8AH99VyNhqznazLQIcdk/PHeLl9qAd7uj56dqWdFRVNuCI5Bk42WTi6n2tq/RsQw==
X-Received: by 2002:a17:903:186:b0:1dd:7df8:9ed7 with SMTP id
 z6-20020a170903018600b001dd7df89ed7mr5526206plg.15.1711248086613; 
 Sat, 23 Mar 2024 19:41:26 -0700 (PDT)
Received: from hermes.local (204-195-123-203.wavecable.com. [204.195.123.203])
 by smtp.gmail.com with ESMTPSA id
 q17-20020a17090311d100b001dc3c4e7a12sm2244980plh.14.2024.03.23.19.41.26
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Sat, 23 Mar 2024 19:41:26 -0700 (PDT)
From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>
Subject: [PATCH v11 8/9] log: add support for systemd journal
Date: Sat, 23 Mar 2024 19:33:30 -0700
Message-ID: <20240324024109.306614-9-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>
 <20240324024109.306614-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>,
 <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>,
 <mailto:dev-request@dpdk.org?subject=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/

The journal protocol supports more information that could
be added later.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/log/log.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 136 insertions(+), 5 deletions(-)

diff --git a/lib/log/log.c b/lib/log/log.c
index bd488dff1b..4cfa160e3b 100644
--- a/lib/log/log.c
+++ b/lib/log/log.c
@@ -13,15 +13,20 @@
 #include <sys/queue.h>
 #include <unistd.h>
 
+#ifdef RTE_EXEC_ENV_WINDOWS
+#include <rte_os_shim.h>
+#else
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
 #include <rte_log.h>
 #include <rte_per_lcore.h>
 
 #include "log_internal.h"
 
-#ifdef RTE_EXEC_ENV_WINDOWS
-#include <rte_os_shim.h>
-#endif
-
 struct rte_log_dynamic_type {
 	const char *name;
 	uint32_t loglevel;
@@ -39,11 +44,13 @@ enum eal_log_time_format {
 typedef int (*log_print_t)(FILE *f, uint32_t level, const char *fmt, va_list ap);
 static int log_print(FILE *f, uint32_t level, const char *format, va_list ap);
 
+
 /** The rte_log structure. */
 static struct rte_logs {
 	uint32_t type;  /**< Bitfield with enabled logs. */
 	uint32_t level; /**< Log level. */
 	FILE *file;     /**< Output file set by rte_openlog_stream, or NULL. */
+	int journal_fd;	/**< Journal file descriptor if using */
 	log_print_t print_func;
 
 	enum eal_log_time_format time_format;
@@ -681,6 +688,116 @@ log_print_with_timestamp(FILE *f, uint32_t level,
 	return log_print(f, level, format, ap);
 }
 
+#ifdef RTE_EXEC_ENV_LINUX
+/*
+ * send message using journal protocol to journald
+ */
+__rte_format_printf(3, 0)
+static int
+journal_print(FILE *f __rte_unused, uint32_t level, const char *format, va_list ap)
+{
+	struct iovec iov[3];
+	char *buf = NULL;
+	size_t len;
+	char msg[] = "MESSAGE=";
+	char *prio;
+
+	iov[0].iov_base = msg;
+	iov[0].iov_len = strlen(msg);
+
+	len = vasprintf(&buf, format, ap);
+	if (len == 0)
+		return 0;
+
+	/* check that message ends with newline */
+	if (buf[len - 1] != '\n') {
+		char *clone  = alloca(len + 1);
+		if (clone == NULL)
+			return 0;
+		memcpy(clone, buf, len);
+		clone[len++] = '\n';
+		buf = clone;
+	}
+
+	iov[1].iov_base = buf;
+	iov[1].iov_len = len;
+
+	/* priority value between 0 ("emerg") and 7 ("debug") */
+	len = asprintf(&prio, "PRIORITY=%i\n", level - 1);
+	iov[2].iov_base = prio;
+	iov[2].iov_len = len;
+
+	return writev(rte_logs.journal_fd, iov, 3);
+}
+
+static void
+journal_send_id(int fd, const char *id)
+{
+	char *syslog_id = NULL;
+	size_t len;
+
+	len = asprintf(&syslog_id, "SYSLOG_IDENTIFIER=%s\n", id);
+	if (len > 0)
+		write(fd, syslog_id, len);
+
+}
+
+/*
+ * 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
+using_journal(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;
+}
+
+/*
+ * If we are being run as systemd service and stderr is going to journal
+ * then upgrade to use journal protocol.
+ */
+static int
+open_journal(void)
+{
+	struct sockaddr_un sun = {
+		.sun_family = AF_UNIX,
+		.sun_path = "/run/systemd/journal/socket",
+	};
+	int s;
+
+	s = socket(AF_UNIX, SOCK_DGRAM, 0);
+	if (s < 0)
+		return -1;
+
+	if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
+		close(s);
+		return -1;
+	}
+	return s;
+}
+#endif
+
 /* initialize logging */
 void
 eal_log_init(const char *id __rte_unused)
@@ -689,8 +806,22 @@ eal_log_init(const char *id __rte_unused)
 	if (rte_logs.file != NULL)
 		return;
 
-	if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE)
+#ifdef RTE_EXEC_ENV_LINUX
+	if (using_journal()) {
+		int jfd = open_journal();
+
+		if (jfd < 0) {
+			RTE_LOG_LINE(NOTICE, EAL, "Cannot connect to journal");
+		} else {
+			rte_logs.journal_fd = jfd;
+			rte_logs.print_func = journal_print;
+			journal_send_id(jfd, id);
+		}
+	} else
+#endif
+	if (rte_logs.time_format != EAL_LOG_TIMESTAMP_NONE) {
 		rte_logs.print_func = log_print_with_timestamp;
+	}
 
 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
 	RTE_LOG(NOTICE, EAL,
-- 
2.43.0