blob: 5f1d028b1319129f1c9936d4bb83c7c128fda6d3 [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>
Holger Hans Peter Freytherc3376932015-08-21 19:56:54 +000031#include <sys/types.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020032#include <sys/socket.h>
Holger Hans Peter Freytherc3376932015-08-21 19:56:54 +000033#include <netinet/in.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020034#include <arpa/inet.h>
35
36#include <osmocom/core/utils.h>
37#include <osmocom/core/logging.h>
38#include <osmocom/core/rate_ctr.h>
39#include <osmocom/core/stat_item.h>
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010040#include <osmocom/core/timer.h>
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +010041#include <osmocom/core/statistics.h>
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +010042#include <osmocom/core/msgb.h>
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020043
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010044#define STATS_DEFAULT_INTERVAL 5 /* secs */
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +010045#define STATS_DEFAULT_BUFLEN 256
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020046
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010047static LLIST_HEAD(osmo_stats_reporter_list);
48static void *osmo_stats_ctx = NULL;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010049static int is_initialised = 0;
50static int32_t current_stat_item_index = 0;
51
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010052static struct osmo_stats_config s_stats_config = {
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010053 .interval = STATS_DEFAULT_INTERVAL,
54};
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010055struct osmo_stats_config *osmo_stats_config = &s_stats_config;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010056
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010057static struct osmo_timer_list osmo_stats_timer;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020058
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010059static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010060 const struct rate_ctr_group *ctrg,
61 const struct rate_ctr_desc *desc,
62 int64_t value, int64_t delta);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010063static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
64 const struct osmo_stat_item_group *statg,
65 const struct osmo_stat_item_desc *desc, int value);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +010066
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010067static int update_srep_config(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020068{
69 int rc = 0;
70
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020071 if (srep->running) {
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010072 if (srep->close)
73 rc = srep->close(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020074 srep->running = 0;
75 }
76
77 if (!srep->enabled)
78 return rc;
79
Jacob Erlbeck490b38f2015-10-27 15:10:28 +010080 if (srep->open)
81 rc = srep->open(srep);
82 else
83 rc = 0;
84
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020085 if (rc < 0)
86 srep->enabled = 0;
87 else
88 srep->running = 1;
89
Jacob Erlbeckaed7c122015-11-09 11:25:12 +010090 srep->force_single_flush = 1;
91
Jacob Erlbeck95bf82802015-10-20 19:05:52 +020092 return rc;
93}
94
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010095static void osmo_stats_timer_cb(void *data)
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010096{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010097 int interval = osmo_stats_config->interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +010098
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +010099 if (!llist_empty(&osmo_stats_reporter_list))
100 osmo_stats_report();
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100101
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100102 osmo_timer_schedule(&osmo_stats_timer, interval, 0);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100103}
104
105static int start_timer()
106{
107 if (!is_initialised)
108 return -ESRCH;
109
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100110 osmo_stats_timer.cb = osmo_stats_timer_cb;
111 osmo_timer_schedule(&osmo_stats_timer, 0, 1);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100112
113 return 0;
114}
115
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100116struct osmo_stats_reporter *osmo_stats_reporter_alloc(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200117 const char *name)
118{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100119 struct osmo_stats_reporter *srep;
120 srep = talloc_zero(osmo_stats_ctx, struct osmo_stats_reporter);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200121 OSMO_ASSERT(srep);
122 srep->type = type;
123 if (name)
124 srep->name = talloc_strdup(srep, name);
125 srep->fd = -1;
126
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100127 llist_add(&srep->list, &osmo_stats_reporter_list);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200128
129 return srep;
130}
131
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100132void osmo_stats_reporter_free(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200133{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100134 osmo_stats_reporter_disable(srep);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200135 llist_del(&srep->list);
136 talloc_free(srep);
137}
138
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100139void osmo_stats_init(void *ctx)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200140{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100141 osmo_stats_ctx = ctx;
142 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100143
144 is_initialised = 1;
145 start_timer();
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200146}
147
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100148struct osmo_stats_reporter *osmo_stats_reporter_find(enum osmo_stats_reporter_type type,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200149 const char *name)
150{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100151 struct osmo_stats_reporter *srep;
152 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200153 if (srep->type != type)
154 continue;
155 if (srep->name != name) {
156 if (name == NULL || srep->name == NULL ||
157 strcmp(name, srep->name) != 0)
158 continue;
159 }
160 return srep;
161 }
162 return NULL;
163}
164
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100165int osmo_stats_reporter_set_remote_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200166{
167 int rc;
168 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
169 struct in_addr inaddr;
170
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100171 if (!srep->have_net_config)
172 return -ENOTSUP;
173
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200174 OSMO_ASSERT(addr != NULL);
175
176 rc = inet_pton(AF_INET, addr, &inaddr);
177 if (rc <= 0)
178 return -EINVAL;
179
180 sock_addr->sin_addr = inaddr;
181 sock_addr->sin_family = AF_INET;
182 srep->dest_addr_len = sizeof(*sock_addr);
183
184 talloc_free(srep->dest_addr_str);
185 srep->dest_addr_str = talloc_strdup(srep, addr);
186
187 return update_srep_config(srep);
188}
189
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100190int osmo_stats_reporter_set_remote_port(struct osmo_stats_reporter *srep, int port)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200191{
192 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->dest_addr;
193
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100194 if (!srep->have_net_config)
195 return -ENOTSUP;
196
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200197 srep->dest_port = port;
198 sock_addr->sin_port = htons(port);
199
200 return update_srep_config(srep);
201}
202
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100203int osmo_stats_reporter_set_local_addr(struct osmo_stats_reporter *srep, const char *addr)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200204{
205 int rc;
206 struct sockaddr_in *sock_addr = (struct sockaddr_in *)&srep->bind_addr;
207 struct in_addr inaddr;
208
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100209 if (!srep->have_net_config)
210 return -ENOTSUP;
211
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200212 if (addr) {
213 rc = inet_pton(AF_INET, addr, &inaddr);
214 if (rc <= 0)
215 return -EINVAL;
216 } else {
Holger Hans Peter Freyther79219752015-11-02 15:50:32 +0100217 inaddr.s_addr = INADDR_ANY;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200218 }
219
220 sock_addr->sin_addr = inaddr;
221 sock_addr->sin_family = AF_INET;
222 srep->bind_addr_len = addr ? sizeof(*sock_addr) : 0;
223
224 talloc_free(srep->bind_addr_str);
225 srep->bind_addr_str = addr ? talloc_strdup(srep, addr) : NULL;
226
227 return update_srep_config(srep);
228}
229
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100230int osmo_stats_reporter_set_mtu(struct osmo_stats_reporter *srep, int mtu)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100231{
Jacob Erlbecked197fd2015-10-27 14:43:24 +0100232 if (!srep->have_net_config)
233 return -ENOTSUP;
234
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100235 if (mtu < 0)
236 return -EINVAL;
237
238 srep->mtu = mtu;
239
240 return update_srep_config(srep);
241}
242
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100243int osmo_stats_reporter_set_max_class(struct osmo_stats_reporter *srep,
244 enum osmo_stats_class class_id)
245{
246 if (class_id == OSMO_STATS_CLASS_UNKNOWN)
247 return -EINVAL;
248
249 srep->max_class = class_id;
250
251 return 0;
252}
253
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100254int osmo_stats_set_interval(int interval)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200255{
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100256 if (interval <= 0)
257 return -EINVAL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200258
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100259 osmo_stats_config->interval = interval;
Jacob Erlbeckb1dbfb42015-10-26 11:58:38 +0100260 if (is_initialised)
261 start_timer();
262
263 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200264}
265
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100266int osmo_stats_reporter_set_name_prefix(struct osmo_stats_reporter *srep, const char *prefix)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200267{
268 talloc_free(srep->name_prefix);
Jacob Erlbeck916423e2015-11-09 10:52:19 +0100269 srep->name_prefix = prefix && strlen(prefix) > 0 ?
270 talloc_strdup(srep, prefix) : NULL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200271
272 return update_srep_config(srep);
273}
274
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100275int osmo_stats_reporter_enable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200276{
277 srep->enabled = 1;
278
279 return update_srep_config(srep);
280}
281
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100282int osmo_stats_reporter_disable(struct osmo_stats_reporter *srep)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200283{
284 srep->enabled = 0;
285
286 return update_srep_config(srep);
287}
288
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100289/*** i/o helper functions ***/
290
291int osmo_stats_reporter_udp_open(struct osmo_stats_reporter *srep)
292{
293 int sock;
294 int rc;
295 int buffer_size = STATS_DEFAULT_BUFLEN;
296
297 if (srep->fd != -1 && srep->close)
298 srep->close(srep);
299
300 sock = socket(AF_INET, SOCK_DGRAM, 0);
301 if (sock == -1)
302 return -errno;
303
Arran Cudbard-Bellcc3694b2016-05-18 16:02:19 -0400304#if defined(__APPLE__) && !defined(MSG_NOSIGNAL)
305 {
306 static int val = 1;
307
308 rc = setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val));
309 goto failed;
310 }
311#endif
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100312 if (srep->bind_addr_len > 0) {
313 rc = bind(sock, &srep->bind_addr, srep->bind_addr_len);
314 if (rc == -1)
315 goto failed;
316 }
317
318 srep->fd = sock;
319
320 if (srep->mtu > 0) {
321 buffer_size = srep->mtu - 20 /* IP */ - 8 /* UDP */;
322 srep->agg_enabled = 1;
323 }
324
325 srep->buffer = msgb_alloc(buffer_size, "stats buffer");
326
327 return 0;
328
329failed:
330 rc = -errno;
331 close(sock);
332
333 return rc;
334}
335
336int osmo_stats_reporter_udp_close(struct osmo_stats_reporter *srep)
337{
338 int rc;
339 if (srep->fd == -1)
340 return -EBADF;
341
342 osmo_stats_reporter_send_buffer(srep);
343
344 rc = close(srep->fd);
345 srep->fd = -1;
346 msgb_free(srep->buffer);
347 srep->buffer = NULL;
348 return rc == -1 ? -errno : 0;
349}
350
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100351int osmo_stats_reporter_send(struct osmo_stats_reporter *srep, const char *data,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200352 int data_len)
353{
354 int rc;
355
Arran Cudbard-Bellcc3694b2016-05-18 16:02:19 -0400356 rc = sendto(srep->fd, data, data_len,
357#ifdef MSG_NOSIGNAL
358 MSG_NOSIGNAL |
359#endif
360 MSG_DONTWAIT,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200361 &srep->dest_addr, srep->dest_addr_len);
362
363 if (rc == -1)
364 rc = -errno;
365
366 return rc;
367}
368
Jacob Erlbeckb6e6bea2015-11-09 15:33:44 +0100369int osmo_stats_reporter_send_buffer(struct osmo_stats_reporter *srep)
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100370{
371 int rc;
372
373 if (!srep->buffer || msgb_length(srep->buffer) == 0)
374 return 0;
375
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100376 rc = osmo_stats_reporter_send(srep,
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100377 (const char *)msgb_data(srep->buffer), msgb_length(srep->buffer));
378
379 msgb_trim(srep->buffer, 0);
380
381 return rc;
382}
383
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100384/*** log reporter ***/
385
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100386struct osmo_stats_reporter *osmo_stats_reporter_create_log(const char *name)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100387{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100388 struct osmo_stats_reporter *srep;
389 srep = osmo_stats_reporter_alloc(OSMO_STATS_REPORTER_LOG, name);
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100390
391 srep->have_net_config = 0;
392
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100393 srep->send_counter = osmo_stats_reporter_log_send_counter;
394 srep->send_item = osmo_stats_reporter_log_send_item;
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100395
396 return srep;
397}
398
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100399static int osmo_stats_reporter_log_send(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100400 const char *type,
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100401 const char *name1, unsigned int index1, const char *name2, int value,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100402 const char *unit)
403{
Jacob Erlbeck79125ec2015-11-02 15:17:50 +0100404 LOGP(DLSTATS, LOGL_INFO,
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100405 "stats t=%s p=%s g=%s i=%u n=%s v=%d u=%s\n",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100406 type, srep->name_prefix ? srep->name_prefix : "",
407 name1 ? name1 : "", index1,
408 name2, value, unit ? unit : "");
409
410 return 0;
411}
412
413
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100414static int osmo_stats_reporter_log_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100415 const struct rate_ctr_group *ctrg,
416 const struct rate_ctr_desc *desc,
417 int64_t value, int64_t delta)
418{
419 if (ctrg)
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100420 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100421 ctrg->desc->group_name_prefix,
422 ctrg->idx,
423 desc->name, value, NULL);
424 else
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100425 return osmo_stats_reporter_log_send(srep, "c",
Jacob Erlbeck16fe8da2015-11-02 11:30:01 +0100426 NULL, 0,
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100427 desc->name, value, NULL);
428}
429
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100430static int osmo_stats_reporter_log_send_item(struct osmo_stats_reporter *srep,
431 const struct osmo_stat_item_group *statg,
432 const struct osmo_stat_item_desc *desc, int value)
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100433{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100434 return osmo_stats_reporter_log_send(srep, "i",
Jacob Erlbeckbc4f7ae2015-10-28 21:47:45 +0100435 statg->desc->group_name_prefix, statg->idx,
436 desc->name, value, desc->unit);
437}
438
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100439/*** helper for reporting ***/
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200440
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100441static int osmo_stats_reporter_check_config(struct osmo_stats_reporter *srep,
442 unsigned int index, int class_id)
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200443{
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100444 if (class_id == OSMO_STATS_CLASS_UNKNOWN)
445 class_id = index != 0 ?
446 OSMO_STATS_CLASS_SUBSCRIBER : OSMO_STATS_CLASS_GLOBAL;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200447
Jacob Erlbeck2e8f9ed2015-11-09 15:48:25 +0100448 return class_id <= srep->max_class;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200449}
450
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200451/*** generic rate counter support ***/
452
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100453static int osmo_stats_reporter_send_counter(struct osmo_stats_reporter *srep,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200454 const struct rate_ctr_group *ctrg,
455 const struct rate_ctr_desc *desc,
456 int64_t value, int64_t delta)
457{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100458 if (!srep->send_counter)
459 return 0;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200460
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100461 return srep->send_counter(srep, ctrg, desc, value, delta);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200462}
463
464static int rate_ctr_handler(
465 struct rate_ctr_group *ctrg, struct rate_ctr *ctr,
466 const struct rate_ctr_desc *desc, void *sctx_)
467{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100468 struct osmo_stats_reporter *srep;
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200469 int64_t delta = rate_ctr_difference(ctr);
470
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100471 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200472 if (!srep->running)
473 continue;
474
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100475 if (delta == 0 && !srep->force_single_flush)
476 continue;
477
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100478 if (!osmo_stats_reporter_check_config(srep,
479 ctrg->idx, ctrg->desc->class_id))
Jacob Erlbeck8a97cb92015-11-09 11:39:42 +0100480 continue;
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100481
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100482 osmo_stats_reporter_send_counter(srep, ctrg, desc,
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200483 ctr->current, delta);
484
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100485 /* TODO: handle result (log?, inc counter(!)?) or remove it */
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200486 }
487
488 return 0;
489}
490
491static int rate_ctr_group_handler(struct rate_ctr_group *ctrg, void *sctx_)
492{
493 rate_ctr_for_each_counter(ctrg, rate_ctr_handler, sctx_);
494
495 return 0;
496}
497
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100498/*** stat item support ***/
499
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100500static int osmo_stats_reporter_send_item(struct osmo_stats_reporter *srep,
501 const struct osmo_stat_item_group *statg,
502 const struct osmo_stat_item_desc *desc,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100503 int32_t value)
504{
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100505 if (!srep->send_item)
506 return 0;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100507
Jacob Erlbeck490b38f2015-10-27 15:10:28 +0100508 return srep->send_item(srep, statg, desc, value);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100509}
510
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100511static int osmo_stat_item_handler(
512 struct osmo_stat_item_group *statg, struct osmo_stat_item *item, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100513{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100514 struct osmo_stats_reporter *srep;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100515 int32_t idx = current_stat_item_index;
516 int32_t value;
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100517 int have_value;
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100518
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100519 have_value = osmo_stat_item_get_next(item, &idx, &value) > 0;
520 if (!have_value)
521 /* Send the last value in case a flush is requested */
522 value = osmo_stat_item_get_last(item);
523
524 do {
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100525 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100526 if (!srep->running)
527 continue;
528
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100529 if (!have_value && !srep->force_single_flush)
530 continue;
531
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100532 if (!osmo_stats_reporter_check_config(srep,
533 statg->idx, statg->desc->class_id))
Jacob Erlbeck8a97cb92015-11-09 11:39:42 +0100534 continue;
Jacob Erlbeckbc9d9ac2015-11-02 14:49:35 +0100535
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100536 osmo_stats_reporter_send_item(srep, statg,
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100537 item->desc, value);
538 }
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100539
540 if (!have_value)
541 break;
542
543 have_value = osmo_stat_item_get_next(item, &idx, &value) > 0;
544 } while (have_value);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100545
546 return 0;
547}
548
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100549static int osmo_stat_item_group_handler(struct osmo_stat_item_group *statg, void *sctx_)
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100550{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100551 osmo_stat_item_for_each_item(statg, osmo_stat_item_handler, sctx_);
Jacob Erlbeckc27671c2015-10-26 12:32:07 +0100552
553 return 0;
554}
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200555
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100556/*** osmo counter support ***/
557
558static int handle_counter(struct osmo_counter *counter, void *sctx_)
559{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100560 struct osmo_stats_reporter *srep;
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100561 struct rate_ctr_desc desc = {0};
562 /* Fake a rate counter description */
563 desc.name = counter->name;
564 desc.description = counter->description;
565
566 int delta = osmo_counter_difference(counter);
567
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100568 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100569 if (!srep->running)
570 continue;
571
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100572 if (delta == 0 && !srep->force_single_flush)
573 continue;
574
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100575 osmo_stats_reporter_send_counter(srep, NULL, &desc,
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100576 counter->value, delta);
577
Holger Hans Peter Freyther837e9402015-11-02 15:44:26 +0100578 /* TODO: handle result (log?, inc counter(!)?) */
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100579 }
580
581 return 0;
582}
583
584
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200585/*** main reporting function ***/
586
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100587static void flush_all_reporters()
588{
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100589 struct osmo_stats_reporter *srep;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100590
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100591 llist_for_each_entry(srep, &osmo_stats_reporter_list, list) {
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100592 if (!srep->running)
593 continue;
594
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100595 osmo_stats_reporter_send_buffer(srep);
Jacob Erlbeckaed7c122015-11-09 11:25:12 +0100596 srep->force_single_flush = 0;
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100597 }
598}
599
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100600int osmo_stats_report()
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200601{
Jacob Erlbeck01e8c912015-11-09 14:13:23 +0100602 /* per group actions */
Jacob Erlbeckc8f47b62015-10-26 14:42:05 +0100603 osmo_counters_for_each(handle_counter, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200604 rate_ctr_for_each_group(rate_ctr_group_handler, NULL);
Jacob Erlbeckfc9533d2015-10-29 00:55:58 +0100605 osmo_stat_item_for_each_group(osmo_stat_item_group_handler, NULL);
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200606
Jacob Erlbeck01e8c912015-11-09 14:13:23 +0100607 /* global actions */
608 osmo_stat_item_discard_all(&current_stat_item_index);
Jacob Erlbeckd01acfc2015-10-26 16:22:45 +0100609 flush_all_reporters();
610
Jacob Erlbeck95bf82802015-10-20 19:05:52 +0200611 return 0;
612}