blob: d9df232551523246184df213a4bad319bd298375 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file stats.c */
Jacob Erlbeck95bf82802015-10-20 19:05:52 +02002/*
3 * (C) 2015 by Sysmocom s.f.m.c. GmbH
4 *
5 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
6 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
Harald Welte67bdd802017-01-15 17:56:11 +010025#include "config.h"
26#if !defined(EMBEDDED)
27
Harald Welte95871da2017-05-15 12:11:36 +020028#include <osmocom/core/byteswap.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020029#include <osmocom/core/stats.h>
30
31#include <unistd.h>
32#include <string.h>
33#include <stdint.h>
34#include <errno.h>
35#include <stdio.h>
Holger Hans Peter Freytherc3376932015-08-21 19:56:54 +000036#include <sys/types.h>
Harald Welte67bdd802017-01-15 17:56:11 +010037
38#ifdef HAVE_SYS_SOCKET_H
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020039#include <sys/socket.h>
Holger Hans Peter Freytherc3376932015-08-21 19:56:54 +000040#include <netinet/in.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020041#include <arpa/inet.h>
Harald Welte67bdd802017-01-15 17:56:11 +010042#endif
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020043
44#include <osmocom/core/utils.h>
45#include <osmocom/core/logging.h>
46#include <osmocom/core/rate_ctr.h>
47#include <osmocom/core/stat_item.h>
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010048#include <osmocom/core/timer.h>
Harald Welte216338c2017-10-15 19:46:19 +020049#include <osmocom/core/counter.h>
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +010050#include <osmocom/core/msgb.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020051
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010052#define STATS_DEFAULT_INTERVAL 5 /* secs */
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010053#define STATS_DEFAULT_BUFLEN 256
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020054
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010055static LLIST_HEAD(osmo_stats_reporter_list);
56static void *osmo_stats_ctx = NULL;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010057static int is_initialised = 0;
58static int32_t current_stat_item_index = 0;
59
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010060static struct osmo_stats_config s_stats_config = {
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010061 .interval = STATS_DEFAULT_INTERVAL,
62};
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010063struct osmo_stats_config *osmo_stats_config = &s_stats_config;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010064
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010065static struct osmo_timer_list osmo_stats_timer;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020066
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010067static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010068 const struct rate_ctr_group *ctrg,
69 const struct rate_ctr_desc *desc,
70 int64_t value, int64_t delta);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010071static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
72 const struct osmo_stat_item_group *statg,
Harald Welte1554f802016-11-11 15:06:06 +010073 const struct osmo_stat_item_desc *desc, int64_t value);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010074
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010075static int update_srep_config(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020076{
77 int rc = 0;
78
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020079 if (srep->running) {
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010080 if (srep->close)
81 rc = srep->close(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020082 srep->running = 0;
83 }
84
85 if (!srep->enabled)
86 return rc;
87
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010088 if (srep->open)
89 rc = srep->open(srep);
90 else
91 rc = 0;
92
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020093 if (rc < 0)
94 srep->enabled = 0;
95 else
96 srep->running = 1;
97
Jacob Erlbeckaed7c122015-11-09 11:25:12 +010098 srep->force_single_flush = 1;
99
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200100 return rc;
101}
102
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100103static void osmo_stats_timer_cb(void *data)
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100104{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100105 int interval = osmo_stats_config->interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100106
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100107 if (!llist_empty(&osmo_stats_reporter_list))
108 osmo_stats_report();
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100109
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100110 osmo_timer_schedule(&osmo_stats_timer, interval, 0);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100111}
112
113static int start_timer()
114{
115 if (!is_initialised)
116 return -ESRCH;
117
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +0200118 osmo_timer_setup(&osmo_stats_timer, osmo_stats_timer_cb, NULL);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100119 osmo_timer_schedule(&osmo_stats_timer, 0, 1);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100120
121 return 0;
122}
123
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100124struct osmo_stats_reporter *osmo_stats_reporter_alloc(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200125 const char *name)
126{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100127 struct osmo_stats_reporter *srep;
128 srep = talloc_zero(osmo_stats_ctx, struct osmo_stats_reporter);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200129 OSMO_ASSERT(srep);
130 srep->type = type;
131 if (name)
132 srep->name = talloc_strdup(srep, name);
133 srep->fd = -1;
134
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100135 llist_add(&srep->list, &osmo_stats_reporter_list);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200136
137 return srep;
138}
139
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100140void osmo_stats_reporter_free(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200141{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100142 osmo_stats_reporter_disable(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200143 llist_del(&srep->list);
144 talloc_free(srep);
145}
146
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100147void osmo_stats_init(void *ctx)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200148{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100149 osmo_stats_ctx = ctx;
150 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100151
152 is_initialised = 1;
153 start_timer();
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200154}
155
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100156struct osmo_stats_reporter *osmo_stats_reporter_find(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200157 const char *name)
158{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100159 struct osmo_stats_reporter *srep;
160 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200161 if (srep->type != type)
162 continue;
163 if (srep->name != name) {
164 if (name == NULL || srep->name == NULL ||
165 strcmp(name, srep->name) != 0)
166 continue;
167 }
168 return srep;
169 }
170 return NULL;
171}
172
Harald Welte67bdd802017-01-15 17:56:11 +0100173#ifdef HAVE_SYS_SOCKET_H
174
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100175int osmo_stats_reporter_set_remote_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200176{
177 int rc;
178 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
179 struct in_addr inaddr;
180
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100181 if (!srep->have_net_config)
182 return -ENOTSUP;
183
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200184 OSMO_ASSERT(addr != NULL);
185
186 rc = inet_pton(AF_INET, addr, &inaddr);
187 if (rc <= 0)
188 return -EINVAL;
189
190 sock_addr->sin_addr = inaddr;
191 sock_addr->sin_family = AF_INET;
192 srep->dest_addr_len = sizeof(*sock_addr);
193
194 talloc_free(srep->dest_addr_str);
195 srep->dest_addr_str = talloc_strdup(srep, addr);
196
197 return update_srep_config(srep);
198}
199
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100200int osmo_stats_reporter_set_remote_port(struct osmo_stats_reporter *srep, int port)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200201{
202 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
203
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100204 if (!srep->have_net_config)
205 return -ENOTSUP;
206
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200207 srep->dest_port = port;
Harald Welte95871da2017-05-15 12:11:36 +0200208 sock_addr->sin_port = osmo_htons(port);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200209
210 return update_srep_config(srep);
211}
212
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100213int osmo_stats_reporter_set_local_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200214{
215 int rc;
216 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->bind_addr;
217 struct in_addr inaddr;
218
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100219 if (!srep->have_net_config)
220 return -ENOTSUP;
221
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200222 if (addr) {
223 rc = inet_pton(AF_INET, addr, &inaddr);
224 if (rc <= 0)
225 return -EINVAL;
226 } else {
Holger Hans Peter Freyther79219752015-11-02 15:50:32 +0100227 inaddr.s_addr = INADDR_ANY;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200228 }
229
230 sock_addr->sin_addr = inaddr;
231 sock_addr->sin_family = AF_INET;
232 srep->bind_addr_len = addr ? sizeof(*sock_addr) : 0;
233
234 talloc_free(srep->bind_addr_str);
235 srep->bind_addr_str = addr ? talloc_strdup(srep, addr) : NULL;
236
237 return update_srep_config(srep);
238}
239
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100240int osmo_stats_reporter_set_mtu(struct osmo_stats_reporter *srep, int mtu)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100241{
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100242 if (!srep->have_net_config)
243 return -ENOTSUP;
244
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100245 if (mtu < 0)
246 return -EINVAL;
247
248 srep->mtu = mtu;
249
250 return update_srep_config(srep);
251}
Harald Welte67bdd802017-01-15 17:56:11 +0100252#endif /* HAVE_SYS_SOCKETS_H */
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100253
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100254int osmo_stats_reporter_set_max_class(struct osmo_stats_reporter *srep,
255 enum osmo_stats_class class_id)
256{
257 if (class_id == OSMO_STATS_CLASS_UNKNOWN)
258 return -EINVAL;
259
260 srep->max_class = class_id;
261
262 return 0;
263}
264
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100265int osmo_stats_set_interval(int interval)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200266{
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100267 if (interval <= 0)
268 return -EINVAL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200269
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100270 osmo_stats_config->interval = interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100271 if (is_initialised)
272 start_timer();
273
274 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200275}
276
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100277int osmo_stats_reporter_set_name_prefix(struct osmo_stats_reporter *srep, const char *prefix)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200278{
279 talloc_free(srep->name_prefix);
Jacob Erlbeck916423e2015-11-09 10:52:19 +0100280 srep->name_prefix = prefix && strlen(prefix) > 0 ?
281 talloc_strdup(srep, prefix) : NULL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200282
283 return update_srep_config(srep);
284}
285
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100286int osmo_stats_reporter_enable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200287{
288 srep->enabled = 1;
289
290 return update_srep_config(srep);
291}
292
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100293int osmo_stats_reporter_disable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200294{
295 srep->enabled = 0;
296
297 return update_srep_config(srep);
298}
299
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100300/*** i/o helper functions ***/
301
Harald Welte67bdd802017-01-15 17:56:11 +0100302#ifdef HAVE_SYS_SOCKET_H
303
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100304int osmo_stats_reporter_udp_open(struct osmo_stats_reporter *srep)
305{
306 int sock;
307 int rc;
308 int buffer_size = STATS_DEFAULT_BUFLEN;
309
310 if (srep->fd != -1 && srep->close)
311 srep->close(srep);
312
313 sock = socket(AF_INET, SOCK_DGRAM, 0);
314 if (sock == -1)
315 return -errno;
316
Arran Cudbard-Bellcc3694b2016-05-18 16:02:19 -0400317#if defined(__APPLE__) && !defined(MSG_NOSIGNAL)
318 {
319 static int val = 1;
320
321 rc = setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val));
322 goto failed;
323 }
324#endif
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100325 if (srep->bind_addr_len > 0) {
326 rc = bind(sock, &srep->bind_addr, srep->bind_addr_len);
327 if (rc == -1)
328 goto failed;
329 }
330
331 srep->fd = sock;
332
333 if (srep->mtu > 0) {
334 buffer_size = srep->mtu - 20 /* IP */ - 8 /* UDP */;
335 srep->agg_enabled = 1;
336 }
337
338 srep->buffer = msgb_alloc(buffer_size, "stats buffer");
339
340 return 0;
341
342failed:
343 rc = -errno;
344 close(sock);
345
346 return rc;
347}
348
349int osmo_stats_reporter_udp_close(struct osmo_stats_reporter *srep)
350{
351 int rc;
352 if (srep->fd == -1)
353 return -EBADF;
354
355 osmo_stats_reporter_send_buffer(srep);
356
357 rc = close(srep->fd);
358 srep->fd = -1;
359 msgb_free(srep->buffer);
360 srep->buffer = NULL;
361 return rc == -1 ? -errno : 0;
362}
363
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100364int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200365 int data_len)
366{
367 int rc;
368
Arran Cudbard-Bellcc3694b2016-05-18 16:02:19 -0400369 rc = sendto(srep->fd, data, data_len,
370#ifdef MSG_NOSIGNAL
371 MSG_NOSIGNAL |
372#endif
373 MSG_DONTWAIT,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200374 &srep->dest_addr, srep->dest_addr_len);
375
376 if (rc == -1)
377 rc = -errno;
378
379 return rc;
380}
381
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100382int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100383{
384 int rc;
385
386 if (!srep->buffer || msgb_length(srep->buffer) == 0)
387 return 0;
388
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100389 rc = osmo_stats_reporter_send(srep,
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100390 (const char *)msgb_data(srep->buffer), msgb_length(srep->buffer));
391
392 msgb_trim(srep->buffer, 0);
393
394 return rc;
395}
Harald Welte67bdd802017-01-15 17:56:11 +0100396#endif /* HAVE_SYS_SOCKET_H */
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100397
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100398/*** log reporter ***/
399
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100400struct osmo_stats_reporter *osmo_stats_reporter_create_log(const char *name)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100401{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100402 struct osmo_stats_reporter *srep;
403 srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_LOG, name);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100404
405 srep->have_net_config = 0;
406
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100407 srep->send_counter = osmo_stats_reporter_log_send_counter;
408 srep->send_item = osmo_stats_reporter_log_send_item;
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100409
410 return srep;
411}
412
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100413static int osmo_stats_reporter_log_send(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100414 const char *type,
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100415 const char *name1, unsigned int index1, const char *name2, int value,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100416 const char *unit)
417{
Jacob Erlbeck79125ec2015-11-02 15:17:50 +0100418 LOGP(DLSTATS, LOGL_INFO,
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100419 "stats t=%s p=%s g=%s i=%u n=%s v=%d u=%s\n",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100420 type, srep->name_prefix ? srep->name_prefix : "",
421 name1 ? name1 : "", index1,
422 name2, value, unit ? unit : "");
423
424 return 0;
425}
426
427
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100428static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100429 const struct rate_ctr_group *ctrg,
430 const struct rate_ctr_desc *desc,
431 int64_t value, int64_t delta)
432{
433 if (ctrg)
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100434 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100435 ctrg->desc->group_name_prefix,
436 ctrg->idx,
437 desc->name, value, NULL);
438 else
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100439 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100440 NULL, 0,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100441 desc->name, value, NULL);
442}
443
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100444static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
445 const struct osmo_stat_item_group *statg,
Harald Welte1554f802016-11-11 15:06:06 +0100446 const struct osmo_stat_item_desc *desc, int64_t value)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100447{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100448 return osmo_stats_reporter_log_send(srep, "i",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100449 statg->desc->group_name_prefix, statg->idx,
450 desc->name, value, desc->unit);
451}
452
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100453/*** helper for reporting ***/
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200454
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100455static int osmo_stats_reporter_check_config(struct osmo_stats_reporter *srep,
456 unsigned int index, int class_id)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200457{
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100458 if (class_id == OSMO_STATS_CLASS_UNKNOWN)
459 class_id = index != 0 ?
460 OSMO_STATS_CLASS_SUBSCRIBER : OSMO_STATS_CLASS_GLOBAL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200461
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100462 return class_id <= srep->max_class;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200463}
464
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200465/*** generic rate counter support ***/
466
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100467static int osmo_stats_reporter_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200468 const struct rate_ctr_group *ctrg,
469 const struct rate_ctr_desc *desc,
470 int64_t value, int64_t delta)
471{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100472 if (!srep->send_counter)
473 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200474
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100475 return srep->send_counter(srep, ctrg, desc, value, delta);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200476}
477
478static int rate_ctr_handler(
479 struct rate_ctr_group *ctrg, struct rate_ctr *ctr,
480 const struct rate_ctr_desc *desc, void *sctx_)
481{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100482 struct osmo_stats_reporter *srep;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200483 int64_t delta = rate_ctr_difference(ctr);
484
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100485 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200486 if (!srep->running)
487 continue;
488
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100489 if (delta == 0 && !srep->force_single_flush)
490 continue;
491
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100492 if (!osmo_stats_reporter_check_config(srep,
493 ctrg->idx, ctrg->desc->class_id))
Jacob Erlbeck8a97cb92015-11-09 11:39:42 +0100494 continue;
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100495
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100496 osmo_stats_reporter_send_counter(srep, ctrg, desc,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200497 ctr->current, delta);
498
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100499 /* TODO: handle result (log?, inc counter(!)?) or remove it */
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200500 }
501
502 return 0;
503}
504
505static int rate_ctr_group_handler(struct rate_ctr_group *ctrg, void *sctx_)
506{
507 rate_ctr_for_each_counter(ctrg, rate_ctr_handler, sctx_);
508
509 return 0;
510}
511
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100512/*** stat item support ***/
513
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100514static int osmo_stats_reporter_send_item(struct osmo_stats_reporter *srep,
515 const struct osmo_stat_item_group *statg,
516 const struct osmo_stat_item_desc *desc,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100517 int32_t value)
518{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100519 if (!srep->send_item)
520 return 0;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100521
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100522 return srep->send_item(srep, statg, desc, value);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100523}
524
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100525static int osmo_stat_item_handler(
526 struct osmo_stat_item_group *statg, struct osmo_stat_item *item, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100527{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100528 struct osmo_stats_reporter *srep;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100529 int32_t idx = current_stat_item_index;
530 int32_t value;
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100531 int have_value;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100532
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100533 have_value = osmo_stat_item_get_next(item, &idx, &value) > 0;
534 if (!have_value)
535 /* Send the last value in case a flush is requested */
536 value = osmo_stat_item_get_last(item);
537
538 do {
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100539 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100540 if (!srep->running)
541 continue;
542
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100543 if (!have_value && !srep->force_single_flush)
544 continue;
545
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100546 if (!osmo_stats_reporter_check_config(srep,
547 statg->idx, statg->desc->class_id))
Jacob Erlbeck8a97cb92015-11-09 11:39:42 +0100548 continue;
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100549
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100550 osmo_stats_reporter_send_item(srep, statg,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100551 item->desc, value);
552 }
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100553
554 if (!have_value)
555 break;
556
557 have_value = osmo_stat_item_get_next(item, &idx, &value) > 0;
558 } while (have_value);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100559
560 return 0;
561}
562
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100563static int osmo_stat_item_group_handler(struct osmo_stat_item_group *statg, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100564{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100565 osmo_stat_item_for_each_item(statg, osmo_stat_item_handler, sctx_);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100566
567 return 0;
568}
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200569
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100570/*** osmo counter support ***/
571
572static int handle_counter(struct osmo_counter *counter, void *sctx_)
573{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100574 struct osmo_stats_reporter *srep;
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100575 struct rate_ctr_desc desc = {0};
576 /* Fake a rate counter description */
577 desc.name = counter->name;
578 desc.description = counter->description;
579
580 int delta = osmo_counter_difference(counter);
581
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100582 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100583 if (!srep->running)
584 continue;
585
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100586 if (delta == 0 && !srep->force_single_flush)
587 continue;
588
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100589 osmo_stats_reporter_send_counter(srep, NULL, &desc,
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100590 counter->value, delta);
591
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100592 /* TODO: handle result (log?, inc counter(!)?) */
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100593 }
594
595 return 0;
596}
597
598
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200599/*** main reporting function ***/
600
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100601static void flush_all_reporters()
602{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100603 struct osmo_stats_reporter *srep;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100604
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100605 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100606 if (!srep->running)
607 continue;
608
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100609 osmo_stats_reporter_send_buffer(srep);
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100610 srep->force_single_flush = 0;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100611 }
612}
613
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100614int osmo_stats_report()
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200615{
Jacob Erlbeck01e8c912015-11-09 14:13:23 +0100616 /* per group actions */
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100617 osmo_counters_for_each(handle_counter, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200618 rate_ctr_for_each_group(rate_ctr_group_handler, NULL);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100619 osmo_stat_item_for_each_group(osmo_stat_item_group_handler, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200620
Jacob Erlbeck01e8c912015-11-09 14:13:23 +0100621 /* global actions */
622 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100623 flush_all_reporters();
624
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200625 return 0;
626}
Harald Welte67bdd802017-01-15 17:56:11 +0100627
628#endif /* !EMBEDDED */