2015-11-09 14:33:44 +00:00
|
|
|
/*
|
2017-11-12 16:00:26 +00:00
|
|
|
* (C) 2015 by sysmocom - s.f.m.c. GmbH
|
2015-11-09 14:33:44 +00:00
|
|
|
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
2017-11-12 16:00:26 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
|
|
*
|
2015-11-09 14:33:44 +00:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2017-10-15 18:03:24 +00:00
|
|
|
/*! \addtogroup stats
|
|
|
|
* @{
|
|
|
|
* \file stats_statsd.c */
|
|
|
|
|
2017-01-15 16:56:11 +00:00
|
|
|
#include "config.h"
|
|
|
|
#if !defined(EMBEDDED)
|
|
|
|
|
2015-11-09 14:33:44 +00:00
|
|
|
#include <osmocom/core/stats.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <osmocom/core/utils.h>
|
|
|
|
#include <osmocom/core/logging.h>
|
|
|
|
#include <osmocom/core/rate_ctr.h>
|
|
|
|
#include <osmocom/core/stat_item.h>
|
|
|
|
#include <osmocom/core/msgb.h>
|
2016-11-11 14:06:06 +00:00
|
|
|
#include <osmocom/core/stats.h>
|
2015-11-09 14:33:44 +00:00
|
|
|
|
|
|
|
static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep,
|
|
|
|
const struct rate_ctr_group *ctrg,
|
|
|
|
const struct rate_ctr_desc *desc,
|
|
|
|
int64_t value, int64_t delta);
|
|
|
|
static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep,
|
|
|
|
const struct osmo_stat_item_group *statg,
|
2016-10-04 15:13:58 +00:00
|
|
|
const struct osmo_stat_item_desc *desc, int64_t value);
|
2015-11-09 14:33:44 +00:00
|
|
|
|
2017-10-15 18:03:24 +00:00
|
|
|
/*! Create a stats_reporter reporting to statsd. This creates a stats_reporter
|
|
|
|
* instance which reports the related statistics data to statsd.
|
|
|
|
* \param[in] name Name of the to-be-created stats_reporter
|
|
|
|
* \returns stats_reporter on success; NULL on error */
|
2015-11-09 14:33:44 +00:00
|
|
|
struct osmo_stats_reporter *osmo_stats_reporter_create_statsd(const char *name)
|
|
|
|
{
|
|
|
|
struct osmo_stats_reporter *srep;
|
|
|
|
srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_STATSD, name);
|
|
|
|
|
|
|
|
srep->have_net_config = 1;
|
|
|
|
|
|
|
|
srep->open = osmo_stats_reporter_udp_open;
|
|
|
|
srep->close = osmo_stats_reporter_udp_close;
|
|
|
|
srep->send_counter = osmo_stats_reporter_statsd_send_counter;
|
|
|
|
srep->send_item = osmo_stats_reporter_statsd_send_item;
|
|
|
|
|
|
|
|
return srep;
|
|
|
|
}
|
|
|
|
|
2018-07-24 14:37:54 +00:00
|
|
|
/*! Replace all illegal ':' in the stats name, but not when used as value seperator.
|
|
|
|
* ':' is used as seperator between the name and the value in the statsd protocol.
|
|
|
|
* \param[inout] buf is a null terminated string containing name, value, unit. */
|
|
|
|
static void osmo_stats_reporter_sanitize_name(char *buf)
|
|
|
|
{
|
|
|
|
/* e.g. msc.loc_update_type:normal:1|c -> msc.loc_update_type.normal:1|c
|
|
|
|
* last is the seperator between name and value */
|
|
|
|
char *last = strrchr(buf, ':');
|
|
|
|
char *tmp = strchr(buf, ':');
|
|
|
|
|
|
|
|
if (!last)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (tmp < last) {
|
|
|
|
*tmp = '.';
|
|
|
|
tmp = strchr(buf, ':');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 14:33:44 +00:00
|
|
|
static int osmo_stats_reporter_statsd_send(struct osmo_stats_reporter *srep,
|
2016-10-04 15:13:58 +00:00
|
|
|
const char *name1, unsigned int index1, const char *name2, int64_t value,
|
2015-11-09 14:33:44 +00:00
|
|
|
const char *unit)
|
|
|
|
{
|
|
|
|
char *buf;
|
|
|
|
int buf_size;
|
|
|
|
int nchars, rc = 0;
|
|
|
|
char *fmt = NULL;
|
|
|
|
char *prefix = srep->name_prefix;
|
|
|
|
int old_len = msgb_length(srep->buffer);
|
|
|
|
|
|
|
|
if (prefix) {
|
|
|
|
if (name1) {
|
|
|
|
if (index1 != 0)
|
|
|
|
fmt = "%1$s.%2$s.%6$u.%3$s:%4$d|%5$s";
|
|
|
|
else
|
|
|
|
fmt = "%1$s.%2$s.%3$s:%4$d|%5$s";
|
|
|
|
} else {
|
|
|
|
fmt = "%1$s.%2$0.0s%3$s:%4$d|%5$s";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
prefix = "";
|
|
|
|
if (name1) {
|
|
|
|
if (index1 != 0)
|
|
|
|
fmt = "%1$s%2$s.%6$u.%3$s:%4$d|%5$s";
|
|
|
|
else
|
|
|
|
fmt = "%1$s%2$s.%3$s:%4$d|%5$s";
|
|
|
|
} else {
|
|
|
|
fmt = "%1$s%2$0.0s%3$s:%4$d|%5$s";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (srep->agg_enabled) {
|
|
|
|
if (msgb_length(srep->buffer) > 0 &&
|
|
|
|
msgb_tailroom(srep->buffer) > 0)
|
|
|
|
{
|
|
|
|
msgb_put_u8(srep->buffer, '\n');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = (char *)msgb_put(srep->buffer, 0);
|
|
|
|
buf_size = msgb_tailroom(srep->buffer);
|
|
|
|
|
|
|
|
nchars = snprintf(buf, buf_size, fmt,
|
|
|
|
prefix, name1, name2,
|
|
|
|
value, unit, index1);
|
|
|
|
|
|
|
|
if (nchars >= buf_size) {
|
|
|
|
/* Truncated */
|
|
|
|
/* Restore original buffer (without trailing LF) */
|
|
|
|
msgb_trim(srep->buffer, old_len);
|
|
|
|
/* Send it */
|
|
|
|
rc = osmo_stats_reporter_send_buffer(srep);
|
|
|
|
|
|
|
|
/* Try again */
|
|
|
|
buf = (char *)msgb_put(srep->buffer, 0);
|
|
|
|
buf_size = msgb_tailroom(srep->buffer);
|
|
|
|
|
|
|
|
nchars = snprintf(buf, buf_size, fmt,
|
|
|
|
prefix, name1, name2,
|
|
|
|
value, unit, index1);
|
|
|
|
|
|
|
|
if (nchars >= buf_size)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2018-07-24 14:37:54 +00:00
|
|
|
if (nchars > 0) {
|
|
|
|
osmo_stats_reporter_sanitize_name(buf);
|
2015-11-09 14:33:44 +00:00
|
|
|
msgb_trim(srep->buffer, msgb_length(srep->buffer) + nchars);
|
2018-07-24 14:37:54 +00:00
|
|
|
}
|
2015-11-09 14:33:44 +00:00
|
|
|
|
|
|
|
if (!srep->agg_enabled)
|
|
|
|
rc = osmo_stats_reporter_send_buffer(srep);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep,
|
|
|
|
const struct rate_ctr_group *ctrg,
|
|
|
|
const struct rate_ctr_desc *desc,
|
|
|
|
int64_t value, int64_t delta)
|
|
|
|
{
|
|
|
|
if (ctrg)
|
|
|
|
return osmo_stats_reporter_statsd_send(srep,
|
|
|
|
ctrg->desc->group_name_prefix,
|
|
|
|
ctrg->idx,
|
|
|
|
desc->name, delta, "c");
|
|
|
|
else
|
|
|
|
return osmo_stats_reporter_statsd_send(srep,
|
|
|
|
NULL, 0,
|
|
|
|
desc->name, delta, "c");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep,
|
|
|
|
const struct osmo_stat_item_group *statg,
|
2016-10-04 15:13:58 +00:00
|
|
|
const struct osmo_stat_item_desc *desc, int64_t value)
|
2015-11-09 14:33:44 +00:00
|
|
|
{
|
2015-12-17 13:13:22 +00:00
|
|
|
const char *unit = desc->unit;
|
2015-11-27 17:54:58 +00:00
|
|
|
|
|
|
|
if (unit == OSMO_STAT_ITEM_NO_UNIT) {
|
|
|
|
unit = "g";
|
|
|
|
if (value < 0)
|
|
|
|
osmo_stats_reporter_statsd_send(srep,
|
|
|
|
statg->desc->group_name_prefix,
|
|
|
|
statg->idx,
|
|
|
|
desc->name, 0, unit);
|
|
|
|
}
|
2015-11-09 14:33:44 +00:00
|
|
|
return osmo_stats_reporter_statsd_send(srep,
|
|
|
|
statg->desc->group_name_prefix,
|
|
|
|
statg->idx,
|
2015-11-27 17:54:58 +00:00
|
|
|
desc->name, value, unit);
|
2015-11-09 14:33:44 +00:00
|
|
|
}
|
2017-01-15 16:56:11 +00:00
|
|
|
#endif /* !EMBEDDED */
|
2017-10-15 18:03:24 +00:00
|
|
|
|
|
|
|
/* @} */
|