blob: b27baff80958fd792d7b7909b6be9b46740764c2 [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 *
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010018 */
19
Harald Welteeb5b6ce2017-10-15 20:03:24 +020020/*! \addtogroup stats
21 * @{
22 * \file stats_statsd.c */
23
Harald Welte67bdd802017-01-15 17:56:11 +010024#include "config.h"
25#if !defined(EMBEDDED)
26
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010027#include <osmocom/core/stats.h>
28
29#include <string.h>
30#include <stdint.h>
Pau Espin Pedrol3f2775b2020-11-28 01:03:56 +010031#include <inttypes.h>
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010032#include <errno.h>
33
34#include <osmocom/core/utils.h>
35#include <osmocom/core/logging.h>
36#include <osmocom/core/rate_ctr.h>
37#include <osmocom/core/stat_item.h>
38#include <osmocom/core/msgb.h>
Harald Welte1554f802016-11-11 15:06:06 +010039#include <osmocom/core/stats.h>
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010040
41static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep,
42 const struct rate_ctr_group *ctrg,
43 const struct rate_ctr_desc *desc,
44 int64_t value, int64_t delta);
45static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep,
46 const struct osmo_stat_item_group *statg,
Alexander Couzens27a35ed2016-10-04 17:13:58 +020047 const struct osmo_stat_item_desc *desc, int64_t value);
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010048
Harald Welteeb5b6ce2017-10-15 20:03:24 +020049/*! Create a stats_reporter reporting to statsd. This creates a stats_reporter
50 * instance which reports the related statistics data to statsd.
51 * \param[in] name Name of the to-be-created stats_reporter
52 * \returns stats_reporter on success; NULL on error */
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010053struct osmo_stats_reporter *osmo_stats_reporter_create_statsd(const char *name)
54{
55 struct osmo_stats_reporter *srep;
56 srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_STATSD, name);
Harald Weltee8e24c72022-05-08 10:01:52 +020057 if (!srep)
58 return NULL;
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010059
60 srep->have_net_config = 1;
61
62 srep->open = osmo_stats_reporter_udp_open;
63 srep->close = osmo_stats_reporter_udp_close;
64 srep->send_counter = osmo_stats_reporter_statsd_send_counter;
65 srep->send_item = osmo_stats_reporter_statsd_send_item;
66
67 return srep;
68}
69
Alexander Couzens9af70762018-07-24 16:37:54 +020070/*! Replace all illegal ':' in the stats name, but not when used as value seperator.
71 * ':' is used as seperator between the name and the value in the statsd protocol.
72 * \param[inout] buf is a null terminated string containing name, value, unit. */
73static void osmo_stats_reporter_sanitize_name(char *buf)
74{
75 /* e.g. msc.loc_update_type:normal:1|c -> msc.loc_update_type.normal:1|c
76 * last is the seperator between name and value */
77 char *last = strrchr(buf, ':');
78 char *tmp = strchr(buf, ':');
79
80 if (!last)
81 return;
82
83 while (tmp < last) {
84 *tmp = '.';
85 tmp = strchr(buf, ':');
86 }
87}
88
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010089static int osmo_stats_reporter_statsd_send(struct osmo_stats_reporter *srep,
Pau Espin Pedrol09f075f2021-05-31 13:10:24 +020090 const char *name1, const char *index1, const char *name2, int64_t value,
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010091 const char *unit)
92{
93 char *buf;
94 int buf_size;
95 int nchars, rc = 0;
96 char *fmt = NULL;
97 char *prefix = srep->name_prefix;
98 int old_len = msgb_length(srep->buffer);
99
100 if (prefix) {
Kirill Zakharenko0ae0fa12020-04-23 17:33:12 +0300101 if (name1)
Pau Espin Pedrol09f075f2021-05-31 13:10:24 +0200102 fmt = "%1$s.%2$s.%6$s.%3$s:%4$" PRId64 "|%5$s";
Kirill Zakharenko0ae0fa12020-04-23 17:33:12 +0300103 else
Pau Espin Pedrol3f2775b2020-11-28 01:03:56 +0100104 fmt = "%1$s.%2$0.0s%3$s:%4$" PRId64 "|%5$s";
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100105 } else {
106 prefix = "";
Kirill Zakharenko0ae0fa12020-04-23 17:33:12 +0300107 if (name1)
Pau Espin Pedrol09f075f2021-05-31 13:10:24 +0200108 fmt = "%1$s%2$s.%6$s.%3$s:%4$" PRId64 "|%5$s";
Kirill Zakharenko0ae0fa12020-04-23 17:33:12 +0300109 else
Pau Espin Pedrol3f2775b2020-11-28 01:03:56 +0100110 fmt = "%1$s%2$0.0s%3$s:%4$" PRId64 "|%5$s";
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100111 }
112
113 if (srep->agg_enabled) {
114 if (msgb_length(srep->buffer) > 0 &&
115 msgb_tailroom(srep->buffer) > 0)
116 {
117 msgb_put_u8(srep->buffer, '\n');
118 }
119 }
120
121 buf = (char *)msgb_put(srep->buffer, 0);
122 buf_size = msgb_tailroom(srep->buffer);
123
124 nchars = snprintf(buf, buf_size, fmt,
125 prefix, name1, name2,
126 value, unit, index1);
127
128 if (nchars >= buf_size) {
129 /* Truncated */
130 /* Restore original buffer (without trailing LF) */
131 msgb_trim(srep->buffer, old_len);
132 /* Send it */
133 rc = osmo_stats_reporter_send_buffer(srep);
134
135 /* Try again */
136 buf = (char *)msgb_put(srep->buffer, 0);
137 buf_size = msgb_tailroom(srep->buffer);
138
139 nchars = snprintf(buf, buf_size, fmt,
140 prefix, name1, name2,
141 value, unit, index1);
142
143 if (nchars >= buf_size)
144 return -EMSGSIZE;
145 }
146
Alexander Couzens9af70762018-07-24 16:37:54 +0200147 if (nchars > 0) {
148 osmo_stats_reporter_sanitize_name(buf);
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100149 msgb_trim(srep->buffer, msgb_length(srep->buffer) + nchars);
Alexander Couzens9af70762018-07-24 16:37:54 +0200150 }
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100151
152 if (!srep->agg_enabled)
153 rc = osmo_stats_reporter_send_buffer(srep);
154
155 return rc;
156}
157
158static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep,
159 const struct rate_ctr_group *ctrg,
160 const struct rate_ctr_desc *desc,
161 int64_t value, int64_t delta)
162{
Pau Espin Pedrol09f075f2021-05-31 13:10:24 +0200163 char buf_idx[64];
164 const char *idx_name = buf_idx;
165 const char *prefix;
166
167 if (ctrg) {
168 prefix = ctrg->desc->group_name_prefix;
169 if (ctrg->name)
170 idx_name = ctrg->name;
171 else
172 snprintf(buf_idx, sizeof(buf_idx), "%u", ctrg->idx);
173 } else {
174 prefix = NULL;
175 buf_idx[0] = '0';
176 buf_idx[1] = '\n';
177 }
178 return osmo_stats_reporter_statsd_send(srep, prefix, idx_name, desc->name, delta, "c");
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100179}
180
181static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep,
182 const struct osmo_stat_item_group *statg,
Alexander Couzens27a35ed2016-10-04 17:13:58 +0200183 const struct osmo_stat_item_desc *desc, int64_t value)
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100184{
Pau Espin Pedrol09f075f2021-05-31 13:10:24 +0200185 char buf_idx[64];
186 char *idx_name;
187 if (statg->name)
188 idx_name = statg->name;
189 else {
190 snprintf(buf_idx, sizeof(buf_idx), "%u", statg->idx);
191 idx_name = buf_idx;
Jacob Erlbeckaf5bad52015-11-27 18:54:58 +0100192 }
Pau Espin Pedrol09f075f2021-05-31 13:10:24 +0200193
194 if (value < 0)
195 value = 0;
196
197 return osmo_stats_reporter_statsd_send(srep, statg->desc->group_name_prefix,
198 idx_name, desc->name, value, "g");
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100199}
Harald Welte67bdd802017-01-15 17:56:11 +0100200#endif /* !EMBEDDED */
Harald Welteeb5b6ce2017-10-15 20:03:24 +0200201
202/* @} */