Change in libosmocore[master]: logging: introduce 'systemd-journal' target

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Mon Oct 19 15:02:00 UTC 2020


laforge has submitted this change. ( https://gerrit.osmocom.org/c/libosmocore/+/20045 )

Change subject: logging: introduce 'systemd-journal' target
......................................................................

logging: introduce 'systemd-journal' target

This change implements 'systemd-journal' logging target, that is
similar to the existing 'syslog' target.  The key difference is
that 'systemd-journal' allows us to offload rendering of the meta
information, such as location (file name, line number), subsystem,
and logging level, to systemd.  Moreover, we can attach arbitrary,
user-specific fields [1] to the logging messages, so they can be
used for advanced log filtering (e.g. by IMSI/TMSI/TLLI):

  $ journalctl OSMO_SUBSYS=DMSC -f

Since we don't want to make libsystemd a required dependency, this
feature is optional, and needs to be enabled at build-time:

  $ ./configure --enable-systemd-logging

The new logging target can be configured in the same way as any
other one - via the VTY interface, or using the configuration file:

  log systemd-journal [raw]
    logging level set-all notice
    logging filter all 1

Two logging handlers are available: generic and raw.  The first one
behaves similarly to both 'syslog' and 'stderr', i.e. all the meta
information is rendered by libosmocore itself, and then passed to
systemd together with the logging message.  The later is more like
the 'gsmtap' target, so all available meta information is handed
over to systemd in form of fields [1]:

  - CODE_FILE / CODE_LINE - location info,
  - PRIORITY - syslog-compatible logging level,
  - OSMO_SUBSYS - Osmocom-specific sub-system (e.g. DMSC),
  - OSMO_SUBSYS_HEX - same as OSMO_SUBSYS, but encoded in hex,
  - MESSAGE - the logging message itself,

and then can be rendered in any supported format (e.g. JSON).

More details about the API can be found in [2].

[1] https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
[2] https://www.freedesktop.org/software/systemd/man/sd-journal.html

Change-Id: I609f5cf438e6ad9038d8fc95f00add6aac29fb23
---
M configure.ac
M include/osmocom/core/logging.h
M src/Makefile.am
A src/logging_systemd.c
M src/vty/logging_vty.c
5 files changed, 211 insertions(+), 0 deletions(-)

Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/configure.ac b/configure.ac
index b07a3bd..e867197 100644
--- a/configure.ac
+++ b/configure.ac
@@ -181,6 +181,19 @@
 	AC_DEFINE([USE_GNUTLS], [1], [Use GnuTLS as a fallback for missing getrandom()])
 fi
 
+AC_ARG_ENABLE([systemd_logging],
+	[AS_HELP_STRING(
+		[--enable-systemd-logging],
+		[Build with systemd-journal logging support]
+	)],
+	[systemd_logging=$enableval], [systemd_logging="no"])
+AS_IF([test "x$systemd_logging" = "xyes"], [
+	PKG_CHECK_MODULES(SYSTEMD, libsystemd)
+	AC_DEFINE([ENABLE_SYSTEMD_LOGGING], [1], [Enable systemd-journal logging target])
+])
+AM_CONDITIONAL(ENABLE_SYSTEMD_LOGGING, test "x$systemd_logging" = "xyes")
+AC_SUBST(ENABLE_SYSTEMD_LOGGING)
+
 AC_ARG_ENABLE([libsctp], [AS_HELP_STRING([--disable-libsctp], [Do not enable socket multiaddr APIs requiring libsctp])],
 	[ENABLE_LIBSCTP=$enableval], [ENABLE_LIBSCTP="yes"])
 AM_CONDITIONAL(ENABLE_LIBSCTP, test x"$ENABLE_LIBSCTP" = x"yes")
diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h
index 36ce941..6d0d5a3 100644
--- a/include/osmocom/core/logging.h
+++ b/include/osmocom/core/logging.h
@@ -244,6 +244,7 @@
 	LOG_TGT_TYPE_STDERR,	/*!< stderr logging */
 	LOG_TGT_TYPE_STRRB,	/*!< osmo_strrb-backed logging */
 	LOG_TGT_TYPE_GSMTAP,	/*!< GSMTAP network logging */
+	LOG_TGT_TYPE_SYSTEMD,	/*!< systemd journal logging */
 };
 
 /*! Whether/how to log the source filename (and line number). */
@@ -311,6 +312,10 @@
 			const char *ident;
 			const char *hostname;
 		} tgt_gsmtap;
+
+		struct {
+			bool raw;
+		} sd_journal;
 	};
 
 	/*! call-back function to be called when the logging framework
@@ -392,6 +397,8 @@
 					    const char *ident,
 					    bool ofd_wq_mode,
 					    bool add_sink);
+struct log_target *log_target_create_systemd(bool raw);
+void log_target_systemd_set_raw(struct log_target *target, bool raw);
 int log_target_file_reopen(struct log_target *tgt);
 int log_targets_reopen(void);
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 891b4a6..b2c9204 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -71,5 +71,10 @@
 libosmocore_la_SOURCES += serial.c
 endif
 
+if ENABLE_SYSTEMD_LOGGING
+libosmocore_la_SOURCES += logging_systemd.c
+libosmocore_la_LIBADD += $(SYSTEMD_LIBS)
+endif
+
 crc%gen.c: crcXXgen.c.tpl
 	$(AM_V_GEN)sed -e's/XX/$*/g' $< > $@
diff --git a/src/logging_systemd.c b/src/logging_systemd.c
new file mode 100644
index 0000000..7c96686
--- /dev/null
+++ b/src/logging_systemd.c
@@ -0,0 +1,121 @@
+/*
+ * (C) 2020 by Vadim Yanitskiy <axilirator at gmail.com>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/*! \addtogroup logging
+ *  @{
+ * \file logging_systemd.c */
+
+#include <stdio.h>
+#include <syslog.h>
+
+/* Do not use this file as location in sd_journal_print() */
+#define SD_JOURNAL_SUPPRESS_LOCATION
+
+#include <systemd/sd-journal.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/logging.h>
+
+/* FIXME: copy-pasted from logging_syslog.c */
+static int logp2syslog_level(unsigned int level)
+{
+	if (level >= LOGL_FATAL)
+		return LOG_CRIT;
+	else if (level >= LOGL_ERROR)
+		return LOG_ERR;
+	else if (level >= LOGL_NOTICE)
+		return LOG_NOTICE;
+	else if (level >= LOGL_INFO)
+		return LOG_INFO;
+	else
+		return LOG_DEBUG;
+}
+
+static void _systemd_output(struct log_target *target,
+			    unsigned int level, const char *log)
+{
+	/* systemd accepts the same level constants as syslog */
+	sd_journal_print(logp2syslog_level(level), "%s", log);
+}
+
+static void _systemd_raw_output(struct log_target *target, int subsys,
+				unsigned int level, const char *file,
+				int line, int cont, const char *format,
+				va_list ap)
+{
+	char buf[4096];
+	int rc;
+
+	rc = vsnprintf(buf, sizeof(buf), format, ap);
+	if (rc < 0) {
+		sd_journal_print(LOG_ERR, "vsnprintf() failed to render a message "
+					  "originated from %s:%d (rc=%d)\n",
+					  file, line, rc);
+		return;
+	}
+
+	sd_journal_send("CODE_FILE=%s, CODE_LINE=%d", file, line,
+			"PRIORITY=%d", logp2syslog_level(level),
+			"OSMO_SUBSYS=%s", log_category_name(subsys),
+			"OSMO_SUBSYS_HEX=%4.4x", subsys,
+			"MESSAGE=%s", buf,
+			NULL);
+}
+
+/*! Create a new logging target for systemd journal logging.
+ *  \param[in] raw whether to offload rendering of the meta information
+ *		   (location, category) to systemd-journal.
+ *  \returns Log target in case of success, NULL in case of error.
+ */
+struct log_target *log_target_create_systemd(bool raw)
+{
+	struct log_target *target;
+
+	target = log_target_create();
+	if (!target)
+		return NULL;
+
+	target->type = LOG_TGT_TYPE_SYSTEMD;
+	log_target_systemd_set_raw(target, raw);
+
+	return target;
+}
+
+/*! Change meta information handling of an existing logging target.
+ *  \param[in] target logging target to be modified.
+ *  \param[in] raw whether to offload rendering of the meta information
+ *		   (location, category) to systemd-journal.
+ */
+void log_target_systemd_set_raw(struct log_target *target, bool raw)
+{
+	target->sd_journal.raw = raw;
+	if (raw) {
+		target->raw_output = _systemd_raw_output;
+		target->output = NULL;
+	} else {
+		target->output = _systemd_output;
+		target->raw_output = NULL;
+	}
+}
+
+/* @} */
diff --git a/src/vty/logging_vty.c b/src/vty/logging_vty.c
index 200b45a..0282350 100644
--- a/src/vty/logging_vty.c
+++ b/src/vty/logging_vty.c
@@ -732,6 +732,64 @@
 }
 #endif /* HAVE_SYSLOG_H */
 
+DEFUN(cfg_log_systemd_journal, cfg_log_systemd_journal_cmd,
+      "log systemd-journal [raw]",
+      LOG_STR "Logging to systemd-journal\n"
+      "Offload rendering of the meta information (location, category) to systemd\n")
+{
+#ifdef ENABLE_SYSTEMD_LOGGING
+	struct log_target *tgt;
+	bool raw = argc > 0;
+
+	log_tgt_mutex_lock();
+	tgt = log_target_find(LOG_TGT_TYPE_SYSTEMD, NULL);
+	if (tgt == NULL) {
+		tgt = log_target_create_systemd(raw);
+		if (tgt == NULL) {
+			vty_out(vty, "%% Unable to create systemd-journal "
+				"log target%s", VTY_NEWLINE);
+			RET_WITH_UNLOCK(CMD_WARNING);
+		}
+		log_add_target(tgt);
+	} else if (tgt->sd_journal.raw != raw) {
+		log_target_systemd_set_raw(tgt, raw);
+	}
+
+	vty->index = tgt;
+	vty->node = CFG_LOG_NODE;
+
+	RET_WITH_UNLOCK(CMD_SUCCESS);
+#else
+	vty_out(vty, "%% systemd-journal logging is not available "
+		"in this build of libosmocore%s", VTY_NEWLINE);
+	return CMD_WARNING;
+#endif /* ENABLE_SYSTEMD_LOGGING */
+}
+
+DEFUN(cfg_no_log_systemd_journal, cfg_no_log_systemd_journal_cmd,
+	"no log systemd-journal",
+	NO_STR LOG_STR "Logging to systemd-journal\n")
+{
+#ifdef ENABLE_SYSTEMD_LOGGING
+	struct log_target *tgt;
+
+	log_tgt_mutex_lock();
+	tgt = log_target_find(LOG_TGT_TYPE_SYSTEMD, NULL);
+	if (!tgt) {
+		vty_out(vty, "%% No systemd-journal logging active%s", VTY_NEWLINE);
+		RET_WITH_UNLOCK(CMD_WARNING);
+	}
+
+	log_target_destroy(tgt);
+
+	RET_WITH_UNLOCK(CMD_SUCCESS);
+#else
+	vty_out(vty, "%% systemd-journal logging is not available "
+		"in this build of libosmocore%s", VTY_NEWLINE);
+	return CMD_WARNING;
+#endif /* ENABLE_SYSTEMD_LOGGING */
+}
+
 DEFUN(cfg_log_gsmtap, cfg_log_gsmtap_cmd,
 	"log gsmtap [HOSTNAME]",
 	LOG_STR "Logging via GSMTAP\n"
@@ -926,6 +984,11 @@
 		vty_out(vty, "log gsmtap %s%s",
 			tgt->tgt_gsmtap.hostname, VTY_NEWLINE);
 		break;
+	case LOG_TGT_TYPE_SYSTEMD:
+		vty_out(vty, "log systemd-journal%s%s",
+			tgt->sd_journal.raw ? " raw" : "",
+			VTY_NEWLINE);
+		break;
 	}
 
 	vty_out(vty, " logging filter all %u%s",
@@ -1127,5 +1190,7 @@
 	install_lib_element(CONFIG_NODE, &cfg_log_syslog_local_cmd);
 	install_lib_element(CONFIG_NODE, &cfg_no_log_syslog_cmd);
 #endif
+	install_lib_element(CONFIG_NODE, &cfg_log_systemd_journal_cmd);
+	install_lib_element(CONFIG_NODE, &cfg_no_log_systemd_journal_cmd);
 	install_lib_element(CONFIG_NODE, &cfg_log_gsmtap_cmd);
 }

-- 
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/20045
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I609f5cf438e6ad9038d8fc95f00add6aac29fb23
Gerrit-Change-Number: 20045
Gerrit-PatchSet: 7
Gerrit-Owner: fixeria <vyanitskiy at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy at sysmocom.de>
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20201019/a23ccec8/attachment.htm>


More information about the gerrit-log mailing list