/*! \file logging_gsmtap.c * libosmocore log output encapsulated in GSMTAP. * * Encapsulating the log output inside GSMTAP frames allows us to * observer protocol traces (of Um, Abis, A or any other interface in * the Osmocom world) with synchronous interspersed log messages. */ /* * (C) 2016 by Harald Welte * 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_gsmtap.c */ #include "../config.h" #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include #include #include #include #include #include #include #define GSMTAP_LOG_MAX_SIZE 4096 static void _gsmtap_raw_output(struct log_target *target, int subsys, unsigned int level, const char *file, int line, int cont, const char *format, va_list ap) { struct msgb *msg; struct gsmtap_hdr *gh; struct gsmtap_osmocore_log_hdr *golh; const char *subsys_name = log_category_name(subsys); struct timeval tv; int rc; const char *file_basename; /* get timestamp ASAP */ osmo_gettimeofday(&tv, NULL); msg = msgb_alloc(sizeof(*gh)+sizeof(*golh)+GSMTAP_LOG_MAX_SIZE, "GSMTAP logging"); /* GSMTAP header */ gh = (struct gsmtap_hdr *) msgb_put(msg, sizeof(*gh)); memset(gh, 0, sizeof(*gh)); gh->version = GSMTAP_VERSION; gh->hdr_len = sizeof(*gh)/4; gh->type = GSMTAP_TYPE_OSMOCORE_LOG; /* Logging header */ golh = (struct gsmtap_osmocore_log_hdr *) msgb_put(msg, sizeof(*golh)); OSMO_STRLCPY_ARRAY(golh->proc_name, target->tgt_gsmtap.ident); if (subsys_name) OSMO_STRLCPY_ARRAY(golh->subsys, subsys_name + 1); else golh->subsys[0] = '\0'; /* strip all leading path elements from file, if any. */ file_basename = strrchr(file, '/'); file = (file_basename && file_basename[1])? file_basename + 1 : file; OSMO_STRLCPY_ARRAY(golh->src_file.name, file); golh->src_file.line_nr = osmo_htonl(line); golh->level = level; /* we always store the timestamp in the message, irrespective * of hat prrint_[ext_]timestamp say */ golh->ts.sec = osmo_htonl(tv.tv_sec); golh->ts.usec = osmo_htonl(tv.tv_usec); rc = vsnprintf((char *) msg->tail, msgb_tailroom(msg), format, ap); if (rc < 0) { msgb_free(msg); return; } msgb_put(msg, rc); rc = gsmtap_sendmsg(target->tgt_gsmtap.gsmtap_inst, msg); if (rc) msgb_free(msg); } /*! Create a new logging target for GSMTAP logging * \param[in] ident string identifier * \returns Log target in case of success, NULL in case of error */ 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 *target; struct gsmtap_inst *gti; target = log_target_create(); if (!target) return NULL; gti = gsmtap_source_init(host, port, ofd_wq_mode); if (!gti) { log_target_destroy(target); return NULL; } if (add_sink) gsmtap_source_add_sink(gti); target->tgt_gsmtap.gsmtap_inst = gti; target->tgt_gsmtap.ident = talloc_strdup(target, ident); target->tgt_gsmtap.hostname = talloc_strdup(target, host); target->type = LOG_TGT_TYPE_GSMTAP; target->raw_output = _gsmtap_raw_output; return target; } /* @} */