blob: 9c826ccf07b9955da39e30201a344852eb591e87 [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 Welte95871da2017-05-15 12:11:36 +020024#include <osmocom/core/byteswap.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020025#include <osmocom/core/stats.h>
26
27#include <unistd.h>
28#include <string.h>
29#include <stdint.h>
30#include <errno.h>
31#include <stdio.h>
Holger Hans Peter Freytherc3376932015-08-21 19:56:54 +000032#include <sys/types.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020033#include <sys/socket.h>
Holger Hans Peter Freytherc3376932015-08-21 19:56:54 +000034#include <netinet/in.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020035#include <arpa/inet.h>
36
37#include <osmocom/core/utils.h>
38#include <osmocom/core/logging.h>
39#include <osmocom/core/rate_ctr.h>
40#include <osmocom/core/stat_item.h>
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010041#include <osmocom/core/timer.h>
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +010042#include <osmocom/core/statistics.h>
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +010043#include <osmocom/core/msgb.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020044
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010045#define STATS_DEFAULT_INTERVAL 5 /* secs */
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010046#define STATS_DEFAULT_BUFLEN 256
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020047
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010048static LLIST_HEAD(osmo_stats_reporter_list);
49static void *osmo_stats_ctx = NULL;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010050static int is_initialised = 0;
51static int32_t current_stat_item_index = 0;
52
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010053static struct osmo_stats_config s_stats_config = {
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010054 .interval = STATS_DEFAULT_INTERVAL,
55};
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010056struct osmo_stats_config *osmo_stats_config = &s_stats_config;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010057
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010058static struct osmo_timer_list osmo_stats_timer;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020059
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010060static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010061 const struct rate_ctr_group *ctrg,
62 const struct rate_ctr_desc *desc,
63 int64_t value, int64_t delta);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010064static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
65 const struct osmo_stat_item_group *statg,
Harald Welte1554f802016-11-11 15:06:06 +010066 const struct osmo_stat_item_desc *desc, int64_t value);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010067
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010068static int update_srep_config(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020069{
70 int rc = 0;
71
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020072 if (srep->running) {
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010073 if (srep->close)
74 rc = srep->close(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020075 srep->running = 0;
76 }
77
78 if (!srep->enabled)
79 return rc;
80
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010081 if (srep->open)
82 rc = srep->open(srep);
83 else
84 rc = 0;
85
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020086 if (rc < 0)
87 srep->enabled = 0;
88 else
89 srep->running = 1;
90
Jacob Erlbeckaed7c122015-11-09 11:25:12 +010091 srep->force_single_flush = 1;
92
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020093 return rc;
94}
95
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010096static void osmo_stats_timer_cb(void *data)
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010097{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010098 int interval = osmo_stats_config->interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010099
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100100 if (!llist_empty(&osmo_stats_reporter_list))
101 osmo_stats_report();
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100102
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100103 osmo_timer_schedule(&osmo_stats_timer, interval, 0);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100104}
105
106static int start_timer()
107{
108 if (!is_initialised)
109 return -ESRCH;
110
Pablo Neira Ayuso44f423f2017-05-08 18:00:28 +0200111 osmo_timer_setup(&osmo_stats_timer, osmo_stats_timer_cb, NULL);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100112 osmo_timer_schedule(&osmo_stats_timer, 0, 1);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100113
114 return 0;
115}
116
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100117struct osmo_stats_reporter *osmo_stats_reporter_alloc(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200118 const char *name)
119{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100120 struct osmo_stats_reporter *srep;
121 srep = talloc_zero(osmo_stats_ctx, struct osmo_stats_reporter);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200122 OSMO_ASSERT(srep);
123 srep->type = type;
124 if (name)
125 srep->name = talloc_strdup(srep, name);
126 srep->fd = -1;
127
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100128 llist_add(&srep->list, &osmo_stats_reporter_list);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200129
130 return srep;
131}
132
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100133void osmo_stats_reporter_free(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200134{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100135 osmo_stats_reporter_disable(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200136 llist_del(&srep->list);
137 talloc_free(srep);
138}
139
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100140void osmo_stats_init(void *ctx)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200141{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100142 osmo_stats_ctx = ctx;
143 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100144
145 is_initialised = 1;
146 start_timer();
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200147}
148
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100149struct osmo_stats_reporter *osmo_stats_reporter_find(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200150 const char *name)
151{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100152 struct osmo_stats_reporter *srep;
153 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200154 if (srep->type != type)
155 continue;
156 if (srep->name != name) {
157 if (name == NULL || srep->name == NULL ||
158 strcmp(name, srep->name) != 0)
159 continue;
160 }
161 return srep;
162 }
163 return NULL;
164}
165
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100166int osmo_stats_reporter_set_remote_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200167{
168 int rc;
169 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
170 struct in_addr inaddr;
171
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100172 if (!srep->have_net_config)
173 return -ENOTSUP;
174
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200175 OSMO_ASSERT(addr != NULL);
176
177 rc = inet_pton(AF_INET, addr, &inaddr);
178 if (rc <= 0)
179 return -EINVAL;
180
181 sock_addr->sin_addr = inaddr;
182 sock_addr->sin_family = AF_INET;
183 srep->dest_addr_len = sizeof(*sock_addr);
184
185 talloc_free(srep->dest_addr_str);
186 srep->dest_addr_str = talloc_strdup(srep, addr);
187
188 return update_srep_config(srep);
189}
190
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100191int osmo_stats_reporter_set_remote_port(struct osmo_stats_reporter *srep, int port)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200192{
193 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
194
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100195 if (!srep->have_net_config)
196 return -ENOTSUP;
197
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200198 srep->dest_port = port;
Harald Welte95871da2017-05-15 12:11:36 +0200199 sock_addr->sin_port = osmo_htons(port);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200200
201 return update_srep_config(srep);
202}
203
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100204int osmo_stats_reporter_set_local_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200205{
206 int rc;
207 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->bind_addr;
208 struct in_addr inaddr;
209
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100210 if (!srep->have_net_config)
211 return -ENOTSUP;
212
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200213 if (addr) {
214 rc = inet_pton(AF_INET, addr, &inaddr);
215 if (rc <= 0)
216 return -EINVAL;
217 } else {
Holger Hans Peter Freyther79219752015-11-02 15:50:32 +0100218 inaddr.s_addr = INADDR_ANY;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200219 }
220
221 sock_addr->sin_addr = inaddr;
222 sock_addr->sin_family = AF_INET;
223 srep->bind_addr_len = addr ? sizeof(*sock_addr) : 0;
224
225 talloc_free(srep->bind_addr_str);
226 srep->bind_addr_str = addr ? talloc_strdup(srep, addr) : NULL;
227
228 return update_srep_config(srep);
229}
230
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100231int osmo_stats_reporter_set_mtu(struct osmo_stats_reporter *srep, int mtu)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100232{
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100233 if (!srep->have_net_config)
234 return -ENOTSUP;
235
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100236 if (mtu < 0)
237 return -EINVAL;
238
239 srep->mtu = mtu;
240
241 return update_srep_config(srep);
242}
243
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100244int osmo_stats_reporter_set_max_class(struct osmo_stats_reporter *srep,
245 enum osmo_stats_class class_id)
246{
247 if (class_id == OSMO_STATS_CLASS_UNKNOWN)
248 return -EINVAL;
249
250 srep->max_class = class_id;
251
252 return 0;
253}
254
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100255int osmo_stats_set_interval(int interval)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200256{
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100257 if (interval <= 0)
258 return -EINVAL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200259
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100260 osmo_stats_config->interval = interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100261 if (is_initialised)
262 start_timer();
263
264 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200265}
266
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100267int osmo_stats_reporter_set_name_prefix(struct osmo_stats_reporter *srep, const char *prefix)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200268{
269 talloc_free(srep->name_prefix);
Jacob Erlbeck916423e2015-11-09 10:52:19 +0100270 srep->name_prefix = prefix && strlen(prefix) > 0 ?
271 talloc_strdup(srep, prefix) : NULL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200272
273 return update_srep_config(srep);
274}
275
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100276int osmo_stats_reporter_enable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200277{
278 srep->enabled = 1;
279
280 return update_srep_config(srep);
281}
282
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100283int osmo_stats_reporter_disable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200284{
285 srep->enabled = 0;
286
287 return update_srep_config(srep);
288}
289
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100290/*** i/o helper functions ***/
291
292int osmo_stats_reporter_udp_open(struct osmo_stats_reporter *srep)
293{
294 int sock;
295 int rc;
296 int buffer_size = STATS_DEFAULT_BUFLEN;
297
298 if (srep->fd != -1 && srep->close)
299 srep->close(srep);
300
301 sock = socket(AF_INET, SOCK_DGRAM, 0);
302 if (sock == -1)
303 return -errno;
304
Arran Cudbard-Bellcc3694b2016-05-18 16:02:19 -0400305#if defined(__APPLE__) && !defined(MSG_NOSIGNAL)
306 {
307 static int val = 1;
308
309 rc = setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val));
310 goto failed;
311 }
312#endif
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100313 if (srep->bind_addr_len > 0) {
314 rc = bind(sock, &srep->bind_addr, srep->bind_addr_len);
315 if (rc == -1)
316 goto failed;
317 }
318
319 srep->fd = sock;
320
321 if (srep->mtu > 0) {
322 buffer_size = srep->mtu - 20 /* IP */ - 8 /* UDP */;
323 srep->agg_enabled = 1;
324 }
325
326 srep->buffer = msgb_alloc(buffer_size, "stats buffer");
327
328 return 0;
329
330failed:
331 rc = -errno;
332 close(sock);
333
334 return rc;
335}
336
337int osmo_stats_reporter_udp_close(struct osmo_stats_reporter *srep)
338{
339 int rc;
340 if (srep->fd == -1)
341 return -EBADF;
342
343 osmo_stats_reporter_send_buffer(srep);
344
345 rc = close(srep->fd);
346 srep->fd = -1;
347 msgb_free(srep->buffer);
348 srep->buffer = NULL;
349 return rc == -1 ? -errno : 0;
350}
351
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100352int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200353 int data_len)
354{
355 int rc;
356
Arran Cudbard-Bellcc3694b2016-05-18 16:02:19 -0400357 rc = sendto(srep->fd, data, data_len,
358#ifdef MSG_NOSIGNAL
359 MSG_NOSIGNAL |
360#endif
361 MSG_DONTWAIT,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200362 &srep->dest_addr, srep->dest_addr_len);
363
364 if (rc == -1)
365 rc = -errno;
366
367 return rc;
368}
369
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100370int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100371{
372 int rc;
373
374 if (!srep->buffer || msgb_length(srep->buffer) == 0)
375 return 0;
376
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100377 rc = osmo_stats_reporter_send(srep,
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100378 (const char *)msgb_data(srep->buffer), msgb_length(srep->buffer));
379
380 msgb_trim(srep->buffer, 0);
381
382 return rc;
383}
384
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100385/*** log reporter ***/
386
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100387struct osmo_stats_reporter *osmo_stats_reporter_create_log(const char *name)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100388{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100389 struct osmo_stats_reporter *srep;
390 srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_LOG, name);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100391
392 srep->have_net_config = 0;
393
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100394 srep->send_counter = osmo_stats_reporter_log_send_counter;
395 srep->send_item = osmo_stats_reporter_log_send_item;
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100396
397 return srep;
398}
399
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100400static int osmo_stats_reporter_log_send(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100401 const char *type,
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100402 const char *name1, unsigned int index1, const char *name2, int value,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100403 const char *unit)
404{
Jacob Erlbeck79125ec2015-11-02 15:17:50 +0100405 LOGP(DLSTATS, LOGL_INFO,
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100406 "stats t=%s p=%s g=%s i=%u n=%s v=%d u=%s\n",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100407 type, srep->name_prefix ? srep->name_prefix : "",
408 name1 ? name1 : "", index1,
409 name2, value, unit ? unit : "");
410
411 return 0;
412}
413
414
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100415static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100416 const struct rate_ctr_group *ctrg,
417 const struct rate_ctr_desc *desc,
418 int64_t value, int64_t delta)
419{
420 if (ctrg)
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100421 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100422 ctrg->desc->group_name_prefix,
423 ctrg->idx,
424 desc->name, value, NULL);
425 else
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100426 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100427 NULL, 0,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100428 desc->name, value, NULL);
429}
430
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100431static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
432 const struct osmo_stat_item_group *statg,
Harald Welte1554f802016-11-11 15:06:06 +0100433 const struct osmo_stat_item_desc *desc, int64_t value)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100434{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100435 return osmo_stats_reporter_log_send(srep, "i",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100436 statg->desc->group_name_prefix, statg->idx,
437 desc->name, value, desc->unit);
438}
439
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100440/*** helper for reporting ***/
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200441
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100442static int osmo_stats_reporter_check_config(struct osmo_stats_reporter *srep,
443 unsigned int index, int class_id)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200444{
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100445 if (class_id == OSMO_STATS_CLASS_UNKNOWN)
446 class_id = index != 0 ?
447 OSMO_STATS_CLASS_SUBSCRIBER : OSMO_STATS_CLASS_GLOBAL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200448
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100449 return class_id <= srep->max_class;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200450}
451
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200452/*** generic rate counter support ***/
453
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100454static int osmo_stats_reporter_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200455 const struct rate_ctr_group *ctrg,
456 const struct rate_ctr_desc *desc,
457 int64_t value, int64_t delta)
458{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100459 if (!srep->send_counter)
460 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200461
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100462 return srep->send_counter(srep, ctrg, desc, value, delta);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200463}
464
465static int rate_ctr_handler(
466 struct rate_ctr_group *ctrg, struct rate_ctr *ctr,
467 const struct rate_ctr_desc *desc, void *sctx_)
468{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100469 struct osmo_stats_reporter *srep;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200470 int64_t delta = rate_ctr_difference(ctr);
471
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100472 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200473 if (!srep->running)
474 continue;
475
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100476 if (delta == 0 && !srep->force_single_flush)
477 continue;
478
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100479 if (!osmo_stats_reporter_check_config(srep,
480 ctrg->idx, ctrg->desc->class_id))
Jacob Erlbeck8a97cb92015-11-09 11:39:42 +0100481 continue;
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100482
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100483 osmo_stats_reporter_send_counter(srep, ctrg, desc,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200484 ctr->current, delta);
485
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100486 /* TODO: handle result (log?, inc counter(!)?) or remove it */
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200487 }
488
489 return 0;
490}
491
492static int rate_ctr_group_handler(struct rate_ctr_group *ctrg, void *sctx_)
493{
494 rate_ctr_for_each_counter(ctrg, rate_ctr_handler, sctx_);
495
496 return 0;
497}
498
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100499/*** stat item support ***/
500
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100501static int osmo_stats_reporter_send_item(struct osmo_stats_reporter *srep,
502 const struct osmo_stat_item_group *statg,
503 const struct osmo_stat_item_desc *desc,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100504 int32_t value)
505{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100506 if (!srep->send_item)
507 return 0;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100508
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100509 return srep->send_item(srep, statg, desc, value);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100510}
511
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100512static int osmo_stat_item_handler(
513 struct osmo_stat_item_group *statg, struct osmo_stat_item *item, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100514{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100515 struct osmo_stats_reporter *srep;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100516 int32_t idx = current_stat_item_index;
517 int32_t value;
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100518 int have_value;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100519
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100520 have_value = osmo_stat_item_get_next(item, &idx, &value) > 0;
521 if (!have_value)
522 /* Send the last value in case a flush is requested */
523 value = osmo_stat_item_get_last(item);
524
525 do {
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100526 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100527 if (!srep->running)
528 continue;
529
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100530 if (!have_value && !srep->force_single_flush)
531 continue;
532
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100533 if (!osmo_stats_reporter_check_config(srep,
534 statg->idx, statg->desc->class_id))
Jacob Erlbeck8a97cb92015-11-09 11:39:42 +0100535 continue;
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100536
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100537 osmo_stats_reporter_send_item(srep, statg,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100538 item->desc, value);
539 }
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100540
541 if (!have_value)
542 break;
543
544 have_value = osmo_stat_item_get_next(item, &idx, &value) > 0;
545 } while (have_value);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100546
547 return 0;
548}
549
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100550static int osmo_stat_item_group_handler(struct osmo_stat_item_group *statg, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100551{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100552 osmo_stat_item_for_each_item(statg, osmo_stat_item_handler, sctx_);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100553
554 return 0;
555}
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200556
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100557/*** osmo counter support ***/
558
559static int handle_counter(struct osmo_counter *counter, void *sctx_)
560{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100561 struct osmo_stats_reporter *srep;
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100562 struct rate_ctr_desc desc = {0};
563 /* Fake a rate counter description */
564 desc.name = counter->name;
565 desc.description = counter->description;
566
567 int delta = osmo_counter_difference(counter);
568
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100569 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100570 if (!srep->running)
571 continue;
572
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100573 if (delta == 0 && !srep->force_single_flush)
574 continue;
575
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100576 osmo_stats_reporter_send_counter(srep, NULL, &desc,
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100577 counter->value, delta);
578
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100579 /* TODO: handle result (log?, inc counter(!)?) */
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100580 }
581
582 return 0;
583}
584
585
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200586/*** main reporting function ***/
587
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100588static void flush_all_reporters()
589{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100590 struct osmo_stats_reporter *srep;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100591
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100592 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100593 if (!srep->running)
594 continue;
595
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100596 osmo_stats_reporter_send_buffer(srep);
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100597 srep->force_single_flush = 0;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100598 }
599}
600
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100601int osmo_stats_report()
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200602{
Jacob Erlbeck01e8c912015-11-09 14:13:23 +0100603 /* per group actions */
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100604 osmo_counters_for_each(handle_counter, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200605 rate_ctr_for_each_group(rate_ctr_group_handler, NULL);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100606 osmo_stat_item_for_each_group(osmo_stat_item_group_handler, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200607
Jacob Erlbeck01e8c912015-11-09 14:13:23 +0100608 /* global actions */
609 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100610 flush_all_reporters();
611
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200612 return 0;
613}