blob: 35746e9b5e542f13897751557d1adb6def9283da [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
Holger Hans Peter Freyther79599ac2016-01-15 16:49:06 +0100342 /* Apply filters here... if that becomes messy we will
343 * need to put filters in a list and each filter will
344 * say stop, continue, output */
345 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
346 return 1;
347
348 if (osmo_log_info->filter_fn)
349 return osmo_log_info->filter_fn(&log_context, tar);
350
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100351 /* TODO: Check the filter/selector too? */
352 return 1;
353}
354
Harald Welte36c5a3e2011-08-27 14:33:19 +0200355/*! \brief vararg version of logging function */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200356void osmo_vlogp(int subsys, int level, const char *file, int line,
Harald Welte36c5a3e2011-08-27 14:33:19 +0200357 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800358{
Harald Welte3ae27582010-03-26 21:24:24 +0800359 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800360
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100361 subsys = map_subsys(subsys);
Harald Welteb43bc042011-06-27 10:29:17 +0200362
Harald Welte28222962011-02-18 20:37:04 +0100363 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200364 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800365
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100366 if (!check_log_to_target(tar, subsys, level))
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800367 continue;
368
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200369 /* According to the manpage, vsnprintf leaves the value of ap
370 * in undefined state. Since _output uses vsnprintf and it may
371 * be called several times, we have to pass a copy of ap. */
372 va_copy(bp, ap);
Harald Welteda127cb2011-07-02 21:51:32 +0200373 _output(tar, subsys, level, file, line, cont, format, bp);
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200374 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800375 }
376}
377
Harald Weltede6e4982012-12-06 21:25:27 +0100378/*! \brief logging function used by DEBUGP() macro */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200379void logp(int subsys, const char *file, int line, int cont,
Harald Welte3ae27582010-03-26 21:24:24 +0800380 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800381{
382 va_list ap;
383
384 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200385 osmo_vlogp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800386 va_end(ap);
387}
388
Harald Weltede6e4982012-12-06 21:25:27 +0100389/*! \brief logging function used by LOGP() macro */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200390void logp2(int subsys, unsigned int level, const char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800391{
392 va_list ap;
393
394 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200395 osmo_vlogp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800396 va_end(ap);
397}
398
Harald Welte18fc4652011-08-17 14:14:17 +0200399/*! \brief Register a new log target with the logging core
400 * \param[in] target Log target to be registered
401 */
Harald Welte3ae27582010-03-26 21:24:24 +0800402void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800403{
Harald Welte28222962011-02-18 20:37:04 +0100404 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800405}
406
Harald Welte18fc4652011-08-17 14:14:17 +0200407/*! \brief Unregister a log target from the logging core
408 * \param[in] target Log target to be unregistered
409 */
Harald Welte3ae27582010-03-26 21:24:24 +0800410void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800411{
412 llist_del(&target->entry);
413}
414
Harald Welte18fc4652011-08-17 14:14:17 +0200415/*! \brief Reset (clear) the logging context */
Harald Welte3ae27582010-03-26 21:24:24 +0800416void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800417{
Harald Welte3ae27582010-03-26 21:24:24 +0800418 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800419}
420
Harald Welte18fc4652011-08-17 14:14:17 +0200421/*! \brief Set the logging context
422 * \param[in] ctx_nr logging context number
423 * \param[in] value value to which the context is to be set
424 *
425 * A logging context is something like the subscriber identity to which
426 * the currently processed message relates, or the BTS through which it
427 * was received. As soon as this data is known, it can be set using
428 * this function. The main use of context information is for logging
429 * filters.
430 */
Harald Welte3ae27582010-03-26 21:24:24 +0800431int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800432{
Harald Welte3ae27582010-03-26 21:24:24 +0800433 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800434 return -EINVAL;
435
Harald Welte3ae27582010-03-26 21:24:24 +0800436 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800437
438 return 0;
439}
440
Harald Welte18fc4652011-08-17 14:14:17 +0200441/*! \brief Enable the \ref LOG_FILTER_ALL log filter
442 * \param[in] target Log target to be affected
443 * \param[in] all enable (1) or disable (0) the ALL filter
444 *
445 * When the \ref LOG_FILTER_ALL filter is enabled, all log messages will
446 * be printed. It acts as a wildcard. Setting it to \a 1 means there
447 * is no filtering.
448 */
Harald Welte3ae27582010-03-26 21:24:24 +0800449void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800450{
451 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800452 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800453 else
Harald Welte3ae27582010-03-26 21:24:24 +0800454 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800455}
456
Harald Welte18fc4652011-08-17 14:14:17 +0200457/*! \brief Enable or disable the use of colored output
458 * \param[in] target Log target to be affected
459 * \param[in] use_color Use color (1) or don't use color (0)
460 */
Harald Welte3ae27582010-03-26 21:24:24 +0800461void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800462{
463 target->use_color = use_color;
464}
465
Harald Welte18fc4652011-08-17 14:14:17 +0200466/*! \brief Enable or disable printing of timestamps while logging
467 * \param[in] target Log target to be affected
468 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
469 */
Harald Welte3ae27582010-03-26 21:24:24 +0800470void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800471{
472 target->print_timestamp = print_timestamp;
473}
474
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100475/*! \brief Enable or disable printing of extended timestamps while logging
476 * \param[in] target Log target to be affected
477 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
478 *
479 * When both timestamp and extended timestamp is enabled then only
480 * the extended timestamp will be used. The format of the timestamp
481 * is YYYYMMDDhhmmssnnn.
482 */
483void log_set_print_extended_timestamp(struct log_target *target, int print_timestamp)
484{
485 target->print_ext_timestamp = print_timestamp;
486}
487
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200488/*! \brief Enable or disable printing of the filename while logging
489 * \param[in] target Log target to be affected
490 * \param[in] print_filename Enable (1) or disable (0) filenames
491 */
492void log_set_print_filename(struct log_target *target, int print_filename)
493{
494 target->print_filename = print_filename;
495}
496
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100497/*! \brief Enable or disable printing of the category name
498 * \param[in] target Log target to be affected
499 * \param[in] print_catname Enable (1) or disable (0) filenames
500 *
501 * Print the category/subsys name in front of every log message.
502 */
503void log_set_print_category(struct log_target *target, int print_category)
504{
505 target->print_category = print_category;
506}
507
Harald Welte18fc4652011-08-17 14:14:17 +0200508/*! \brief Set the global log level for a given log target
509 * \param[in] target Log target to be affected
510 * \param[in] log_level New global log level
511 */
Harald Welte3ae27582010-03-26 21:24:24 +0800512void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800513{
514 target->loglevel = log_level;
515}
516
Harald Weltede6e4982012-12-06 21:25:27 +0100517/*! \brief Set a category filter on a given log target
518 * \param[in] target Log target to be affected
519 * \param[in] category Log category to be affected
520 * \param[in] enable whether to enable or disable the filter
521 * \param[in] level Log level of the filter
522 */
Harald Welte3ae27582010-03-26 21:24:24 +0800523void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800524 int enable, int level)
525{
Harald Welte4ebdf742010-05-19 19:54:00 +0200526 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800527 return;
528 target->categories[category].enabled = !!enable;
529 target->categories[category].loglevel = level;
530}
531
Harald Welte76e72ab2011-02-17 15:52:39 +0100532static void _file_output(struct log_target *target, unsigned int level,
533 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800534{
Harald Welte0083cd32010-08-25 14:55:44 +0200535 fprintf(target->tgt_file.out, "%s", log);
536 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800537}
538
Harald Welte18fc4652011-08-17 14:14:17 +0200539/*! \brief Create a new log target skeleton */
Harald Welte3ae27582010-03-26 21:24:24 +0800540struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800541{
Harald Welte3ae27582010-03-26 21:24:24 +0800542 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800543 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800544
Harald Welte3ae27582010-03-26 21:24:24 +0800545 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800546 if (!target)
547 return NULL;
548
Harald Welteb43bc042011-06-27 10:29:17 +0200549 target->categories = talloc_zero_array(target,
550 struct log_category,
551 osmo_log_info->num_cat);
552 if (!target->categories) {
553 talloc_free(target);
554 return NULL;
555 }
556
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800557 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800558
559 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200560 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800561 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200562 cat->enabled = osmo_log_info->cat[i].enabled;
563 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800564 }
565
566 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800567 target->use_color = 1;
568 target->print_timestamp = 0;
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200569 target->print_filename = 1;
Harald Weltecc6313c2010-03-26 22:04:03 +0800570
571 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800572 target->loglevel = 0;
573 return target;
574}
575
Harald Welte18fc4652011-08-17 14:14:17 +0200576/*! \brief Create the STDERR log target */
Harald Welte3ae27582010-03-26 21:24:24 +0800577struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800578{
Harald Weltea3b844c2010-03-27 00:04:40 +0800579/* since C89/C99 says stderr is a macro, we can safely do this! */
580#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800581 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800582
Harald Welte3ae27582010-03-26 21:24:24 +0800583 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800584 if (!target)
585 return NULL;
586
Harald Welte28222962011-02-18 20:37:04 +0100587 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200588 target->tgt_file.out = stderr;
589 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800590 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800591#else
592 return NULL;
593#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800594}
595
Harald Welte18fc4652011-08-17 14:14:17 +0200596/*! \brief Create a new file-based log target
597 * \param[in] fname File name of the new log file
598 * \returns Log target in case of success, NULL otherwise
599 */
Harald Welte3086c392010-08-25 19:10:50 +0200600struct log_target *log_target_create_file(const char *fname)
601{
602 struct log_target *target;
603
604 target = log_target_create();
605 if (!target)
606 return NULL;
607
Harald Welte28222962011-02-18 20:37:04 +0100608 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200609 target->tgt_file.out = fopen(fname, "a");
610 if (!target->tgt_file.out)
611 return NULL;
612
613 target->output = _file_output;
614
615 target->tgt_file.fname = talloc_strdup(target, fname);
616
617 return target;
618}
619
Harald Welte18fc4652011-08-17 14:14:17 +0200620/*! \brief Find a registered log target
621 * \param[in] type Log target type
622 * \param[in] fname File name
623 * \returns Log target (if found), NULL otherwise
624 */
Harald Welte28222962011-02-18 20:37:04 +0100625struct log_target *log_target_find(int type, const char *fname)
626{
627 struct log_target *tgt;
628
629 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
630 if (tgt->type != type)
631 continue;
632 if (tgt->type == LOG_TGT_TYPE_FILE) {
633 if (!strcmp(fname, tgt->tgt_file.fname))
634 return tgt;
635 } else
636 return tgt;
637 }
638 return NULL;
639}
640
Harald Welte18fc4652011-08-17 14:14:17 +0200641/*! \brief Unregister, close and delete a log target */
Harald Welte3086c392010-08-25 19:10:50 +0200642void log_target_destroy(struct log_target *target)
643{
644
645 /* just in case, to make sure we don't have any references */
646 log_del_target(target);
647
648 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200649/* since C89/C99 says stderr is a macro, we can safely do this! */
650#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200651 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200652 if (target->tgt_file.out != stderr)
653#endif
654 {
Harald Welte3086c392010-08-25 19:10:50 +0200655 fclose(target->tgt_file.out);
656 target->tgt_file.out = NULL;
657 }
658 }
659
660 talloc_free(target);
661}
662
Harald Welte18fc4652011-08-17 14:14:17 +0200663/*! \brief close and re-open a log file (for log file rotation) */
Harald Welte3086c392010-08-25 19:10:50 +0200664int log_target_file_reopen(struct log_target *target)
665{
666 fclose(target->tgt_file.out);
667
668 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
669 if (!target->tgt_file.out)
670 return -errno;
671
672 /* we assume target->output already to be set */
673
674 return 0;
675}
676
Harald Welte4de854d2013-03-18 19:01:40 +0100677/*! \brief close and re-open a log file (for log file rotation) */
678int log_targets_reopen(void)
679{
680 struct log_target *tar;
681 int rc = 0;
682
683 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
684 switch (tar->type) {
685 case LOG_TGT_TYPE_FILE:
686 if (log_target_file_reopen(tar) < 0)
687 rc = -1;
688 break;
689 default:
690 break;
691 }
692 }
693
694 return rc;
695}
696
Harald Welte18fc4652011-08-17 14:14:17 +0200697/*! \brief Generates the logging command string for VTY
698 * \param[in] unused_info Deprecated parameter, no longer used!
699 */
Harald Weltece9fec32011-06-27 14:19:16 +0200700const char *log_vty_command_string(const struct log_info *unused_info)
Harald Welte7638af92010-05-11 16:39:22 +0200701{
Harald Weltece9fec32011-06-27 14:19:16 +0200702 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100703 int len = 0, offset = 0, ret, i, rem;
704 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200705 char *str;
706
Harald Welteb43bc042011-06-27 10:29:17 +0200707 for (i = 0; i < info->num_cat; i++) {
708 if (info->cat[i].name == NULL)
709 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100710 size += strlen(info->cat[i].name) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200711 }
Harald Welte7638af92010-05-11 16:39:22 +0200712
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100713 for (i = 0; i < LOGLEVEL_DEFS; i++)
714 size += strlen(loglevel_strs[i].str) + 1;
715
716 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200717 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200718 if (!str)
719 return NULL;
720
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200721 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100722 if (ret < 0)
723 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200724 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200725
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100726 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200727 if (info->cat[i].name) {
728 int j, name_len = strlen(info->cat[i].name)+1;
729 char name[name_len];
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100730
Harald Welteb43bc042011-06-27 10:29:17 +0200731 for (j = 0; j < name_len; j++)
732 name[j] = tolower(info->cat[i].name[j]);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100733
Harald Welteb43bc042011-06-27 10:29:17 +0200734 name[name_len-1] = '\0';
735 ret = snprintf(str + offset, rem, "%s|", name+1);
736 if (ret < 0)
737 goto err;
738 OSMO_SNPRINTF_RET(ret, rem, offset, len);
739 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100740 }
741 offset--; /* to remove the trailing | */
742 rem++;
743
744 ret = snprintf(str + offset, rem, ") (");
745 if (ret < 0)
746 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200747 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100748
749 for (i = 0; i < LOGLEVEL_DEFS; i++) {
750 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
751 char loglevel_str[loglevel_str_len];
752
753 for (j = 0; j < loglevel_str_len; j++)
754 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
755
756 loglevel_str[loglevel_str_len-1] = '\0';
757 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
758 if (ret < 0)
759 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200760 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100761 }
762 offset--; /* to remove the trailing | */
763 rem++;
764
765 ret = snprintf(str + offset, rem, ")");
766 if (ret < 0)
767 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200768 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100769err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200770 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100771 return str;
772}
773
Harald Welte18fc4652011-08-17 14:14:17 +0200774/*! \brief Generates the logging command description for VTY
775 * \param[in] unused_info Deprecated parameter, no longer used!
776 */
Harald Weltece9fec32011-06-27 14:19:16 +0200777const char *log_vty_command_description(const struct log_info *unused_info)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100778{
Harald Weltece9fec32011-06-27 14:19:16 +0200779 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100780 char *str;
781 int i, ret, len = 0, offset = 0, rem;
782 unsigned int size =
783 strlen(LOGGING_STR
784 "Set the log level for a specified category\n") + 1;
785
Harald Welteb43bc042011-06-27 10:29:17 +0200786 for (i = 0; i < info->num_cat; i++) {
787 if (info->cat[i].name == NULL)
788 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100789 size += strlen(info->cat[i].description) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200790 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100791
792 for (i = 0; i < LOGLEVEL_DEFS; i++)
793 size += strlen(loglevel_descriptions[i]) + 1;
794
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200795 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100796 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200797 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100798 if (!str)
799 return NULL;
800
801 ret = snprintf(str + offset, rem, LOGGING_STR
802 "Set the log level for a specified category\n");
803 if (ret < 0)
804 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200805 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100806
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200807 ret = snprintf(str + offset, rem,
808 "Global setting for all subsystems\n");
809 if (ret < 0)
810 goto err;
811 OSMO_SNPRINTF_RET(ret, rem, offset, len);
812
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100813 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200814 if (info->cat[i].name == NULL)
815 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100816 ret = snprintf(str + offset, rem, "%s\n",
817 info->cat[i].description);
818 if (ret < 0)
819 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200820 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100821 }
822 for (i = 0; i < LOGLEVEL_DEFS; i++) {
823 ret = snprintf(str + offset, rem, "%s\n",
824 loglevel_descriptions[i]);
825 if (ret < 0)
826 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200827 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100828 }
829err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200830 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200831 return str;
832}
833
Harald Welte18fc4652011-08-17 14:14:17 +0200834/*! \brief Initialize the Osmocom logging core
835 * \param[in] inf Information regarding logging categories
836 * \param[in] ctx \ref talloc context for logging allocations
837 * \returns 0 in case of success, negative in case of error
838 */
Harald Welteb43bc042011-06-27 10:29:17 +0200839int log_init(const struct log_info *inf, void *ctx)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800840{
Harald Welteb43bc042011-06-27 10:29:17 +0200841 int i;
842
843 tall_log_ctx = talloc_named_const(ctx, 1, "logging");
844 if (!tall_log_ctx)
845 return -ENOMEM;
846
847 osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
848 if (!osmo_log_info)
849 return -ENOMEM;
850
Holger Hans Peter Freytherb7d0f462013-12-29 19:38:01 +0100851 osmo_log_info->filter_fn = inf->filter_fn;
Harald Welteb43bc042011-06-27 10:29:17 +0200852 osmo_log_info->num_cat_user = inf->num_cat;
853 /* total number = number of user cat + library cat */
Harald Weltece9fec32011-06-27 14:19:16 +0200854 osmo_log_info->num_cat = inf->num_cat + ARRAY_SIZE(internal_cat);
Harald Welteb43bc042011-06-27 10:29:17 +0200855
856 osmo_log_info->cat = talloc_zero_array(osmo_log_info,
857 struct log_info_cat,
858 osmo_log_info->num_cat);
859 if (!osmo_log_info->cat) {
860 talloc_free(osmo_log_info);
861 osmo_log_info = NULL;
862 return -ENOMEM;
863 }
864
865 /* copy over the user part */
866 for (i = 0; i < inf->num_cat; i++) {
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200867 memcpy((struct log_info_cat *) &osmo_log_info->cat[i],
868 &inf->cat[i],
Harald Welteb43bc042011-06-27 10:29:17 +0200869 sizeof(struct log_info_cat));
870 }
871
872 /* copy over the library part */
Harald Welte9fe16522011-06-27 14:00:03 +0200873 for (i = 0; i < ARRAY_SIZE(internal_cat); i++) {
Harald Weltece9fec32011-06-27 14:19:16 +0200874 unsigned int cn = osmo_log_info->num_cat_user + i;
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200875 memcpy((struct log_info_cat *) &osmo_log_info->cat[cn],
Harald Welte9fe16522011-06-27 14:00:03 +0200876 &internal_cat[i], sizeof(struct log_info_cat));
877 }
878
879 return 0;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800880}
Harald Welte18fc4652011-08-17 14:14:17 +0200881
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100882/*! \brief Check whether a log entry will be generated.
883 * \returns != 0 if a log entry might get generated by at least one target */
884int log_check_level(int subsys, unsigned int level)
885{
886 struct log_target *tar;
887
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100888 subsys = map_subsys(subsys);
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100889
890 /* TODO: The following could/should be cached (update on config) */
891
892 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100893 if (!check_log_to_target(tar, subsys, level))
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100894 continue;
895
896 /* This might get logged (ignoring filters) */
897 return 1;
898 }
899
900 /* We are sure, that this will not be logged. */
901 return 0;
902}
903
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200904/*! @} */