diff options
-rw-r--r-- | configure.ac | 13 | ||||
-rw-r--r-- | include/osmocom/core/logging.h | 7 | ||||
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/logging_systemd.c | 121 | ||||
-rw-r--r-- | src/vty/logging_vty.c | 65 |
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); } |