blob: 155f8a2c21812a5c83b4fc022de8445c3cf8c49f [file] [log] [blame]
Jacob Erlbeck95bf82802015-10-20 19:05:52 +02001/*
2 * (C) 2015 by Sysmocom s.f.m.c. GmbH
3 *
4 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
5 *
6 * All Rights Reserved
7 *
8 * 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
24#include <osmocom/core/stats.h>
25
26#include <unistd.h>
27#include <string.h>
28#include <stdint.h>
29#include <errno.h>
30#include <stdio.h>
31#include <sys/socket.h>
32#include <netinet/ip.h>
33#include <arpa/inet.h>
34
35#include <osmocom/core/utils.h>
36#include <osmocom/core/logging.h>
37#include <osmocom/core/rate_ctr.h>
38#include <osmocom/core/stat_item.h>
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010039#include <osmocom/core/timer.h>
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +010040#include <osmocom/core/statistics.h>
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +010041#include <osmocom/core/msgb.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020042
43/* TODO: register properly */
44#define DSTATS DLGLOBAL
45
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010046#define STATS_DEFAULT_INTERVAL 5 /* secs */
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +010047#define STATS_DEFAULT_STATSD_BUFLEN 256
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020048
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010049static LLIST_HEAD(osmo_stats_reporter_list);
50static void *osmo_stats_ctx = NULL;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010051static int is_initialised = 0;
52static int32_t current_stat_item_index = 0;
53
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010054static struct osmo_stats_config s_stats_config = {
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010055 .interval = STATS_DEFAULT_INTERVAL,
56};
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010057struct osmo_stats_config *osmo_stats_config = &s_stats_config;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010058
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010059static struct osmo_timer_list osmo_stats_timer;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020060
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010061static int osmo_stats_reporter_statsd_open(struct osmo_stats_reporter *srep);
62static int osmo_stats_reporter_statsd_close(struct osmo_stats_reporter *srep);
63static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010064 const struct rate_ctr_group *ctrg,
65 const struct rate_ctr_desc *desc,
66 int64_t value, int64_t delta);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010067static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep,
68 const struct osmo_stat_item_group *statg,
69 const struct osmo_stat_item_desc *desc, int value);
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010070
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010071static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010072 const struct rate_ctr_group *ctrg,
73 const struct rate_ctr_desc *desc,
74 int64_t value, int64_t delta);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010075static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
76 const struct osmo_stat_item_group *statg,
77 const struct osmo_stat_item_desc *desc, int value);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010078
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010079static int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020080 int data_len);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010081static int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020082
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010083static int update_srep_config(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020084{
85 int rc = 0;
86
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020087 if (srep->running) {
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010088 if (srep->close)
89 rc = srep->close(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020090 srep->running = 0;
91 }
92
93 if (!srep->enabled)
94 return rc;
95
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010096 if (srep->open)
97 rc = srep->open(srep);
98 else
99 rc = 0;
100
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200101 if (rc < 0)
102 srep->enabled = 0;
103 else
104 srep->running = 1;
105
106 return rc;
107}
108
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100109static void osmo_stats_timer_cb(void *data)
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100110{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100111 int interval = osmo_stats_config->interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100112
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100113 if (!llist_empty(&osmo_stats_reporter_list))
114 osmo_stats_report();
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100115
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100116 osmo_timer_schedule(&osmo_stats_timer, interval, 0);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100117}
118
119static int start_timer()
120{
121 if (!is_initialised)
122 return -ESRCH;
123
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100124 osmo_stats_timer.cb = osmo_stats_timer_cb;
125 osmo_timer_schedule(&osmo_stats_timer, 0, 1);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100126
127 return 0;
128}
129
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100130struct osmo_stats_reporter *osmo_stats_reporter_alloc(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200131 const char *name)
132{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100133 struct osmo_stats_reporter *srep;
134 srep = talloc_zero(osmo_stats_ctx, struct osmo_stats_reporter);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200135 OSMO_ASSERT(srep);
136 srep->type = type;
137 if (name)
138 srep->name = talloc_strdup(srep, name);
139 srep->fd = -1;
140
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100141 llist_add(&srep->list, &osmo_stats_reporter_list);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200142
143 return srep;
144}
145
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100146void osmo_stats_reporter_free(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200147{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100148 osmo_stats_reporter_disable(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200149 llist_del(&srep->list);
150 talloc_free(srep);
151}
152
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100153void osmo_stats_init(void *ctx)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200154{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100155 osmo_stats_ctx = ctx;
156 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100157
158 is_initialised = 1;
159 start_timer();
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200160}
161
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100162struct osmo_stats_reporter *osmo_stats_reporter_find(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200163 const char *name)
164{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100165 struct osmo_stats_reporter *srep;
166 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200167 if (srep->type != type)
168 continue;
169 if (srep->name != name) {
170 if (name == NULL || srep->name == NULL ||
171 strcmp(name, srep->name) != 0)
172 continue;
173 }
174 return srep;
175 }
176 return NULL;
177}
178
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100179int osmo_stats_reporter_set_remote_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200180{
181 int rc;
182 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
183 struct in_addr inaddr;
184
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100185 if (!srep->have_net_config)
186 return -ENOTSUP;
187
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200188 OSMO_ASSERT(addr != NULL);
189
190 rc = inet_pton(AF_INET, addr, &inaddr);
191 if (rc <= 0)
192 return -EINVAL;
193
194 sock_addr->sin_addr = inaddr;
195 sock_addr->sin_family = AF_INET;
196 srep->dest_addr_len = sizeof(*sock_addr);
197
198 talloc_free(srep->dest_addr_str);
199 srep->dest_addr_str = talloc_strdup(srep, addr);
200
201 return update_srep_config(srep);
202}
203
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100204int osmo_stats_reporter_set_remote_port(struct osmo_stats_reporter *srep, int port)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200205{
206 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
207
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100208 if (!srep->have_net_config)
209 return -ENOTSUP;
210
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200211 srep->dest_port = port;
212 sock_addr->sin_port = htons(port);
213
214 return update_srep_config(srep);
215}
216
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100217int osmo_stats_reporter_set_local_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200218{
219 int rc;
220 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->bind_addr;
221 struct in_addr inaddr;
222
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100223 if (!srep->have_net_config)
224 return -ENOTSUP;
225
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200226 if (addr) {
227 rc = inet_pton(AF_INET, addr, &inaddr);
228 if (rc <= 0)
229 return -EINVAL;
230 } else {
231 addr = INADDR_ANY;
232 }
233
234 sock_addr->sin_addr = inaddr;
235 sock_addr->sin_family = AF_INET;
236 srep->bind_addr_len = addr ? sizeof(*sock_addr) : 0;
237
238 talloc_free(srep->bind_addr_str);
239 srep->bind_addr_str = addr ? talloc_strdup(srep, addr) : NULL;
240
241 return update_srep_config(srep);
242}
243
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100244int osmo_stats_reporter_set_mtu(struct osmo_stats_reporter *srep, int mtu)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100245{
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100246 if (!srep->have_net_config)
247 return -ENOTSUP;
248
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100249 if (mtu < 0)
250 return -EINVAL;
251
252 srep->mtu = mtu;
253
254 return update_srep_config(srep);
255}
256
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100257int osmo_stats_set_interval(int interval)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200258{
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100259 if (interval <= 0)
260 return -EINVAL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200261
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100262 osmo_stats_config->interval = interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100263 if (is_initialised)
264 start_timer();
265
266 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200267}
268
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100269int osmo_stats_reporter_set_name_prefix(struct osmo_stats_reporter *srep, const char *prefix)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200270{
271 talloc_free(srep->name_prefix);
272 srep->name_prefix = prefix ? talloc_strdup(srep, prefix) : NULL;
273
274 return update_srep_config(srep);
275}
276
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100277int osmo_stats_reporter_enable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200278{
279 srep->enabled = 1;
280
281 return update_srep_config(srep);
282}
283
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100284int osmo_stats_reporter_disable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200285{
286 srep->enabled = 0;
287
288 return update_srep_config(srep);
289}
290
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100291static int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200292 int data_len)
293{
294 int rc;
295
296 rc = sendto(srep->fd, data, data_len, MSG_NOSIGNAL | MSG_DONTWAIT,
297 &srep->dest_addr, srep->dest_addr_len);
298
299 if (rc == -1)
300 rc = -errno;
301
302 return rc;
303}
304
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100305static int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100306{
307 int rc;
308
309 if (!srep->buffer || msgb_length(srep->buffer) == 0)
310 return 0;
311
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100312 rc = osmo_stats_reporter_send(srep,
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100313 (const char *)msgb_data(srep->buffer), msgb_length(srep->buffer));
314
315 msgb_trim(srep->buffer, 0);
316
317 return rc;
318}
319
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100320/*** log reporter ***/
321
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100322struct osmo_stats_reporter *osmo_stats_reporter_create_log(const char *name)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100323{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100324 struct osmo_stats_reporter *srep;
325 srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_LOG, name);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100326
327 srep->have_net_config = 0;
328
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100329 srep->send_counter = osmo_stats_reporter_log_send_counter;
330 srep->send_item = osmo_stats_reporter_log_send_item;
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100331
332 return srep;
333}
334
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100335static int osmo_stats_reporter_log_send(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100336 const char *type,
337 const char *name1, int index1, const char *name2, int value,
338 const char *unit)
339{
340 LOGP(DSTATS, LOGL_INFO,
341 "stats t=%s p=%s g=%s i=%d n=%s v=%d u=%s\n",
342 type, srep->name_prefix ? srep->name_prefix : "",
343 name1 ? name1 : "", index1,
344 name2, value, unit ? unit : "");
345
346 return 0;
347}
348
349
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100350static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100351 const struct rate_ctr_group *ctrg,
352 const struct rate_ctr_desc *desc,
353 int64_t value, int64_t delta)
354{
355 if (ctrg)
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100356 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100357 ctrg->desc->group_name_prefix,
358 ctrg->idx,
359 desc->name, value, NULL);
360 else
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100361 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100362 NULL, -1,
363 desc->name, value, NULL);
364}
365
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100366static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
367 const struct osmo_stat_item_group *statg,
368 const struct osmo_stat_item_desc *desc, int value)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100369{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100370 return osmo_stats_reporter_log_send(srep, "i",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100371 statg->desc->group_name_prefix, statg->idx,
372 desc->name, value, desc->unit);
373}
374
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200375/*** statsd reporter ***/
376
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100377struct osmo_stats_reporter *osmo_stats_reporter_create_statsd(const char *name)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200378{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100379 struct osmo_stats_reporter *srep;
380 srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_STATSD, name);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200381
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100382 srep->have_net_config = 1;
383
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100384 srep->open = osmo_stats_reporter_statsd_open;
385 srep->close = osmo_stats_reporter_statsd_close;
386 srep->send_counter = osmo_stats_reporter_statsd_send_counter;
387 srep->send_item = osmo_stats_reporter_statsd_send_item;
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100388
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200389 return srep;
390}
391
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100392static int osmo_stats_reporter_statsd_open(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200393{
394 int sock;
395 int rc;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100396 int buffer_size = STATS_DEFAULT_STATSD_BUFLEN;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200397
398 if (srep->fd != -1)
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100399 osmo_stats_reporter_statsd_close(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200400
401 sock = socket(AF_INET, SOCK_DGRAM, 0);
402 if (sock == -1)
403 return -errno;
404
405 if (srep->bind_addr_len > 0) {
406 rc = bind(sock, &srep->bind_addr, srep->bind_addr_len);
407 if (rc == -1)
408 goto failed;
409 }
410
411 srep->fd = sock;
412
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100413 if (srep->mtu > 0) {
414 buffer_size = srep->mtu - 20 /* IP */ - 8 /* UDP */;
415 srep->agg_enabled = 1;
416 }
417
418 srep->buffer = msgb_alloc(buffer_size, "stats buffer");
419
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200420 return 0;
421
422failed:
423 rc = -errno;
424 close(sock);
425
426 return rc;
427}
428
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100429static int osmo_stats_reporter_statsd_close(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200430{
431 int rc;
432 if (srep->fd == -1)
433 return -EBADF;
434
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100435 osmo_stats_reporter_send_buffer(srep);
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100436
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200437 rc = close(srep->fd);
438 srep->fd = -1;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100439 msgb_free(srep->buffer);
440 srep->buffer = NULL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200441 return rc == -1 ? -errno : 0;
442}
443
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100444static int osmo_stats_reporter_statsd_send(struct osmo_stats_reporter *srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200445 const char *name1, int index1, const char *name2, int value,
446 const char *unit)
447{
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100448 char *buf;
449 int buf_size;
450 int nchars, rc = 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200451 char *fmt = NULL;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100452 int old_len = msgb_length(srep->buffer);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200453
454 if (name1) {
455 if (index1 > 0)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100456 fmt = "%1$s.%2$s.%6$d.%3$s:%4$d|%5$s";
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200457 else
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100458 fmt = "%1$s.%2$s.%3$s:%4$d|%5$s";
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200459 } else {
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100460 fmt = "%1$s.%2$0.0s%3$s:%4$d|%5$s";
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200461 }
462 if (!srep->name_prefix)
463 fmt += 5; /* skip prefix part */
464
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100465 if (srep->agg_enabled) {
466 if (msgb_length(srep->buffer) > 0 &&
467 msgb_tailroom(srep->buffer) > 0)
468 {
469 msgb_put_u8(srep->buffer, '\n');
470 }
471 }
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200472
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100473 buf = (char *)msgb_put(srep->buffer, 0);
474 buf_size = msgb_tailroom(srep->buffer);
475
476 nchars = snprintf(buf, buf_size, fmt,
477 srep->name_prefix, name1, name2,
478 value, unit, index1);
479
480 if (nchars >= buf_size) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200481 /* Truncated */
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100482 /* Restore original buffer (without trailing LF) */
483 msgb_trim(srep->buffer, old_len);
484 /* Send it */
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100485 rc = osmo_stats_reporter_send_buffer(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200486
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100487 /* Try again */
488 buf = (char *)msgb_put(srep->buffer, 0);
489 buf_size = msgb_tailroom(srep->buffer);
490
491 nchars = snprintf(buf, buf_size, fmt,
492 srep->name_prefix, name1, name2,
493 value, unit, index1);
494
495 if (nchars >= buf_size)
496 return -EMSGSIZE;
497 }
498
499 if (nchars > 0)
500 msgb_trim(srep->buffer, msgb_length(srep->buffer) + nchars);
501
502 if (!srep->agg_enabled)
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100503 rc = osmo_stats_reporter_send_buffer(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200504
505 return rc;
506}
507
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100508static int osmo_stats_reporter_statsd_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200509 const struct rate_ctr_group *ctrg,
510 const struct rate_ctr_desc *desc,
511 int64_t value, int64_t delta)
512{
513 if (ctrg)
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100514 return osmo_stats_reporter_statsd_send(srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200515 ctrg->desc->group_name_prefix,
516 ctrg->idx,
517 desc->name, delta, "c");
518 else
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100519 return osmo_stats_reporter_statsd_send(srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200520 NULL, -1,
521 desc->name, delta, "c");
522}
523
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100524static int osmo_stats_reporter_statsd_send_item(struct osmo_stats_reporter *srep,
525 const struct osmo_stat_item_group *statg,
526 const struct osmo_stat_item_desc *desc, int value)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200527{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100528 return osmo_stats_reporter_statsd_send(srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200529 statg->desc->group_name_prefix, statg->idx,
530 desc->name, value, desc->unit);
531}
532
533/*** generic rate counter support ***/
534
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100535static int osmo_stats_reporter_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200536 const struct rate_ctr_group *ctrg,
537 const struct rate_ctr_desc *desc,
538 int64_t value, int64_t delta)
539{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100540 if (!srep->send_counter)
541 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200542
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100543 return srep->send_counter(srep, ctrg, desc, value, delta);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200544}
545
546static int rate_ctr_handler(
547 struct rate_ctr_group *ctrg, struct rate_ctr *ctr,
548 const struct rate_ctr_desc *desc, void *sctx_)
549{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100550 struct osmo_stats_reporter *srep;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200551 int rc;
552 int64_t delta = rate_ctr_difference(ctr);
553
554 if (delta == 0)
555 return 0;
556
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100557 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200558 if (!srep->running)
559 continue;
560
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100561 rc = osmo_stats_reporter_send_counter(srep, ctrg, desc,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200562 ctr->current, delta);
563
564 /* TODO: handle rc (log?, inc counter(!)?) or remove it */
565 }
566
567 return 0;
568}
569
570static int rate_ctr_group_handler(struct rate_ctr_group *ctrg, void *sctx_)
571{
572 rate_ctr_for_each_counter(ctrg, rate_ctr_handler, sctx_);
573
574 return 0;
575}
576
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100577/*** stat item support ***/
578
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100579static int osmo_stats_reporter_send_item(struct osmo_stats_reporter *srep,
580 const struct osmo_stat_item_group *statg,
581 const struct osmo_stat_item_desc *desc,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100582 int32_t value)
583{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100584 if (!srep->send_item)
585 return 0;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100586
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100587 return srep->send_item(srep, statg, desc, value);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100588}
589
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100590static int osmo_stat_item_handler(
591 struct osmo_stat_item_group *statg, struct osmo_stat_item *item, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100592{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100593 struct osmo_stats_reporter *srep;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100594 int rc;
595 int32_t idx = current_stat_item_index;
596 int32_t value;
597
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100598 while (osmo_stat_item_get_next(item, &idx, &value) > 0) {
599 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100600 if (!srep->running)
601 continue;
602
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100603 rc = osmo_stats_reporter_send_item(srep, statg,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100604 item->desc, value);
605 }
606 }
607
608 return 0;
609}
610
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100611static int osmo_stat_item_group_handler(struct osmo_stat_item_group *statg, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100612{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100613 osmo_stat_item_for_each_item(statg, osmo_stat_item_handler, sctx_);
614 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100615
616 return 0;
617}
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200618
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100619/*** osmo counter support ***/
620
621static int handle_counter(struct osmo_counter *counter, void *sctx_)
622{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100623 struct osmo_stats_reporter *srep;
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100624 int rc;
625 struct rate_ctr_desc desc = {0};
626 /* Fake a rate counter description */
627 desc.name = counter->name;
628 desc.description = counter->description;
629
630 int delta = osmo_counter_difference(counter);
631
632 if (delta == 0)
633 return 0;
634
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100635 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100636 if (!srep->running)
637 continue;
638
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100639 rc = osmo_stats_reporter_send_counter(srep, NULL, &desc,
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100640 counter->value, delta);
641
642 /* TODO: handle rc (log?, inc counter(!)?) */
643 }
644
645 return 0;
646}
647
648
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200649/*** main reporting function ***/
650
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100651static void flush_all_reporters()
652{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100653 struct osmo_stats_reporter *srep;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100654
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100655 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100656 if (!srep->running)
657 continue;
658
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100659 osmo_stats_reporter_send_buffer(srep);
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100660 }
661}
662
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100663int osmo_stats_report()
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200664{
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100665 osmo_counters_for_each(handle_counter, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200666 rate_ctr_for_each_group(rate_ctr_group_handler, NULL);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100667 osmo_stat_item_for_each_group(osmo_stat_item_group_handler, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200668
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100669 flush_all_reporters();
670
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200671 return 0;
672}