aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac13
-rw-r--r--include/osmocom/core/logging.h7
-rw-r--r--src/Makefile.am5
-rw-r--r--src/logging_systemd.c121
-rw-r--r--src/vty/logging_vty.c65
5 files changed, 211 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index b07a3bd6..e8671974 100644
--- a/configure.ac
+++ b/configure.ac
@@ -181,6 +181,19 @@ then
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 36ce941c..6d0d5a3a 100644
--- a/include/osmocom/core/logging.h
+++ b/include/osmocom/core/logging.h
@@ -244,6 +244,7 @@ enum log_target_type {
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 @@ struct log_target {
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 @@ struct log_target *log_target_create_gsmtap(const char *host, uint16_t port,
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 891b4a6f..b2c9204f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -71,5 +71,10 @@ if ENABLE_SERIAL
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 00000000..7c966863
--- /dev/null
+++ b/src/logging_systemd.c
@@ -0,0 +1,121 @@
+/*
+ * (C) 2020 by Vadim Yanitskiy <axilirator@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 200b45a1..02823504 100644
--- a/src/vty/logging_vty.c
+++ b/src/vty/logging_vty.c
@@ -732,6 +732,64 @@ DEFUN(cfg_no_log_syslog, cfg_no_log_syslog_cmd,
}
#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 @@ static int config_write_log_single(struct vty *vty, struct log_target *tgt)
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 @@ void logging_vty_add_cmds()
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);
}