blob: 7db7101eaf1e4a7ca11829ed485fdcc02c3ad12c [file] [log] [blame]
Harald Welte4a2bb9e2010-03-26 09:33:40 +08001/* Debugging/Logging support code */
2
3/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
Harald Welte18fc4652011-08-17 14:14:17 +020023/* \addtogroup logging
24 * @{
25 */
26
27/* \file logging.c */
28
Harald Welte01fd5cb2010-03-26 23:51:31 +080029#include "../config.h"
30
Harald Welte4a2bb9e2010-03-26 09:33:40 +080031#include <stdarg.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <string.h>
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010035#include <ctype.h>
Harald Welte01fd5cb2010-03-26 23:51:31 +080036
37#ifdef HAVE_STRINGS_H
Harald Welte4a2bb9e2010-03-26 09:33:40 +080038#include <strings.h>
Harald Welte01fd5cb2010-03-26 23:51:31 +080039#endif
Harald Welte4a2bb9e2010-03-26 09:33:40 +080040#include <time.h>
Jacob Erlbeckb61b2ca2015-03-17 10:21:15 +010041#include <sys/time.h>
Harald Welte4a2bb9e2010-03-26 09:33:40 +080042#include <errno.h>
43
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010044#include <osmocom/core/talloc.h>
45#include <osmocom/core/utils.h>
46#include <osmocom/core/logging.h>
Harald Welte4a2bb9e2010-03-26 09:33:40 +080047
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010048#include <osmocom/vty/logging.h> /* for LOGGING_STR. */
49
Harald Welteb43bc042011-06-27 10:29:17 +020050struct log_info *osmo_log_info;
Harald Welte4a2bb9e2010-03-26 09:33:40 +080051
Harald Welte3ae27582010-03-26 21:24:24 +080052static struct log_context log_context;
53static void *tall_log_ctx = NULL;
Harald Welte28222962011-02-18 20:37:04 +010054LLIST_HEAD(osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +080055
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010056#define LOGLEVEL_DEFS 6 /* Number of loglevels.*/
57
58static const struct value_string loglevel_strs[LOGLEVEL_DEFS+1] = {
Harald Welte9b186702013-03-19 09:55:28 +010059 { 0, "EVERYTHING" },
Harald Welte4a2bb9e2010-03-26 09:33:40 +080060 { LOGL_DEBUG, "DEBUG" },
61 { LOGL_INFO, "INFO" },
62 { LOGL_NOTICE, "NOTICE" },
63 { LOGL_ERROR, "ERROR" },
64 { LOGL_FATAL, "FATAL" },
65 { 0, NULL },
66};
67
Harald Welteb43bc042011-06-27 10:29:17 +020068#define INT2IDX(x) (-1*(x)-1)
69static const struct log_info_cat internal_cat[OSMO_NUM_DLIB] = {
70 [INT2IDX(DLGLOBAL)] = { /* -1 becomes 0 */
71 .name = "DLGLOBAL",
72 .description = "Library-internal global log family",
73 .loglevel = LOGL_NOTICE,
74 .enabled = 1,
75 },
root8a996b42011-09-26 11:22:21 +020076 [INT2IDX(DLLAPD)] = { /* -2 becomes 1 */
77 .name = "DLLAPD",
78 .description = "LAPD in libosmogsm",
Harald Welte1f0b8c22011-06-27 10:51:37 +020079 .loglevel = LOGL_NOTICE,
80 .enabled = 1,
81 },
Harald Welte892e6212011-07-19 14:31:44 +020082 [INT2IDX(DLINP)] = {
Harald Welte087e1132011-07-29 11:43:39 +020083 .name = "DLINP",
Pablo Neira Ayuso199f3772011-07-07 19:46:38 +020084 .description = "A-bis Intput Subsystem",
85 .loglevel = LOGL_NOTICE,
86 .enabled = 1,
87 },
Harald Welte892e6212011-07-19 14:31:44 +020088 [INT2IDX(DLMUX)] = {
Harald Welte087e1132011-07-29 11:43:39 +020089 .name = "DLMUX",
Pablo Neira Ayuso199f3772011-07-07 19:46:38 +020090 .description = "A-bis B-Subchannel TRAU Frame Multiplex",
91 .loglevel = LOGL_NOTICE,
92 .enabled = 1,
93 },
Harald Welte892e6212011-07-19 14:31:44 +020094 [INT2IDX(DLMI)] = {
Harald Welte087e1132011-07-29 11:43:39 +020095 .name = "DLMI",
Pablo Neira Ayuso199f3772011-07-07 19:46:38 +020096 .description = "A-bis Input Driver for Signalling",
97 .enabled = 0, .loglevel = LOGL_NOTICE,
98 },
Harald Welte892e6212011-07-19 14:31:44 +020099 [INT2IDX(DLMIB)] = {
Harald Welte087e1132011-07-29 11:43:39 +0200100 .name = "DLMIB",
Pablo Neira Ayuso199f3772011-07-07 19:46:38 +0200101 .description = "A-bis Input Driver for B-Channels (voice)",
102 .enabled = 0, .loglevel = LOGL_NOTICE,
103 },
Andreas Eversbergc626da92011-10-28 03:53:50 +0200104 [INT2IDX(DLSMS)] = {
105 .name = "DLSMS",
106 .description = "Layer3 Short Message Service (SMS)",
107 .enabled = 1, .loglevel = LOGL_NOTICE,
108 .color = "\033[1;38m",
109 },
Harald Welte7fd0c832014-08-20 19:58:13 +0200110 [INT2IDX(DLCTRL)] = {
111 .name = "DLCTRL",
112 .description = "Control Interface",
113 .enabled = 1, .loglevel = LOGL_NOTICE,
114 },
Holger Hans Peter Freythera5dc19d2014-12-04 14:35:21 +0100115 [INT2IDX(DLGTP)] = {
116 .name = "DLGTP",
117 .description = "GPRS GTP library",
118 .enabled = 1, .loglevel = LOGL_NOTICE,
119 },
Jacob Erlbeck79125ec2015-11-02 15:17:50 +0100120 [INT2IDX(DLSTATS)] = {
121 .name = "DLSTATS",
122 .description = "Statistics messages and logging",
123 .enabled = 1, .loglevel = LOGL_NOTICE,
124 },
Harald Welteb43bc042011-06-27 10:29:17 +0200125};
126
Harald Weltede6e4982012-12-06 21:25:27 +0100127/*! \brief descriptive string for each log level */
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100128/* You have to keep this in sync with the structure loglevel_strs. */
129const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
Holger Hans Peter Freyther6ec6bd92014-12-28 18:27:38 +0100130 "Don't use. It doesn't log anything",
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100131 "Log debug messages and higher levels",
132 "Log informational messages and higher levels",
133 "Log noticable messages and higher levels",
134 "Log error messages and higher levels",
135 "Log only fatal messages",
136 NULL,
137};
138
Harald Welteb43bc042011-06-27 10:29:17 +0200139/* special magic for negative (library-internal) log subsystem numbers */
140static int subsys_lib2index(int subsys)
141{
142 return (subsys * -1) + (osmo_log_info->num_cat_user-1);
143}
144
Harald Welte18fc4652011-08-17 14:14:17 +0200145/*! \brief Parse a human-readable log level into a numeric value */
Harald Welte3ae27582010-03-26 21:24:24 +0800146int log_parse_level(const char *lvl)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800147{
148 return get_string_value(loglevel_strs, lvl);
149}
150
Harald Welte18fc4652011-08-17 14:14:17 +0200151/*! \brief convert a numeric log level into human-readable string */
Harald Welte9ac22252010-05-11 11:19:40 +0200152const char *log_level_str(unsigned int lvl)
153{
154 return get_value_string(loglevel_strs, lvl);
155}
156
Harald Welte18fc4652011-08-17 14:14:17 +0200157/*! \brief parse a human-readable log category into numeric form
158 * \param[in] category human-readable log category name
159 * \returns numeric category value, or -EINVAL otherwise
160 */
Harald Welte3ae27582010-03-26 21:24:24 +0800161int log_parse_category(const char *category)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800162{
163 int i;
164
Harald Welte4ebdf742010-05-19 19:54:00 +0200165 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welteb43bc042011-06-27 10:29:17 +0200166 if (osmo_log_info->cat[i].name == NULL)
167 continue;
Harald Welte4ebdf742010-05-19 19:54:00 +0200168 if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
Harald Weltefaadfe22010-03-26 21:05:43 +0800169 return i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800170 }
171
172 return -EINVAL;
173}
174
Harald Welte18fc4652011-08-17 14:14:17 +0200175/*! \brief parse the log category mask
176 * \param[in] target log target to be configured
177 * \param[in] _mask log category mask string
178 *
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800179 * The format can be this: category1:category2:category3
180 * or category1,2:category2,3:...
181 */
Harald Welte3ae27582010-03-26 21:24:24 +0800182void log_parse_category_mask(struct log_target* target, const char *_mask)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800183{
184 int i = 0;
185 char *mask = strdup(_mask);
186 char *category_token = NULL;
187
188 /* Disable everything to enable it afterwards */
Harald Welteb43bc042011-06-27 10:29:17 +0200189 for (i = 0; i < osmo_log_info->num_cat; ++i)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800190 target->categories[i].enabled = 0;
191
192 category_token = strtok(mask, ":");
193 do {
Harald Welte4ebdf742010-05-19 19:54:00 +0200194 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Nico Golde0262d3f2012-09-21 17:44:58 +0200195 size_t length, cat_length;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800196 char* colon = strstr(category_token, ",");
Nico Golde0262d3f2012-09-21 17:44:58 +0200197
198 if (!osmo_log_info->cat[i].name)
199 continue;
200
201 length = strlen(category_token);
202 cat_length = strlen(osmo_log_info->cat[i].name);
Pablo Neira Ayuso300e78d2011-08-11 13:24:18 +0200203
204 /* Use longest length not to match subocurrences. */
205 if (cat_length > length)
206 length = cat_length;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800207
208 if (colon)
209 length = colon - category_token;
210
Harald Welte4ebdf742010-05-19 19:54:00 +0200211 if (strncasecmp(osmo_log_info->cat[i].name,
212 category_token, length) == 0) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800213 int level = 0;
214
215 if (colon)
216 level = atoi(colon+1);
217
Harald Weltefaadfe22010-03-26 21:05:43 +0800218 target->categories[i].enabled = 1;
219 target->categories[i].loglevel = level;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800220 }
221 }
222 } while ((category_token = strtok(NULL, ":")));
223
224 free(mask);
225}
226
227static const char* color(int subsys)
228{
Harald Welte4ebdf742010-05-19 19:54:00 +0200229 if (subsys < osmo_log_info->num_cat)
230 return osmo_log_info->cat[subsys].color;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800231
Harald Welted788f662010-03-26 09:45:03 +0800232 return NULL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800233}
234
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100235static const char* category_name(int subsys)
236{
237 if (subsys < osmo_log_info->num_cat)
238 return osmo_log_info->cat[subsys].name;
239
240 return NULL;
241}
242
Harald Welte3ae27582010-03-26 21:24:24 +0800243static void _output(struct log_target *target, unsigned int subsys,
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200244 unsigned int level, const char *file, int line, int cont,
Harald Welte76e72ab2011-02-17 15:52:39 +0100245 const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800246{
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800247 char buf[4096];
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200248 int ret, len = 0, offset = 0, rem = sizeof(buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800249
250 /* are we using color */
251 if (target->use_color) {
Harald Welted788f662010-03-26 09:45:03 +0800252 const char *c = color(subsys);
253 if (c) {
Holger Hans Peter Freyther5f91a402014-12-05 10:29:45 +0100254 ret = snprintf(buf + offset, rem, "%s", c);
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200255 if (ret < 0)
256 goto err;
257 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welted788f662010-03-26 09:45:03 +0800258 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800259 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800260 if (!cont) {
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100261 if (target->print_ext_timestamp) {
262 struct tm tm;
Jacob Erlbeckb61b2ca2015-03-17 10:21:15 +0100263 struct timeval tv;
264 gettimeofday(&tv, NULL);
265 localtime_r(&tv.tv_sec, &tm);
266 ret = snprintf(buf + offset, rem, "%04d%02d%02d%02d%02d%02d%03d ",
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100267 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
Jacob Erlbeckb61b2ca2015-03-17 10:21:15 +0100268 tm.tm_hour, tm.tm_min, tm.tm_sec,
269 (int)(tv.tv_usec / 1000));
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100270 if (ret < 0)
271 goto err;
272 OSMO_SNPRINTF_RET(ret, rem, offset, len);
273 } else if (target->print_timestamp) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800274 char *timestr;
275 time_t tm;
276 tm = time(NULL);
277 timestr = ctime(&tm);
278 timestr[strlen(timestr)-1] = '\0';
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200279 ret = snprintf(buf + offset, rem, "%s ", timestr);
280 if (ret < 0)
281 goto err;
282 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800283 }
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100284 if (target->print_category) {
285 ret = snprintf(buf + offset, rem, "%s ", category_name(subsys));
286 if (ret < 0)
287 goto err;
288 OSMO_SNPRINTF_RET(ret, rem, offset, len);
289 }
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200290 if (target->print_filename) {
291 ret = snprintf(buf + offset, rem, "<%4.4x> %s:%d ",
292 subsys, file, line);
293 if (ret < 0)
294 goto err;
295 OSMO_SNPRINTF_RET(ret, rem, offset, len);
296 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800297 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200298 ret = vsnprintf(buf + offset, rem, format, ap);
299 if (ret < 0)
300 goto err;
301 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800302
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200303 ret = snprintf(buf + offset, rem, "%s",
304 target->use_color ? "\033[0;m" : "");
305 if (ret < 0)
306 goto err;
307 OSMO_SNPRINTF_RET(ret, rem, offset, len);
308err:
309 buf[sizeof(buf)-1] = '\0';
310 target->output(target, level, buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800311}
312
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100313static inline int map_subsys(int subsys)
314{
315 if (subsys < 0)
316 subsys = subsys_lib2index(subsys);
317
318 if (subsys > osmo_log_info->num_cat)
319 subsys = DLGLOBAL;
320 return subsys;
321}
322
323static inline int check_log_to_target(struct log_target *tar, int subsys, int level)
324{
325 struct log_category *category;
326
327 category = &tar->categories[subsys];
328
329 /* subsystem is not supposed to be logged */
330 if (!category->enabled)
331 return 0;
332
333 /* Check the global log level */
334 if (tar->loglevel != 0 && level < tar->loglevel)
335 return 0;
336
337 /* Check the category log level */
338 if (tar->loglevel == 0 && category->loglevel != 0 &&
339 level < category->loglevel)
340 return 0;
341
342 /* TODO: Check the filter/selector too? */
343 return 1;
344}
345
Harald Welte36c5a3e2011-08-27 14:33:19 +0200346/*! \brief vararg version of logging function */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200347void osmo_vlogp(int subsys, int level, const char *file, int line,
Harald Welte36c5a3e2011-08-27 14:33:19 +0200348 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800349{
Harald Welte3ae27582010-03-26 21:24:24 +0800350 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800351
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100352 subsys = map_subsys(subsys);
Harald Welteb43bc042011-06-27 10:29:17 +0200353
Harald Welte28222962011-02-18 20:37:04 +0100354 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800355 int output = 0;
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200356 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800357
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100358 if (!check_log_to_target(tar, subsys, level))
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800359 continue;
360
361 /* Apply filters here... if that becomes messy we will
362 * need to put filters in a list and each filter will
363 * say stop, continue, output */
Harald Welte3ae27582010-03-26 21:24:24 +0800364 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800365 output = 1;
Harald Welte4ebdf742010-05-19 19:54:00 +0200366 else if (osmo_log_info->filter_fn)
367 output = osmo_log_info->filter_fn(&log_context,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800368 tar);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200369 if (!output)
370 continue;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800371
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200372 /* According to the manpage, vsnprintf leaves the value of ap
373 * in undefined state. Since _output uses vsnprintf and it may
374 * be called several times, we have to pass a copy of ap. */
375 va_copy(bp, ap);
Harald Welteda127cb2011-07-02 21:51:32 +0200376 _output(tar, subsys, level, file, line, cont, format, bp);
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200377 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800378 }
379}
380
Harald Weltede6e4982012-12-06 21:25:27 +0100381/*! \brief logging function used by DEBUGP() macro */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200382void logp(int subsys, const char *file, int line, int cont,
Harald Welte3ae27582010-03-26 21:24:24 +0800383 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800384{
385 va_list ap;
386
387 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200388 osmo_vlogp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800389 va_end(ap);
390}
391
Harald Weltede6e4982012-12-06 21:25:27 +0100392/*! \brief logging function used by LOGP() macro */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200393void logp2(int subsys, unsigned int level, const char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800394{
395 va_list ap;
396
397 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200398 osmo_vlogp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800399 va_end(ap);
400}
401
Harald Welte18fc4652011-08-17 14:14:17 +0200402/*! \brief Register a new log target with the logging core
403 * \param[in] target Log target to be registered
404 */
Harald Welte3ae27582010-03-26 21:24:24 +0800405void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800406{
Harald Welte28222962011-02-18 20:37:04 +0100407 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800408}
409
Harald Welte18fc4652011-08-17 14:14:17 +0200410/*! \brief Unregister a log target from the logging core
411 * \param[in] target Log target to be unregistered
412 */
Harald Welte3ae27582010-03-26 21:24:24 +0800413void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800414{
415 llist_del(&target->entry);
416}
417
Harald Welte18fc4652011-08-17 14:14:17 +0200418/*! \brief Reset (clear) the logging context */
Harald Welte3ae27582010-03-26 21:24:24 +0800419void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800420{
Harald Welte3ae27582010-03-26 21:24:24 +0800421 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800422}
423
Harald Welte18fc4652011-08-17 14:14:17 +0200424/*! \brief Set the logging context
425 * \param[in] ctx_nr logging context number
426 * \param[in] value value to which the context is to be set
427 *
428 * A logging context is something like the subscriber identity to which
429 * the currently processed message relates, or the BTS through which it
430 * was received. As soon as this data is known, it can be set using
431 * this function. The main use of context information is for logging
432 * filters.
433 */
Harald Welte3ae27582010-03-26 21:24:24 +0800434int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800435{
Harald Welte3ae27582010-03-26 21:24:24 +0800436 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800437 return -EINVAL;
438
Harald Welte3ae27582010-03-26 21:24:24 +0800439 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800440
441 return 0;
442}
443
Harald Welte18fc4652011-08-17 14:14:17 +0200444/*! \brief Enable the \ref LOG_FILTER_ALL log filter
445 * \param[in] target Log target to be affected
446 * \param[in] all enable (1) or disable (0) the ALL filter
447 *
448 * When the \ref LOG_FILTER_ALL filter is enabled, all log messages will
449 * be printed. It acts as a wildcard. Setting it to \a 1 means there
450 * is no filtering.
451 */
Harald Welte3ae27582010-03-26 21:24:24 +0800452void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800453{
454 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800455 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800456 else
Harald Welte3ae27582010-03-26 21:24:24 +0800457 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800458}
459
Harald Welte18fc4652011-08-17 14:14:17 +0200460/*! \brief Enable or disable the use of colored output
461 * \param[in] target Log target to be affected
462 * \param[in] use_color Use color (1) or don't use color (0)
463 */
Harald Welte3ae27582010-03-26 21:24:24 +0800464void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800465{
466 target->use_color = use_color;
467}
468
Harald Welte18fc4652011-08-17 14:14:17 +0200469/*! \brief Enable or disable printing of timestamps while logging
470 * \param[in] target Log target to be affected
471 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
472 */
Harald Welte3ae27582010-03-26 21:24:24 +0800473void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800474{
475 target->print_timestamp = print_timestamp;
476}
477
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100478/*! \brief Enable or disable printing of extended timestamps while logging
479 * \param[in] target Log target to be affected
480 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
481 *
482 * When both timestamp and extended timestamp is enabled then only
483 * the extended timestamp will be used. The format of the timestamp
484 * is YYYYMMDDhhmmssnnn.
485 */
486void log_set_print_extended_timestamp(struct log_target *target, int print_timestamp)
487{
488 target->print_ext_timestamp = print_timestamp;
489}
490
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200491/*! \brief Enable or disable printing of the filename while logging
492 * \param[in] target Log target to be affected
493 * \param[in] print_filename Enable (1) or disable (0) filenames
494 */
495void log_set_print_filename(struct log_target *target, int print_filename)
496{
497 target->print_filename = print_filename;
498}
499
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100500/*! \brief Enable or disable printing of the category name
501 * \param[in] target Log target to be affected
502 * \param[in] print_catname Enable (1) or disable (0) filenames
503 *
504 * Print the category/subsys name in front of every log message.
505 */
506void log_set_print_category(struct log_target *target, int print_category)
507{
508 target->print_category = print_category;
509}
510
Harald Welte18fc4652011-08-17 14:14:17 +0200511/*! \brief Set the global log level for a given log target
512 * \param[in] target Log target to be affected
513 * \param[in] log_level New global log level
514 */
Harald Welte3ae27582010-03-26 21:24:24 +0800515void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800516{
517 target->loglevel = log_level;
518}
519
Harald Weltede6e4982012-12-06 21:25:27 +0100520/*! \brief Set a category filter on a given log target
521 * \param[in] target Log target to be affected
522 * \param[in] category Log category to be affected
523 * \param[in] enable whether to enable or disable the filter
524 * \param[in] level Log level of the filter
525 */
Harald Welte3ae27582010-03-26 21:24:24 +0800526void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800527 int enable, int level)
528{
Harald Welte4ebdf742010-05-19 19:54:00 +0200529 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800530 return;
531 target->categories[category].enabled = !!enable;
532 target->categories[category].loglevel = level;
533}
534
Harald Welte76e72ab2011-02-17 15:52:39 +0100535static void _file_output(struct log_target *target, unsigned int level,
536 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800537{
Harald Welte0083cd32010-08-25 14:55:44 +0200538 fprintf(target->tgt_file.out, "%s", log);
539 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800540}
541
Harald Welte18fc4652011-08-17 14:14:17 +0200542/*! \brief Create a new log target skeleton */
Harald Welte3ae27582010-03-26 21:24:24 +0800543struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800544{
Harald Welte3ae27582010-03-26 21:24:24 +0800545 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800546 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800547
Harald Welte3ae27582010-03-26 21:24:24 +0800548 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800549 if (!target)
550 return NULL;
551
Harald Welteb43bc042011-06-27 10:29:17 +0200552 target->categories = talloc_zero_array(target,
553 struct log_category,
554 osmo_log_info->num_cat);
555 if (!target->categories) {
556 talloc_free(target);
557 return NULL;
558 }
559
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800560 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800561
562 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200563 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800564 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200565 cat->enabled = osmo_log_info->cat[i].enabled;
566 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800567 }
568
569 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800570 target->use_color = 1;
571 target->print_timestamp = 0;
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200572 target->print_filename = 1;
Harald Weltecc6313c2010-03-26 22:04:03 +0800573
574 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800575 target->loglevel = 0;
576 return target;
577}
578
Harald Welte18fc4652011-08-17 14:14:17 +0200579/*! \brief Create the STDERR log target */
Harald Welte3ae27582010-03-26 21:24:24 +0800580struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800581{
Harald Weltea3b844c2010-03-27 00:04:40 +0800582/* since C89/C99 says stderr is a macro, we can safely do this! */
583#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800584 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800585
Harald Welte3ae27582010-03-26 21:24:24 +0800586 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800587 if (!target)
588 return NULL;
589
Harald Welte28222962011-02-18 20:37:04 +0100590 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200591 target->tgt_file.out = stderr;
592 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800593 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800594#else
595 return NULL;
596#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800597}
598
Harald Welte18fc4652011-08-17 14:14:17 +0200599/*! \brief Create a new file-based log target
600 * \param[in] fname File name of the new log file
601 * \returns Log target in case of success, NULL otherwise
602 */
Harald Welte3086c392010-08-25 19:10:50 +0200603struct log_target *log_target_create_file(const char *fname)
604{
605 struct log_target *target;
606
607 target = log_target_create();
608 if (!target)
609 return NULL;
610
Harald Welte28222962011-02-18 20:37:04 +0100611 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200612 target->tgt_file.out = fopen(fname, "a");
613 if (!target->tgt_file.out)
614 return NULL;
615
616 target->output = _file_output;
617
618 target->tgt_file.fname = talloc_strdup(target, fname);
619
620 return target;
621}
622
Harald Welte18fc4652011-08-17 14:14:17 +0200623/*! \brief Find a registered log target
624 * \param[in] type Log target type
625 * \param[in] fname File name
626 * \returns Log target (if found), NULL otherwise
627 */
Harald Welte28222962011-02-18 20:37:04 +0100628struct log_target *log_target_find(int type, const char *fname)
629{
630 struct log_target *tgt;
631
632 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
633 if (tgt->type != type)
634 continue;
635 if (tgt->type == LOG_TGT_TYPE_FILE) {
636 if (!strcmp(fname, tgt->tgt_file.fname))
637 return tgt;
638 } else
639 return tgt;
640 }
641 return NULL;
642}
643
Harald Welte18fc4652011-08-17 14:14:17 +0200644/*! \brief Unregister, close and delete a log target */
Harald Welte3086c392010-08-25 19:10:50 +0200645void log_target_destroy(struct log_target *target)
646{
647
648 /* just in case, to make sure we don't have any references */
649 log_del_target(target);
650
651 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200652/* since C89/C99 says stderr is a macro, we can safely do this! */
653#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200654 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200655 if (target->tgt_file.out != stderr)
656#endif
657 {
Harald Welte3086c392010-08-25 19:10:50 +0200658 fclose(target->tgt_file.out);
659 target->tgt_file.out = NULL;
660 }
661 }
662
663 talloc_free(target);
664}
665
Harald Welte18fc4652011-08-17 14:14:17 +0200666/*! \brief close and re-open a log file (for log file rotation) */
Harald Welte3086c392010-08-25 19:10:50 +0200667int log_target_file_reopen(struct log_target *target)
668{
669 fclose(target->tgt_file.out);
670
671 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
672 if (!target->tgt_file.out)
673 return -errno;
674
675 /* we assume target->output already to be set */
676
677 return 0;
678}
679
Harald Welte4de854d2013-03-18 19:01:40 +0100680/*! \brief close and re-open a log file (for log file rotation) */
681int log_targets_reopen(void)
682{
683 struct log_target *tar;
684 int rc = 0;
685
686 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
687 switch (tar->type) {
688 case LOG_TGT_TYPE_FILE:
689 if (log_target_file_reopen(tar) < 0)
690 rc = -1;
691 break;
692 default:
693 break;
694 }
695 }
696
697 return rc;
698}
699
Harald Welte18fc4652011-08-17 14:14:17 +0200700/*! \brief Generates the logging command string for VTY
701 * \param[in] unused_info Deprecated parameter, no longer used!
702 */
Harald Weltece9fec32011-06-27 14:19:16 +0200703const char *log_vty_command_string(const struct log_info *unused_info)
Harald Welte7638af92010-05-11 16:39:22 +0200704{
Harald Weltece9fec32011-06-27 14:19:16 +0200705 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100706 int len = 0, offset = 0, ret, i, rem;
707 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200708 char *str;
709
Harald Welteb43bc042011-06-27 10:29:17 +0200710 for (i = 0; i < info->num_cat; i++) {
711 if (info->cat[i].name == NULL)
712 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100713 size += strlen(info->cat[i].name) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200714 }
Harald Welte7638af92010-05-11 16:39:22 +0200715
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100716 for (i = 0; i < LOGLEVEL_DEFS; i++)
717 size += strlen(loglevel_strs[i].str) + 1;
718
719 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200720 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200721 if (!str)
722 return NULL;
723
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200724 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100725 if (ret < 0)
726 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200727 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200728
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100729 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200730 if (info->cat[i].name) {
731 int j, name_len = strlen(info->cat[i].name)+1;
732 char name[name_len];
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100733
Harald Welteb43bc042011-06-27 10:29:17 +0200734 for (j = 0; j < name_len; j++)
735 name[j] = tolower(info->cat[i].name[j]);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100736
Harald Welteb43bc042011-06-27 10:29:17 +0200737 name[name_len-1] = '\0';
738 ret = snprintf(str + offset, rem, "%s|", name+1);
739 if (ret < 0)
740 goto err;
741 OSMO_SNPRINTF_RET(ret, rem, offset, len);
742 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100743 }
744 offset--; /* to remove the trailing | */
745 rem++;
746
747 ret = snprintf(str + offset, rem, ") (");
748 if (ret < 0)
749 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200750 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100751
752 for (i = 0; i < LOGLEVEL_DEFS; i++) {
753 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
754 char loglevel_str[loglevel_str_len];
755
756 for (j = 0; j < loglevel_str_len; j++)
757 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
758
759 loglevel_str[loglevel_str_len-1] = '\0';
760 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
761 if (ret < 0)
762 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200763 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100764 }
765 offset--; /* to remove the trailing | */
766 rem++;
767
768 ret = snprintf(str + offset, rem, ")");
769 if (ret < 0)
770 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200771 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100772err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200773 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100774 return str;
775}
776
Harald Welte18fc4652011-08-17 14:14:17 +0200777/*! \brief Generates the logging command description for VTY
778 * \param[in] unused_info Deprecated parameter, no longer used!
779 */
Harald Weltece9fec32011-06-27 14:19:16 +0200780const char *log_vty_command_description(const struct log_info *unused_info)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100781{
Harald Weltece9fec32011-06-27 14:19:16 +0200782 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100783 char *str;
784 int i, ret, len = 0, offset = 0, rem;
785 unsigned int size =
786 strlen(LOGGING_STR
787 "Set the log level for a specified category\n") + 1;
788
Harald Welteb43bc042011-06-27 10:29:17 +0200789 for (i = 0; i < info->num_cat; i++) {
790 if (info->cat[i].name == NULL)
791 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100792 size += strlen(info->cat[i].description) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200793 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100794
795 for (i = 0; i < LOGLEVEL_DEFS; i++)
796 size += strlen(loglevel_descriptions[i]) + 1;
797
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200798 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100799 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200800 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100801 if (!str)
802 return NULL;
803
804 ret = snprintf(str + offset, rem, LOGGING_STR
805 "Set the log level for a specified category\n");
806 if (ret < 0)
807 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200808 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100809
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200810 ret = snprintf(str + offset, rem,
811 "Global setting for all subsystems\n");
812 if (ret < 0)
813 goto err;
814 OSMO_SNPRINTF_RET(ret, rem, offset, len);
815
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100816 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200817 if (info->cat[i].name == NULL)
818 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100819 ret = snprintf(str + offset, rem, "%s\n",
820 info->cat[i].description);
821 if (ret < 0)
822 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200823 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100824 }
825 for (i = 0; i < LOGLEVEL_DEFS; i++) {
826 ret = snprintf(str + offset, rem, "%s\n",
827 loglevel_descriptions[i]);
828 if (ret < 0)
829 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200830 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100831 }
832err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200833 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200834 return str;
835}
836
Harald Welte18fc4652011-08-17 14:14:17 +0200837/*! \brief Initialize the Osmocom logging core
838 * \param[in] inf Information regarding logging categories
839 * \param[in] ctx \ref talloc context for logging allocations
840 * \returns 0 in case of success, negative in case of error
841 */
Harald Welteb43bc042011-06-27 10:29:17 +0200842int log_init(const struct log_info *inf, void *ctx)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800843{
Harald Welteb43bc042011-06-27 10:29:17 +0200844 int i;
845
846 tall_log_ctx = talloc_named_const(ctx, 1, "logging");
847 if (!tall_log_ctx)
848 return -ENOMEM;
849
850 osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
851 if (!osmo_log_info)
852 return -ENOMEM;
853
Holger Hans Peter Freytherb7d0f462013-12-29 19:38:01 +0100854 osmo_log_info->filter_fn = inf->filter_fn;
Harald Welteb43bc042011-06-27 10:29:17 +0200855 osmo_log_info->num_cat_user = inf->num_cat;
856 /* total number = number of user cat + library cat */
Harald Weltece9fec32011-06-27 14:19:16 +0200857 osmo_log_info->num_cat = inf->num_cat + ARRAY_SIZE(internal_cat);
Harald Welteb43bc042011-06-27 10:29:17 +0200858
859 osmo_log_info->cat = talloc_zero_array(osmo_log_info,
860 struct log_info_cat,
861 osmo_log_info->num_cat);
862 if (!osmo_log_info->cat) {
863 talloc_free(osmo_log_info);
864 osmo_log_info = NULL;
865 return -ENOMEM;
866 }
867
868 /* copy over the user part */
869 for (i = 0; i < inf->num_cat; i++) {
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200870 memcpy((struct log_info_cat *) &osmo_log_info->cat[i],
871 &inf->cat[i],
Harald Welteb43bc042011-06-27 10:29:17 +0200872 sizeof(struct log_info_cat));
873 }
874
875 /* copy over the library part */
Harald Welte9fe16522011-06-27 14:00:03 +0200876 for (i = 0; i < ARRAY_SIZE(internal_cat); i++) {
Harald Weltece9fec32011-06-27 14:19:16 +0200877 unsigned int cn = osmo_log_info->num_cat_user + i;
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200878 memcpy((struct log_info_cat *) &osmo_log_info->cat[cn],
Harald Welte9fe16522011-06-27 14:00:03 +0200879 &internal_cat[i], sizeof(struct log_info_cat));
880 }
881
882 return 0;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800883}
Harald Welte18fc4652011-08-17 14:14:17 +0200884
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100885/*! \brief Check whether a log entry will be generated.
886 * \returns != 0 if a log entry might get generated by at least one target */
887int log_check_level(int subsys, unsigned int level)
888{
889 struct log_target *tar;
890
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100891 subsys = map_subsys(subsys);
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100892
893 /* TODO: The following could/should be cached (update on config) */
894
895 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100896 if (!check_log_to_target(tar, subsys, level))
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100897 continue;
898
899 /* This might get logged (ignoring filters) */
900 return 1;
901 }
902
903 /* We are sure, that this will not be logged. */
904 return 0;
905}
906
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200907/*! @} */