blob: 99764e648cfeba693846d8431e319417edca8500 [file] [log] [blame]
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +01001/*
Harald Weltee08da972017-11-13 01:00:26 +09002 * (C) 2015 by sysmocom - s.f.m.c. GmbH
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +01003 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +01004 * All Rights Reserved
5 *
Harald Weltee08da972017-11-13 01:00:26 +09006 * SPDX-License-Identifier: GPL-2.0+
7 *
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +01008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
Harald Welteeb5b6ce2017-10-15 20:03:24 +020024/*! \addtogroup stats
25 * @{
26 * \file stats_statsd.c */
27
Harald Welte67bdd802017-01-15 17:56:11 +010028#include "config.h"
29#if !defined(EMBEDDED)
30
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010031#include <osmocom/core/stats.h>
32
33#include <string.h>
34#include <stdint.h>
Pau Espin Pedrol3f2775b2020-11-28 01:03:56 +010035#include <inttypes.h>
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010036#include <errno.h>
37
38#include <osmocom/core/utils.h>
39#include <osmocom/core/logging.h>
40#include <osmocom/core/rate_ctr.h>
41#include <osmocom/core/stat_item.h>
42#include <osmocom/core/msgb.h>
Harald Welte1554f802016-11-11 15:06:06 +010043#include <osmocom/core/stats.h>
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010044
45static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep,
46 const struct rate_ctr_group *ctrg,
47 const struct rate_ctr_desc *desc,
48 int64_t value, int64_t delta);
49static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep,
50 const struct osmo_stat_item_group *statg,
Alexander Couzens27a35ed2016-10-04 17:13:58 +020051 const struct osmo_stat_item_desc *desc, int64_t value);
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010052
Harald Welteeb5b6ce2017-10-15 20:03:24 +020053/*! Create a stats_reporter reporting to statsd. This creates a stats_reporter
54 * instance which reports the related statistics data to statsd.
55 * \param[in] name Name of the to-be-created stats_reporter
56 * \returns stats_reporter on success; NULL on error */
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010057struct osmo_stats_reporter *osmo_stats_reporter_create_statsd(const char *name)
58{
59 struct osmo_stats_reporter *srep;
60 srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_STATSD, name);
61
62 srep->have_net_config = 1;
63
64 srep->open = osmo_stats_reporter_udp_open;
65 srep->close = osmo_stats_reporter_udp_close;
66 srep->send_counter = osmo_stats_reporter_statsd_send_counter;
67 srep->send_item = osmo_stats_reporter_statsd_send_item;
68
69 return srep;
70}
71
Alexander Couzens9af70762018-07-24 16:37:54 +020072/*! Replace all illegal ':' in the stats name, but not when used as value seperator.
73 * ':' is used as seperator between the name and the value in the statsd protocol.
74 * \param[inout] buf is a null terminated string containing name, value, unit. */
75static void osmo_stats_reporter_sanitize_name(char *buf)
76{
77 /* e.g. msc.loc_update_type:normal:1|c -> msc.loc_update_type.normal:1|c
78 * last is the seperator between name and value */
79 char *last = strrchr(buf, ':');
80 char *tmp = strchr(buf, ':');
81
82 if (!last)
83 return;
84
85 while (tmp < last) {
86 *tmp = '.';
87 tmp = strchr(buf, ':');
88 }
89}
90
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010091static int osmo_stats_reporter_statsd_send(struct osmo_stats_reporter *srep,
Alexander Couzens27a35ed2016-10-04 17:13:58 +020092 const char *name1, unsigned int index1, const char *name2, int64_t value,
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010093 const char *unit)
94{
95 char *buf;
96 int buf_size;
97 int nchars, rc = 0;
98 char *fmt = NULL;
99 char *prefix = srep->name_prefix;
100 int old_len = msgb_length(srep->buffer);
101
102 if (prefix) {
Kirill Zakharenko0ae0fa12020-04-23 17:33:12 +0300103 if (name1)
Pau Espin Pedrol3f2775b2020-11-28 01:03:56 +0100104 fmt = "%1$s.%2$s.%6$u.%3$s:%4$" PRId64 "|%5$s";
Kirill Zakharenko0ae0fa12020-04-23 17:33:12 +0300105 else
Pau Espin Pedrol3f2775b2020-11-28 01:03:56 +0100106 fmt = "%1$s.%2$0.0s%3$s:%4$" PRId64 "|%5$s";
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100107 } else {
108 prefix = "";
Kirill Zakharenko0ae0fa12020-04-23 17:33:12 +0300109 if (name1)
Pau Espin Pedrol3f2775b2020-11-28 01:03:56 +0100110 fmt = "%1$s%2$s.%6$u.%3$s:%4$" PRId64 "|%5$s";
Kirill Zakharenko0ae0fa12020-04-23 17:33:12 +0300111 else
Pau Espin Pedrol3f2775b2020-11-28 01:03:56 +0100112 fmt = "%1$s%2$0.0s%3$s:%4$" PRId64 "|%5$s";
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100113 }
114
115 if (srep->agg_enabled) {
116 if (msgb_length(srep->buffer) > 0 &&
117 msgb_tailroom(srep->buffer) > 0)
118 {
119 msgb_put_u8(srep->buffer, '\n');
120 }
121 }
122
123 buf = (char *)msgb_put(srep->buffer, 0);
124 buf_size = msgb_tailroom(srep->buffer);
125
126 nchars = snprintf(buf, buf_size, fmt,
127 prefix, name1, name2,
128 value, unit, index1);
129
130 if (nchars >= buf_size) {
131 /* Truncated */
132 /* Restore original buffer (without trailing LF) */
133 msgb_trim(srep->buffer, old_len);
134 /* Send it */
135 rc = osmo_stats_reporter_send_buffer(srep);
136
137 /* Try again */
138 buf = (char *)msgb_put(srep->buffer, 0);
139 buf_size = msgb_tailroom(srep->buffer);
140
141 nchars = snprintf(buf, buf_size, fmt,
142 prefix, name1, name2,
143 value, unit, index1);
144
145 if (nchars >= buf_size)
146 return -EMSGSIZE;
147 }
148
Alexander Couzens9af70762018-07-24 16:37:54 +0200149 if (nchars > 0) {
150 osmo_stats_reporter_sanitize_name(buf);
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100151 msgb_trim(srep->buffer, msgb_length(srep->buffer) + nchars);
Alexander Couzens9af70762018-07-24 16:37:54 +0200152 }
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100153
154 if (!srep->agg_enabled)
155 rc = osmo_stats_reporter_send_buffer(srep);
156
157 return rc;
158}
159
160static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep,
161 const struct rate_ctr_group *ctrg,
162 const struct rate_ctr_desc *desc,
163 int64_t value, int64_t delta)
164{
165 if (ctrg)
166 return osmo_stats_reporter_statsd_send(srep,
167 ctrg->desc->group_name_prefix,
168 ctrg->idx,
169 desc->name, delta, "c");
170 else
171 return osmo_stats_reporter_statsd_send(srep,
172 NULL, 0,
173 desc->name, delta, "c");
174}
175
176static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep,
177 const struct osmo_stat_item_group *statg,
Alexander Couzens27a35ed2016-10-04 17:13:58 +0200178 const struct osmo_stat_item_desc *desc, int64_t value)
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100179{
Daniel Willmann0c878fd2018-10-11 17:55:28 +0200180 if (value < 0) {
181 return osmo_stats_reporter_statsd_send(srep,
Jacob Erlbeckaf5bad52015-11-27 18:54:58 +0100182 statg->desc->group_name_prefix,
183 statg->idx,
Daniel Willmann0c878fd2018-10-11 17:55:28 +0200184 desc->name, 0, "g");
185 } else {
186 return osmo_stats_reporter_statsd_send(srep,
187 statg->desc->group_name_prefix,
188 statg->idx,
189 desc->name, value, "g");
Jacob Erlbeckaf5bad52015-11-27 18:54:58 +0100190 }
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100191}
Harald Welte67bdd802017-01-15 17:56:11 +0100192#endif /* !EMBEDDED */
Harald Welteeb5b6ce2017-10-15 20:03:24 +0200193
194/* @} */