blob: a5232595780bee73a7cb8e7699cc95ff9f6f1c3d [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
Harald Welte67bdd802017-01-15 17:56:11 +010024#include "config.h"
25#if !defined(EMBEDDED)
26
Harald Welte95871da2017-05-15 12:11:36 +020027#include <osmocom/core/byteswap.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020028#include <osmocom/core/stats.h>
29
30#include <unistd.h>
31#include <string.h>
32#include <stdint.h>
33#include <errno.h>
34#include <stdio.h>
Holger Hans Peter Freytherc3376932015-08-21 19:56:54 +000035#include <sys/types.h>
Harald Welte67bdd802017-01-15 17:56:11 +010036
37#ifdef HAVE_SYS_SOCKET_H
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020038#include <sys/socket.h>
Holger Hans Peter Freytherc3376932015-08-21 19:56:54 +000039#include <netinet/in.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020040#include <arpa/inet.h>
Harald Welte67bdd802017-01-15 17:56:11 +010041#endif
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020042
43#include <osmocom/core/utils.h>
44#include <osmocom/core/logging.h>
45#include <osmocom/core/rate_ctr.h>
46#include <osmocom/core/stat_item.h>
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010047#include <osmocom/core/timer.h>
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +010048#include <osmocom/core/statistics.h>
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +010049#include <osmocom/core/msgb.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020050
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010051#define STATS_DEFAULT_INTERVAL 5 /* secs */
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010052#define STATS_DEFAULT_BUFLEN 256
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020053
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010054static LLIST_HEAD(osmo_stats_reporter_list);
55static void *osmo_stats_ctx = NULL;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010056static int is_initialised = 0;
57static int32_t current_stat_item_index = 0;
58
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010059static struct osmo_stats_config s_stats_config = {
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010060 .interval = STATS_DEFAULT_INTERVAL,
61};
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010062struct osmo_stats_config *osmo_stats_config = &s_stats_config;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010063
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010064static struct osmo_timer_list osmo_stats_timer;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020065
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010066static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010067 const struct rate_ctr_group *ctrg,
68 const struct rate_ctr_desc *desc,
69 int64_t value, int64_t delta);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010070static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
71 const struct osmo_stat_item_group *statg,
Harald Welte1554f802016-11-11 15:06:06 +010072 const struct osmo_stat_item_desc *desc, int64_t value);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010073
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010074static int update_srep_config(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020075{
76 int rc = 0;
77
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020078 if (srep->running) {
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010079 if (srep->close)
80 rc = srep->close(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020081 srep->running = 0;
82 }
83
84 if (!srep->enabled)
85 return rc;
86
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010087 if (srep->open)
88 rc = srep->open(srep);
89 else
90 rc = 0;
91
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020092 if (rc < 0)
93 srep->enabled = 0;
94 else
95 srep->running = 1;
96
Jacob Erlbeckaed7c122015-11-09 11:25:12 +010097 srep->force_single_flush = 1;
98
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020099 return rc;
100}
101
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100102static void osmo_stats_timer_cb(void *data)
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100103{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100104 int interval = osmo_stats_config->interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100105
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100106 if (!llist_empty(&osmo_stats_reporter_list))
107 osmo_stats_report();
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100108
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100109 osmo_timer_schedule(&osmo_stats_timer, interval, 0);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100110}
111
112static int start_timer()
113{
114 if (!is_initialised)
115 return -ESRCH;
116
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +0200117 osmo_timer_setup(&osmo_stats_timer, osmo_stats_timer_cb, NULL);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100118 osmo_timer_schedule(&osmo_stats_timer, 0, 1);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100119
120 return 0;
121}
122
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100123struct osmo_stats_reporter *osmo_stats_reporter_alloc(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200124 const char *name)
125{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100126 struct osmo_stats_reporter *srep;
127 srep = talloc_zero(osmo_stats_ctx, struct osmo_stats_reporter);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200128 OSMO_ASSERT(srep);
129 srep->type = type;
130 if (name)
131 srep->name = talloc_strdup(srep, name);
132 srep->fd = -1;
133
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100134 llist_add(&srep->list, &osmo_stats_reporter_list);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200135
136 return srep;
137}
138
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100139void osmo_stats_reporter_free(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200140{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100141 osmo_stats_reporter_disable(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200142 llist_del(&srep->list);
143 talloc_free(srep);
144}
145
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100146void osmo_stats_init(void *ctx)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200147{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100148 osmo_stats_ctx = ctx;
149 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100150
151 is_initialised = 1;
152 start_timer();
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200153}
154
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100155struct osmo_stats_reporter *osmo_stats_reporter_find(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200156 const char *name)
157{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100158 struct osmo_stats_reporter *srep;
159 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200160 if (srep->type != type)
161 continue;
162 if (srep->name != name) {
163 if (name == NULL || srep->name == NULL ||
164 strcmp(name, srep->name) != 0)
165 continue;
166 }
167 return srep;
168 }
169 return NULL;
170}
171
Harald Welte67bdd802017-01-15 17:56:11 +0100172#ifdef HAVE_SYS_SOCKET_H
173
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100174int osmo_stats_reporter_set_remote_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200175{
176 int rc;
177 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
178 struct in_addr inaddr;
179
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100180 if (!srep->have_net_config)
181 return -ENOTSUP;
182
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200183 OSMO_ASSERT(addr != NULL);
184
185 rc = inet_pton(AF_INET, addr, &inaddr);
186 if (rc <= 0)
187 return -EINVAL;
188
189 sock_addr->sin_addr = inaddr;
190 sock_addr->sin_family = AF_INET;
191 srep->dest_addr_len = sizeof(*sock_addr);
192
193 talloc_free(srep->dest_addr_str);
194 srep->dest_addr_str = talloc_strdup(srep, addr);
195
196 return update_srep_config(srep);
197}
198
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100199int osmo_stats_reporter_set_remote_port(struct osmo_stats_reporter *srep, int port)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200200{
201 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
202
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100203 if (!srep->have_net_config)
204 return -ENOTSUP;
205
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200206 srep->dest_port = port;
Harald Welte95871da2017-05-15 12:11:36 +0200207 sock_addr->sin_port = osmo_htons(port);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200208
209 return update_srep_config(srep);
210}
211
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100212int osmo_stats_reporter_set_local_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200213{
214 int rc;
215 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->bind_addr;
216 struct in_addr inaddr;
217
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100218 if (!srep->have_net_config)
219 return -ENOTSUP;
220
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200221 if (addr) {
222 rc = inet_pton(AF_INET, addr, &inaddr);
223 if (rc <= 0)
224 return -EINVAL;
225 } else {
Holger Hans Peter Freyther79219752015-11-02 15:50:32 +0100226 inaddr.s_addr = INADDR_ANY;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200227 }
228
229 sock_addr->sin_addr = inaddr;
230 sock_addr->sin_family = AF_INET;
231 srep->bind_addr_len = addr ? sizeof(*sock_addr) : 0;
232
233 talloc_free(srep->bind_addr_str);
234 srep->bind_addr_str = addr ? talloc_strdup(srep, addr) : NULL;
235
236 return update_srep_config(srep);
237}
238
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100239int osmo_stats_reporter_set_mtu(struct osmo_stats_reporter *srep, int mtu)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100240{
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100241 if (!srep->have_net_config)
242 return -ENOTSUP;
243
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100244 if (mtu < 0)
245 return -EINVAL;
246
247 srep->mtu = mtu;
248
249 return update_srep_config(srep);
250}
Harald Welte67bdd802017-01-15 17:56:11 +0100251#endif /* HAVE_SYS_SOCKETS_H */
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100252
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100253int osmo_stats_reporter_set_max_class(struct osmo_stats_reporter *srep,
254 enum osmo_stats_class class_id)
255{
256 if (class_id == OSMO_STATS_CLASS_UNKNOWN)
257 return -EINVAL;
258
259 srep->max_class = class_id;
260
261 return 0;
262}
263
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100264int osmo_stats_set_interval(int interval)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200265{
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100266 if (interval <= 0)
267 return -EINVAL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200268
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100269 osmo_stats_config->interval = interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100270 if (is_initialised)
271 start_timer();
272
273 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200274}
275
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100276int osmo_stats_reporter_set_name_prefix(struct osmo_stats_reporter *srep, const char *prefix)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200277{
278 talloc_free(srep->name_prefix);
Jacob Erlbeck916423e2015-11-09 10:52:19 +0100279 srep->name_prefix = prefix && strlen(prefix) > 0 ?
280 talloc_strdup(srep, prefix) : NULL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200281
282 return update_srep_config(srep);
283}
284
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100285int osmo_stats_reporter_enable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200286{
287 srep->enabled = 1;
288
289 return update_srep_config(srep);
290}
291
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100292int osmo_stats_reporter_disable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200293{
294 srep->enabled = 0;
295
296 return update_srep_config(srep);
297}
298
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100299/*** i/o helper functions ***/
300
Harald Welte67bdd802017-01-15 17:56:11 +0100301#ifdef HAVE_SYS_SOCKET_H
302
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100303int osmo_stats_reporter_udp_open(struct osmo_stats_reporter *srep)
304{
305 int sock;
306 int rc;
307 int buffer_size = STATS_DEFAULT_BUFLEN;
308
309 if (srep->fd != -1 && srep->close)
310 srep->close(srep);
311
312 sock = socket(AF_INET, SOCK_DGRAM, 0);
313 if (sock == -1)
314 return -errno;
315
Arran Cudbard-Bellcc3694b2016-05-18 16:02:19 -0400316#if defined(__APPLE__) && !defined(MSG_NOSIGNAL)
317 {
318 static int val = 1;
319
320 rc = setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val));
321 goto failed;
322 }
323#endif
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100324 if (srep->bind_addr_len > 0) {
325 rc = bind(sock, &srep->bind_addr, srep->bind_addr_len);
326 if (rc == -1)
327 goto failed;
328 }
329
330 srep->fd = sock;
331
332 if (srep->mtu > 0) {
333 buffer_size = srep->mtu - 20 /* IP */ - 8 /* UDP */;
334 srep->agg_enabled = 1;
335 }
336
337 srep->buffer = msgb_alloc(buffer_size, "stats buffer");
338
339 return 0;
340
341failed:
342 rc = -errno;
343 close(sock);
344
345 return rc;
346}
347
348int osmo_stats_reporter_udp_close(struct osmo_stats_reporter *srep)
349{
350 int rc;
351 if (srep->fd == -1)
352 return -EBADF;
353
354 osmo_stats_reporter_send_buffer(srep);
355
356 rc = close(srep->fd);
357 srep->fd = -1;
358 msgb_free(srep->buffer);
359 srep->buffer = NULL;
360 return rc == -1 ? -errno : 0;
361}
362
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100363int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200364 int data_len)
365{
366 int rc;
367
Arran Cudbard-Bellcc3694b2016-05-18 16:02:19 -0400368 rc = sendto(srep->fd, data, data_len,
369#ifdef MSG_NOSIGNAL
370 MSG_NOSIGNAL |
371#endif
372 MSG_DONTWAIT,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200373 &srep->dest_addr, srep->dest_addr_len);
374
375 if (rc == -1)
376 rc = -errno;
377
378 return rc;
379}
380
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100381int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100382{
383 int rc;
384
385 if (!srep->buffer || msgb_length(srep->buffer) == 0)
386 return 0;
387
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100388 rc = osmo_stats_reporter_send(srep,
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100389 (const char *)msgb_data(srep->buffer), msgb_length(srep->buffer));
390
391 msgb_trim(srep->buffer, 0);
392
393 return rc;
394}
Harald Welte67bdd802017-01-15 17:56:11 +0100395#endif /* HAVE_SYS_SOCKET_H */
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100396
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100397/*** log reporter ***/
398
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100399struct osmo_stats_reporter *osmo_stats_reporter_create_log(const char *name)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100400{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100401 struct osmo_stats_reporter *srep;
402 srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_LOG, name);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100403
404 srep->have_net_config = 0;
405
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100406 srep->send_counter = osmo_stats_reporter_log_send_counter;
407 srep->send_item = osmo_stats_reporter_log_send_item;
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100408
409 return srep;
410}
411
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100412static int osmo_stats_reporter_log_send(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100413 const char *type,
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100414 const char *name1, unsigned int index1, const char *name2, int value,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100415 const char *unit)
416{
Jacob Erlbeck79125ec2015-11-02 15:17:50 +0100417 LOGP(DLSTATS, LOGL_INFO,
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100418 "stats t=%s p=%s g=%s i=%u n=%s v=%d u=%s\n",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100419 type, srep->name_prefix ? srep->name_prefix : "",
420 name1 ? name1 : "", index1,
421 name2, value, unit ? unit : "");
422
423 return 0;
424}
425
426
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100427static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100428 const struct rate_ctr_group *ctrg,
429 const struct rate_ctr_desc *desc,
430 int64_t value, int64_t delta)
431{
432 if (ctrg)
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100433 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100434 ctrg->desc->group_name_prefix,
435 ctrg->idx,
436 desc->name, value, NULL);
437 else
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100438 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100439 NULL, 0,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100440 desc->name, value, NULL);
441}
442
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100443static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
444 const struct osmo_stat_item_group *statg,
Harald Welte1554f802016-11-11 15:06:06 +0100445 const struct osmo_stat_item_desc *desc, int64_t value)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100446{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100447 return osmo_stats_reporter_log_send(srep, "i",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100448 statg->desc->group_name_prefix, statg->idx,
449 desc->name, value, desc->unit);
450}
451
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100452/*** helper for reporting ***/
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200453
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100454static int osmo_stats_reporter_check_config(struct osmo_stats_reporter *srep,
455 unsigned int index, int class_id)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200456{
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100457 if (class_id == OSMO_STATS_CLASS_UNKNOWN)
458 class_id = index != 0 ?
459 OSMO_STATS_CLASS_SUBSCRIBER : OSMO_STATS_CLASS_GLOBAL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200460
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100461 return class_id <= srep->max_class;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200462}
463
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200464/*** generic rate counter support ***/
465
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100466static int osmo_stats_reporter_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200467 const struct rate_ctr_group *ctrg,
468 const struct rate_ctr_desc *desc,
469 int64_t value, int64_t delta)
470{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100471 if (!srep->send_counter)
472 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200473
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100474 return srep->send_counter(srep, ctrg, desc, value, delta);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200475}
476
477static int rate_ctr_handler(
478 struct rate_ctr_group *ctrg, struct rate_ctr *ctr,
479 const struct rate_ctr_desc *desc, void *sctx_)
480{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100481 struct osmo_stats_reporter *srep;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200482 int64_t delta = rate_ctr_difference(ctr);
483
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100484 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200485 if (!srep->running)
486 continue;
487
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100488 if (delta == 0 && !srep->force_single_flush)
489 continue;
490
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100491 if (!osmo_stats_reporter_check_config(srep,
492 ctrg->idx, ctrg->desc->class_id))
Jacob Erlbeck8a97cb92015-11-09 11:39:42 +0100493 continue;
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100494
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100495 osmo_stats_reporter_send_counter(srep, ctrg, desc,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200496 ctr->current, delta);
497
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100498 /* TODO: handle result (log?, inc counter(!)?) or remove it */
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200499 }
500
501 return 0;
502}
503
504static int rate_ctr_group_handler(struct rate_ctr_group *ctrg, void *sctx_)
505{
506 rate_ctr_for_each_counter(ctrg, rate_ctr_handler, sctx_);
507
508 return 0;
509}
510
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100511/*** stat item support ***/
512
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100513static int osmo_stats_reporter_send_item(struct osmo_stats_reporter *srep,
514 const struct osmo_stat_item_group *statg,
515 const struct osmo_stat_item_desc *desc,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100516 int32_t value)
517{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100518 if (!srep->send_item)
519 return 0;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100520
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100521 return srep->send_item(srep, statg, desc, value);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100522}
523
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100524static int osmo_stat_item_handler(
525 struct osmo_stat_item_group *statg, struct osmo_stat_item *item, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100526{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100527 struct osmo_stats_reporter *srep;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100528 int32_t idx = current_stat_item_index;
529 int32_t value;
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100530 int have_value;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100531
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100532 have_value = osmo_stat_item_get_next(item, &idx, &value) > 0;
533 if (!have_value)
534 /* Send the last value in case a flush is requested */
535 value = osmo_stat_item_get_last(item);
536
537 do {
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100538 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100539 if (!srep->running)
540 continue;
541
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100542 if (!have_value && !srep->force_single_flush)
543 continue;
544
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100545 if (!osmo_stats_reporter_check_config(srep,
546 statg->idx, statg->desc->class_id))
Jacob Erlbeck8a97cb92015-11-09 11:39:42 +0100547 continue;
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100548
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100549 osmo_stats_reporter_send_item(srep, statg,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100550 item->desc, value);
551 }
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100552
553 if (!have_value)
554 break;
555
556 have_value = osmo_stat_item_get_next(item, &idx, &value) > 0;
557 } while (have_value);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100558
559 return 0;
560}
561
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100562static int osmo_stat_item_group_handler(struct osmo_stat_item_group *statg, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100563{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100564 osmo_stat_item_for_each_item(statg, osmo_stat_item_handler, sctx_);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100565
566 return 0;
567}
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200568
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100569/*** osmo counter support ***/
570
571static int handle_counter(struct osmo_counter *counter, void *sctx_)
572{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100573 struct osmo_stats_reporter *srep;
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100574 struct rate_ctr_desc desc = {0};
575 /* Fake a rate counter description */
576 desc.name = counter->name;
577 desc.description = counter->description;
578
579 int delta = osmo_counter_difference(counter);
580
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100581 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100582 if (!srep->running)
583 continue;
584
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100585 if (delta == 0 && !srep->force_single_flush)
586 continue;
587
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100588 osmo_stats_reporter_send_counter(srep, NULL, &desc,
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100589 counter->value, delta);
590
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100591 /* TODO: handle result (log?, inc counter(!)?) */
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100592 }
593
594 return 0;
595}
596
597
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200598/*** main reporting function ***/
599
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100600static void flush_all_reporters()
601{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100602 struct osmo_stats_reporter *srep;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100603
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100604 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100605 if (!srep->running)
606 continue;
607
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100608 osmo_stats_reporter_send_buffer(srep);
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100609 srep->force_single_flush = 0;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100610 }
611}
612
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100613int osmo_stats_report()
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200614{
Jacob Erlbeck01e8c912015-11-09 14:13:23 +0100615 /* per group actions */
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100616 osmo_counters_for_each(handle_counter, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200617 rate_ctr_for_each_group(rate_ctr_group_handler, NULL);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100618 osmo_stat_item_for_each_group(osmo_stat_item_group_handler, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200619
Jacob Erlbeck01e8c912015-11-09 14:13:23 +0100620 /* global actions */
621 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100622 flush_all_reporters();
623
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200624 return 0;
625}
Harald Welte67bdd802017-01-15 17:56:11 +0100626
627#endif /* !EMBEDDED */