mirror of https://gerrit.osmocom.org/libosmocore
Implement GSMTAP log target
This target wraps the to-be-logged string (With metadata) into a GSMTAP packet and sends it to the configured destination address. Change-Id: I9a7e72b8c9c6f6f2d76d1ea2332dcdee12394625
This commit is contained in:
parent
a65e99331a
commit
aa00f99be2
|
@ -4,3 +4,4 @@ libosmocore change major external talloc dependency / internal talloc removal
|
||||||
libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with presence information
|
libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with presence information
|
||||||
libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with measurement information
|
libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with measurement information
|
||||||
libosmocore change major size of ph_tch_param struct changed / Extend with RTP Marker
|
libosmocore change major size of ph_tch_param struct changed / Extend with RTP Marker
|
||||||
|
libosmocore change major size of struct log_target changed / Extend with GSMTAP
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <osmocom/core/linuxlist.h>
|
#include <osmocom/core/linuxlist.h>
|
||||||
|
|
||||||
/*! \brief Maximum number of logging contexts */
|
/*! \brief Maximum number of logging contexts */
|
||||||
|
@ -122,6 +123,7 @@ typedef int log_filter(const struct log_context *ctx,
|
||||||
|
|
||||||
struct log_info;
|
struct log_info;
|
||||||
struct vty;
|
struct vty;
|
||||||
|
struct gsmtap_inst;
|
||||||
|
|
||||||
typedef void log_print_filters(struct vty *vty,
|
typedef void log_print_filters(struct vty *vty,
|
||||||
const struct log_info *info,
|
const struct log_info *info,
|
||||||
|
@ -156,6 +158,7 @@ enum log_target_type {
|
||||||
LOG_TGT_TYPE_FILE, /*!< \brief text file logging */
|
LOG_TGT_TYPE_FILE, /*!< \brief text file logging */
|
||||||
LOG_TGT_TYPE_STDERR, /*!< \brief stderr logging */
|
LOG_TGT_TYPE_STDERR, /*!< \brief stderr logging */
|
||||||
LOG_TGT_TYPE_STRRB, /*!< \brief osmo_strrb-backed logging */
|
LOG_TGT_TYPE_STRRB, /*!< \brief osmo_strrb-backed logging */
|
||||||
|
LOG_TGT_TYPE_GSMTAP, /*!< \brief GSMTAP network logging */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief structure representing a logging target */
|
/*! \brief structure representing a logging target */
|
||||||
|
@ -204,6 +207,12 @@ struct log_target {
|
||||||
struct {
|
struct {
|
||||||
void *rb;
|
void *rb;
|
||||||
} tgt_rb;
|
} tgt_rb;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct gsmtap_inst *gsmtap_inst;
|
||||||
|
const char *ident;
|
||||||
|
const char *hostname;
|
||||||
|
} tgt_gsmtap;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief call-back function to be called when the logging framework
|
/*! \brief call-back function to be called when the logging framework
|
||||||
|
@ -254,6 +263,7 @@ void log_set_print_filename(struct log_target *target, int);
|
||||||
void log_set_print_category(struct log_target *target, int);
|
void log_set_print_category(struct log_target *target, int);
|
||||||
void log_set_log_level(struct log_target *target, int log_level);
|
void log_set_log_level(struct log_target *target, int log_level);
|
||||||
void log_parse_category_mask(struct log_target *target, const char* mask);
|
void log_parse_category_mask(struct log_target *target, const char* mask);
|
||||||
|
const char* log_category_name(int subsys);
|
||||||
int log_parse_level(const char *lvl);
|
int log_parse_level(const char *lvl);
|
||||||
const char *log_level_str(unsigned int lvl);
|
const char *log_level_str(unsigned int lvl);
|
||||||
int log_parse_category(const char *category);
|
int log_parse_category(const char *category);
|
||||||
|
@ -267,6 +277,10 @@ struct log_target *log_target_create_stderr(void);
|
||||||
struct log_target *log_target_create_file(const char *fname);
|
struct log_target *log_target_create_file(const char *fname);
|
||||||
struct log_target *log_target_create_syslog(const char *ident, int option,
|
struct log_target *log_target_create_syslog(const char *ident, int option,
|
||||||
int facility);
|
int facility);
|
||||||
|
struct log_target *log_target_create_gsmtap(const char *host, uint16_t port,
|
||||||
|
const char *ident,
|
||||||
|
bool ofd_wq_mode,
|
||||||
|
bool add_sink);
|
||||||
int log_target_file_reopen(struct log_target *tgt);
|
int log_target_file_reopen(struct log_target *tgt);
|
||||||
int log_targets_reopen(void);
|
int log_targets_reopen(void);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ libosmocore_la_LIBADD = $(BACKTRACE_LIB) $(TALLOC_LIBS)
|
||||||
libosmocore_la_SOURCES = timer.c timer_gettimeofday.c select.c signal.c msgb.c bits.c \
|
libosmocore_la_SOURCES = timer.c timer_gettimeofday.c select.c signal.c msgb.c bits.c \
|
||||||
bitvec.c bitcomp.c statistics.c fsm.c \
|
bitvec.c bitcomp.c statistics.c fsm.c \
|
||||||
write_queue.c utils.c socket.c \
|
write_queue.c utils.c socket.c \
|
||||||
logging.c logging_syslog.c rate_ctr.c \
|
logging.c logging_syslog.c logging_gsmtap.c rate_ctr.c \
|
||||||
gsmtap_util.c crc16.c panic.c backtrace.c \
|
gsmtap_util.c crc16.c panic.c backtrace.c \
|
||||||
conv.c application.c rbtree.c strrb.c \
|
conv.c application.c rbtree.c strrb.c \
|
||||||
loggingrb.c crc8gen.c crc16gen.c crc32gen.c crc64gen.c \
|
loggingrb.c crc8gen.c crc16gen.c crc32gen.c crc64gen.c \
|
||||||
|
|
|
@ -240,7 +240,7 @@ static const char* color(int subsys)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* category_name(int subsys)
|
const char* log_category_name(int subsys)
|
||||||
{
|
{
|
||||||
if (subsys < osmo_log_info->num_cat)
|
if (subsys < osmo_log_info->num_cat)
|
||||||
return osmo_log_info->cat[subsys].name;
|
return osmo_log_info->cat[subsys].name;
|
||||||
|
@ -290,7 +290,7 @@ static void _output(struct log_target *target, unsigned int subsys,
|
||||||
OSMO_SNPRINTF_RET(ret, rem, offset, len);
|
OSMO_SNPRINTF_RET(ret, rem, offset, len);
|
||||||
}
|
}
|
||||||
if (target->print_category) {
|
if (target->print_category) {
|
||||||
ret = snprintf(buf + offset, rem, "%s ", category_name(subsys));
|
ret = snprintf(buf + offset, rem, "%s ", log_category_name(subsys));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
OSMO_SNPRINTF_RET(ret, rem, offset, len);
|
OSMO_SNPRINTF_RET(ret, rem, offset, len);
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
/* GSMTAP network logging support code */
|
||||||
|
|
||||||
|
/* (C) 2016 by Harald Welte <laforge@gnumonks.org>
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* 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 <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_STRINGS_H
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <osmocom/core/talloc.h>
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/gsmtap.h>
|
||||||
|
#include <osmocom/core/gsmtap_util.h>
|
||||||
|
#include <osmocom/core/logging.h>
|
||||||
|
#include <osmocom/core/timer.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
/* 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(golh->proc_name, target->tgt_gsmtap.ident,
|
||||||
|
sizeof(golh->proc_name));
|
||||||
|
if (subsys_name)
|
||||||
|
osmo_strlcpy(golh->subsys, subsys_name+1, sizeof(golh->subsys));
|
||||||
|
else
|
||||||
|
golh->subsys[0] = '\0';
|
||||||
|
osmo_strlcpy(golh->src_file.name, file, sizeof(golh->src_file.name));
|
||||||
|
golh->src_file.line_nr = htonl(line);
|
||||||
|
golh->level = level;
|
||||||
|
/* we always store the timestamp in the message, irrespective
|
||||||
|
* of hat prrint_[ext_]timestamp say */
|
||||||
|
golh->ts.sec = htonl(tv.tv_sec);
|
||||||
|
golh->ts.usec = htonl(tv.tv_usec);
|
||||||
|
|
||||||
|
rc = vsnprintf((char *) msg->tail, msgb_tailroom(msg), format, ap);
|
||||||
|
if (rc < 0)
|
||||||
|
return;
|
||||||
|
msgb_put(msg, rc);
|
||||||
|
|
||||||
|
gsmtap_sendmsg(target->tgt_gsmtap.gsmtap_inst, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @} */
|
|
@ -29,6 +29,7 @@
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
#include <osmocom/core/strrb.h>
|
#include <osmocom/core/strrb.h>
|
||||||
#include <osmocom/core/loggingrb.h>
|
#include <osmocom/core/loggingrb.h>
|
||||||
|
#include <osmocom/core/gsmtap.h>
|
||||||
|
|
||||||
#include <osmocom/vty/command.h>
|
#include <osmocom/vty/command.h>
|
||||||
#include <osmocom/vty/buffer.h>
|
#include <osmocom/vty/buffer.h>
|
||||||
|
@ -498,6 +499,32 @@ DEFUN(cfg_no_log_syslog, cfg_no_log_syslog_cmd,
|
||||||
}
|
}
|
||||||
#endif /* HAVE_SYSLOG_H */
|
#endif /* HAVE_SYSLOG_H */
|
||||||
|
|
||||||
|
DEFUN(cfg_log_gsmtap, cfg_log_gsmtap_cmd,
|
||||||
|
"log gsmtap [HOSTNAME]",
|
||||||
|
LOG_STR "Logging via GSMTAP\n")
|
||||||
|
{
|
||||||
|
const char *hostname = argv[0];
|
||||||
|
struct log_target *tgt;
|
||||||
|
|
||||||
|
tgt = log_target_find(LOG_TGT_TYPE_GSMTAP, hostname);
|
||||||
|
if (!tgt) {
|
||||||
|
tgt = log_target_create_gsmtap(hostname, GSMTAP_UDP_PORT,
|
||||||
|
host.app_info->name, false,
|
||||||
|
true);
|
||||||
|
if (!tgt) {
|
||||||
|
vty_out(vty, "%% Unable to create GSMTAP log%s",
|
||||||
|
VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
log_add_target(tgt);
|
||||||
|
}
|
||||||
|
|
||||||
|
vty->index = tgt;
|
||||||
|
vty->node = CFG_LOG_NODE;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN(cfg_log_stderr, cfg_log_stderr_cmd,
|
DEFUN(cfg_log_stderr, cfg_log_stderr_cmd,
|
||||||
"log stderr",
|
"log stderr",
|
||||||
LOG_STR "Logging via STDERR of the process\n")
|
LOG_STR "Logging via STDERR of the process\n")
|
||||||
|
@ -652,6 +679,10 @@ static int config_write_log_single(struct vty *vty, struct log_target *tgt)
|
||||||
vty_out(vty, "log alarms %zu%s",
|
vty_out(vty, "log alarms %zu%s",
|
||||||
log_target_rb_avail_size(tgt), VTY_NEWLINE);
|
log_target_rb_avail_size(tgt), VTY_NEWLINE);
|
||||||
break;
|
break;
|
||||||
|
case LOG_TGT_TYPE_GSMTAP:
|
||||||
|
vty_out(vty, "log gsmtap %s%s",
|
||||||
|
tgt->tgt_gsmtap.hostname, VTY_NEWLINE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
vty_out(vty, " logging filter all %u%s",
|
vty_out(vty, " logging filter all %u%s",
|
||||||
|
@ -744,4 +775,5 @@ void logging_vty_add_cmds(const struct log_info *cat)
|
||||||
install_element(CONFIG_NODE, &cfg_log_syslog_local_cmd);
|
install_element(CONFIG_NODE, &cfg_log_syslog_local_cmd);
|
||||||
install_element(CONFIG_NODE, &cfg_no_log_syslog_cmd);
|
install_element(CONFIG_NODE, &cfg_no_log_syslog_cmd);
|
||||||
#endif
|
#endif
|
||||||
|
install_element(CONFIG_NODE, &cfg_log_gsmtap_cmd);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue