blob: b96e64a1615f886921908bb9eac5bd445a1a419f [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, ":");
Neels Hofmeyrda1b20c2016-04-14 15:12:16 +0200193 OSMO_ASSERT(category_token);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800194 do {
Harald Welte4ebdf742010-05-19 19:54:00 +0200195 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Nico Golde0262d3f2012-09-21 17:44:58 +0200196 size_t length, cat_length;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800197 char* colon = strstr(category_token, ",");
Nico Golde0262d3f2012-09-21 17:44:58 +0200198
199 if (!osmo_log_info->cat[i].name)
200 continue;
201
202 length = strlen(category_token);
203 cat_length = strlen(osmo_log_info->cat[i].name);
Pablo Neira Ayuso300e78d2011-08-11 13:24:18 +0200204
205 /* Use longest length not to match subocurrences. */
206 if (cat_length > length)
207 length = cat_length;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800208
209 if (colon)
210 length = colon - category_token;
211
Harald Welte4ebdf742010-05-19 19:54:00 +0200212 if (strncasecmp(osmo_log_info->cat[i].name,
213 category_token, length) == 0) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800214 int level = 0;
215
216 if (colon)
217 level = atoi(colon+1);
218
Harald Weltefaadfe22010-03-26 21:05:43 +0800219 target->categories[i].enabled = 1;
220 target->categories[i].loglevel = level;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800221 }
222 }
223 } while ((category_token = strtok(NULL, ":")));
224
225 free(mask);
226}
227
228static const char* color(int subsys)
229{
Harald Welte4ebdf742010-05-19 19:54:00 +0200230 if (subsys < osmo_log_info->num_cat)
231 return osmo_log_info->cat[subsys].color;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800232
Harald Welted788f662010-03-26 09:45:03 +0800233 return NULL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800234}
235
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100236static const char* category_name(int subsys)
237{
238 if (subsys < osmo_log_info->num_cat)
239 return osmo_log_info->cat[subsys].name;
240
241 return NULL;
242}
243
Harald Welte3ae27582010-03-26 21:24:24 +0800244static void _output(struct log_target *target, unsigned int subsys,
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200245 unsigned int level, const char *file, int line, int cont,
Harald Welte76e72ab2011-02-17 15:52:39 +0100246 const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800247{
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800248 char buf[4096];
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200249 int ret, len = 0, offset = 0, rem = sizeof(buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800250
251 /* are we using color */
252 if (target->use_color) {
Harald Welted788f662010-03-26 09:45:03 +0800253 const char *c = color(subsys);
254 if (c) {
Holger Hans Peter Freyther5f91a402014-12-05 10:29:45 +0100255 ret = snprintf(buf + offset, rem, "%s", c);
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200256 if (ret < 0)
257 goto err;
258 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welted788f662010-03-26 09:45:03 +0800259 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800260 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800261 if (!cont) {
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100262 if (target->print_ext_timestamp) {
263 struct tm tm;
Jacob Erlbeckb61b2ca2015-03-17 10:21:15 +0100264 struct timeval tv;
265 gettimeofday(&tv, NULL);
266 localtime_r(&tv.tv_sec, &tm);
267 ret = snprintf(buf + offset, rem, "%04d%02d%02d%02d%02d%02d%03d ",
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100268 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
Jacob Erlbeckb61b2ca2015-03-17 10:21:15 +0100269 tm.tm_hour, tm.tm_min, tm.tm_sec,
270 (int)(tv.tv_usec / 1000));
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100271 if (ret < 0)
272 goto err;
273 OSMO_SNPRINTF_RET(ret, rem, offset, len);
274 } else if (target->print_timestamp) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800275 char *timestr;
276 time_t tm;
277 tm = time(NULL);
278 timestr = ctime(&tm);
279 timestr[strlen(timestr)-1] = '\0';
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200280 ret = snprintf(buf + offset, rem, "%s ", timestr);
281 if (ret < 0)
282 goto err;
283 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800284 }
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100285 if (target->print_category) {
286 ret = snprintf(buf + offset, rem, "%s ", category_name(subsys));
287 if (ret < 0)
288 goto err;
289 OSMO_SNPRINTF_RET(ret, rem, offset, len);
290 }
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200291 if (target->print_filename) {
292 ret = snprintf(buf + offset, rem, "<%4.4x> %s:%d ",
293 subsys, file, line);
294 if (ret < 0)
295 goto err;
296 OSMO_SNPRINTF_RET(ret, rem, offset, len);
297 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800298 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200299 ret = vsnprintf(buf + offset, rem, format, ap);
300 if (ret < 0)
301 goto err;
302 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800303
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200304 ret = snprintf(buf + offset, rem, "%s",
305 target->use_color ? "\033[0;m" : "");
306 if (ret < 0)
307 goto err;
308 OSMO_SNPRINTF_RET(ret, rem, offset, len);
309err:
310 buf[sizeof(buf)-1] = '\0';
311 target->output(target, level, buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800312}
313
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100314static inline int map_subsys(int subsys)
315{
316 if (subsys < 0)
317 subsys = subsys_lib2index(subsys);
318
319 if (subsys > osmo_log_info->num_cat)
320 subsys = DLGLOBAL;
321 return subsys;
322}
323
324static inline int check_log_to_target(struct log_target *tar, int subsys, int level)
325{
326 struct log_category *category;
327
328 category = &tar->categories[subsys];
329
330 /* subsystem is not supposed to be logged */
331 if (!category->enabled)
332 return 0;
333
334 /* Check the global log level */
335 if (tar->loglevel != 0 && level < tar->loglevel)
336 return 0;
337
338 /* Check the category log level */
339 if (tar->loglevel == 0 && category->loglevel != 0 &&
340 level < category->loglevel)
341 return 0;
342
Holger Hans Peter Freyther79599ac2016-01-15 16:49:06 +0100343 /* Apply filters here... if that becomes messy we will
344 * need to put filters in a list and each filter will
345 * say stop, continue, output */
346 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
347 return 1;
348
349 if (osmo_log_info->filter_fn)
350 return osmo_log_info->filter_fn(&log_context, tar);
351
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100352 /* TODO: Check the filter/selector too? */
353 return 1;
354}
355
Harald Welte36c5a3e2011-08-27 14:33:19 +0200356/*! \brief vararg version of logging function */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200357void osmo_vlogp(int subsys, int level, const char *file, int line,
Harald Welte36c5a3e2011-08-27 14:33:19 +0200358 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800359{
Harald Welte3ae27582010-03-26 21:24:24 +0800360 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800361
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100362 subsys = map_subsys(subsys);
Harald Welteb43bc042011-06-27 10:29:17 +0200363
Harald Welte28222962011-02-18 20:37:04 +0100364 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200365 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800366
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100367 if (!check_log_to_target(tar, subsys, level))
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800368 continue;
369
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200370 /* According to the manpage, vsnprintf leaves the value of ap
371 * in undefined state. Since _output uses vsnprintf and it may
372 * be called several times, we have to pass a copy of ap. */
373 va_copy(bp, ap);
Harald Welteda127cb2011-07-02 21:51:32 +0200374 _output(tar, subsys, level, file, line, cont, format, bp);
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200375 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800376 }
377}
378
Harald Weltede6e4982012-12-06 21:25:27 +0100379/*! \brief logging function used by DEBUGP() macro */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200380void logp(int subsys, const char *file, int line, int cont,
Harald Welte3ae27582010-03-26 21:24:24 +0800381 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800382{
383 va_list ap;
384
385 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200386 osmo_vlogp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800387 va_end(ap);
388}
389
Harald Weltede6e4982012-12-06 21:25:27 +0100390/*! \brief logging function used by LOGP() macro */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200391void logp2(int subsys, unsigned int level, const char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800392{
393 va_list ap;
394
395 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200396 osmo_vlogp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800397 va_end(ap);
398}
399
Harald Welte18fc4652011-08-17 14:14:17 +0200400/*! \brief Register a new log target with the logging core
401 * \param[in] target Log target to be registered
402 */
Harald Welte3ae27582010-03-26 21:24:24 +0800403void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800404{
Harald Welte28222962011-02-18 20:37:04 +0100405 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800406}
407
Harald Welte18fc4652011-08-17 14:14:17 +0200408/*! \brief Unregister a log target from the logging core
409 * \param[in] target Log target to be unregistered
410 */
Harald Welte3ae27582010-03-26 21:24:24 +0800411void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800412{
413 llist_del(&target->entry);
414}
415
Harald Welte18fc4652011-08-17 14:14:17 +0200416/*! \brief Reset (clear) the logging context */
Harald Welte3ae27582010-03-26 21:24:24 +0800417void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800418{
Harald Welte3ae27582010-03-26 21:24:24 +0800419 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800420}
421
Harald Welte18fc4652011-08-17 14:14:17 +0200422/*! \brief Set the logging context
423 * \param[in] ctx_nr logging context number
424 * \param[in] value value to which the context is to be set
425 *
426 * A logging context is something like the subscriber identity to which
427 * the currently processed message relates, or the BTS through which it
428 * was received. As soon as this data is known, it can be set using
429 * this function. The main use of context information is for logging
430 * filters.
431 */
Harald Welte3ae27582010-03-26 21:24:24 +0800432int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800433{
Harald Welte3ae27582010-03-26 21:24:24 +0800434 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800435 return -EINVAL;
436
Harald Welte3ae27582010-03-26 21:24:24 +0800437 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800438
439 return 0;
440}
441
Harald Welte18fc4652011-08-17 14:14:17 +0200442/*! \brief Enable the \ref LOG_FILTER_ALL log filter
443 * \param[in] target Log target to be affected
444 * \param[in] all enable (1) or disable (0) the ALL filter
445 *
446 * When the \ref LOG_FILTER_ALL filter is enabled, all log messages will
447 * be printed. It acts as a wildcard. Setting it to \a 1 means there
448 * is no filtering.
449 */
Harald Welte3ae27582010-03-26 21:24:24 +0800450void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800451{
452 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800453 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800454 else
Harald Welte3ae27582010-03-26 21:24:24 +0800455 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800456}
457
Harald Welte18fc4652011-08-17 14:14:17 +0200458/*! \brief Enable or disable the use of colored output
459 * \param[in] target Log target to be affected
460 * \param[in] use_color Use color (1) or don't use color (0)
461 */
Harald Welte3ae27582010-03-26 21:24:24 +0800462void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800463{
464 target->use_color = use_color;
465}
466
Harald Welte18fc4652011-08-17 14:14:17 +0200467/*! \brief Enable or disable printing of timestamps while logging
468 * \param[in] target Log target to be affected
469 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
470 */
Harald Welte3ae27582010-03-26 21:24:24 +0800471void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800472{
473 target->print_timestamp = print_timestamp;
474}
475
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100476/*! \brief Enable or disable printing of extended timestamps while logging
477 * \param[in] target Log target to be affected
478 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
479 *
480 * When both timestamp and extended timestamp is enabled then only
481 * the extended timestamp will be used. The format of the timestamp
482 * is YYYYMMDDhhmmssnnn.
483 */
484void log_set_print_extended_timestamp(struct log_target *target, int print_timestamp)
485{
486 target->print_ext_timestamp = print_timestamp;
487}
488
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200489/*! \brief Enable or disable printing of the filename while logging
490 * \param[in] target Log target to be affected
491 * \param[in] print_filename Enable (1) or disable (0) filenames
492 */
493void log_set_print_filename(struct log_target *target, int print_filename)
494{
495 target->print_filename = print_filename;
496}
497
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100498/*! \brief Enable or disable printing of the category name
499 * \param[in] target Log target to be affected
500 * \param[in] print_catname Enable (1) or disable (0) filenames
501 *
502 * Print the category/subsys name in front of every log message.
503 */
504void log_set_print_category(struct log_target *target, int print_category)
505{
506 target->print_category = print_category;
507}
508
Harald Welte18fc4652011-08-17 14:14:17 +0200509/*! \brief Set the global log level for a given log target
510 * \param[in] target Log target to be affected
511 * \param[in] log_level New global log level
512 */
Harald Welte3ae27582010-03-26 21:24:24 +0800513void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800514{
515 target->loglevel = log_level;
516}
517
Harald Weltede6e4982012-12-06 21:25:27 +0100518/*! \brief Set a category filter on a given log target
519 * \param[in] target Log target to be affected
520 * \param[in] category Log category to be affected
521 * \param[in] enable whether to enable or disable the filter
522 * \param[in] level Log level of the filter
523 */
Harald Welte3ae27582010-03-26 21:24:24 +0800524void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800525 int enable, int level)
526{
Harald Welte4ebdf742010-05-19 19:54:00 +0200527 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800528 return;
529 target->categories[category].enabled = !!enable;
530 target->categories[category].loglevel = level;
531}
532
Harald Welte76e72ab2011-02-17 15:52:39 +0100533static void _file_output(struct log_target *target, unsigned int level,
534 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800535{
Harald Welte0083cd32010-08-25 14:55:44 +0200536 fprintf(target->tgt_file.out, "%s", log);
537 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800538}
539
Harald Welte18fc4652011-08-17 14:14:17 +0200540/*! \brief Create a new log target skeleton */
Harald Welte3ae27582010-03-26 21:24:24 +0800541struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800542{
Harald Welte3ae27582010-03-26 21:24:24 +0800543 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800544 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800545
Harald Welte3ae27582010-03-26 21:24:24 +0800546 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800547 if (!target)
548 return NULL;
549
Harald Welteb43bc042011-06-27 10:29:17 +0200550 target->categories = talloc_zero_array(target,
551 struct log_category,
552 osmo_log_info->num_cat);
553 if (!target->categories) {
554 talloc_free(target);
555 return NULL;
556 }
557
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800558 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800559
560 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200561 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800562 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200563 cat->enabled = osmo_log_info->cat[i].enabled;
564 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800565 }
566
567 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800568 target->use_color = 1;
569 target->print_timestamp = 0;
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200570 target->print_filename = 1;
Harald Weltecc6313c2010-03-26 22:04:03 +0800571
572 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800573 target->loglevel = 0;
574 return target;
575}
576
Harald Welte18fc4652011-08-17 14:14:17 +0200577/*! \brief Create the STDERR log target */
Harald Welte3ae27582010-03-26 21:24:24 +0800578struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800579{
Harald Weltea3b844c2010-03-27 00:04:40 +0800580/* since C89/C99 says stderr is a macro, we can safely do this! */
581#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800582 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800583
Harald Welte3ae27582010-03-26 21:24:24 +0800584 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800585 if (!target)
586 return NULL;
587
Harald Welte28222962011-02-18 20:37:04 +0100588 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200589 target->tgt_file.out = stderr;
590 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800591 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800592#else
593 return NULL;
594#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800595}
596
Harald Welte18fc4652011-08-17 14:14:17 +0200597/*! \brief Create a new file-based log target
598 * \param[in] fname File name of the new log file
599 * \returns Log target in case of success, NULL otherwise
600 */
Harald Welte3086c392010-08-25 19:10:50 +0200601struct log_target *log_target_create_file(const char *fname)
602{
603 struct log_target *target;
604
605 target = log_target_create();
606 if (!target)
607 return NULL;
608
Harald Welte28222962011-02-18 20:37:04 +0100609 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200610 target->tgt_file.out = fopen(fname, "a");
611 if (!target->tgt_file.out)
612 return NULL;
613
614 target->output = _file_output;
615
616 target->tgt_file.fname = talloc_strdup(target, fname);
617
618 return target;
619}
620
Harald Welte18fc4652011-08-17 14:14:17 +0200621/*! \brief Find a registered log target
622 * \param[in] type Log target type
623 * \param[in] fname File name
624 * \returns Log target (if found), NULL otherwise
625 */
Harald Welte28222962011-02-18 20:37:04 +0100626struct log_target *log_target_find(int type, const char *fname)
627{
628 struct log_target *tgt;
629
630 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
631 if (tgt->type != type)
632 continue;
633 if (tgt->type == LOG_TGT_TYPE_FILE) {
634 if (!strcmp(fname, tgt->tgt_file.fname))
635 return tgt;
636 } else
637 return tgt;
638 }
639 return NULL;
640}
641
Harald Welte18fc4652011-08-17 14:14:17 +0200642/*! \brief Unregister, close and delete a log target */
Harald Welte3086c392010-08-25 19:10:50 +0200643void log_target_destroy(struct log_target *target)
644{
645
646 /* just in case, to make sure we don't have any references */
647 log_del_target(target);
648
649 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200650/* since C89/C99 says stderr is a macro, we can safely do this! */
651#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200652 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200653 if (target->tgt_file.out != stderr)
654#endif
655 {
Harald Welte3086c392010-08-25 19:10:50 +0200656 fclose(target->tgt_file.out);
657 target->tgt_file.out = NULL;
658 }
659 }
660
661 talloc_free(target);
662}
663
Harald Welte18fc4652011-08-17 14:14:17 +0200664/*! \brief close and re-open a log file (for log file rotation) */
Harald Welte3086c392010-08-25 19:10:50 +0200665int log_target_file_reopen(struct log_target *target)
666{
667 fclose(target->tgt_file.out);
668
669 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
670 if (!target->tgt_file.out)
671 return -errno;
672
673 /* we assume target->output already to be set */
674
675 return 0;
676}
677
Harald Welte4de854d2013-03-18 19:01:40 +0100678/*! \brief close and re-open a log file (for log file rotation) */
679int log_targets_reopen(void)
680{
681 struct log_target *tar;
682 int rc = 0;
683
684 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
685 switch (tar->type) {
686 case LOG_TGT_TYPE_FILE:
687 if (log_target_file_reopen(tar) < 0)
688 rc = -1;
689 break;
690 default:
691 break;
692 }
693 }
694
695 return rc;
696}
697
Harald Welte18fc4652011-08-17 14:14:17 +0200698/*! \brief Generates the logging command string for VTY
699 * \param[in] unused_info Deprecated parameter, no longer used!
700 */
Harald Weltece9fec32011-06-27 14:19:16 +0200701const char *log_vty_command_string(const struct log_info *unused_info)
Harald Welte7638af92010-05-11 16:39:22 +0200702{
Harald Weltece9fec32011-06-27 14:19:16 +0200703 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100704 int len = 0, offset = 0, ret, i, rem;
705 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200706 char *str;
707
Harald Welteb43bc042011-06-27 10:29:17 +0200708 for (i = 0; i < info->num_cat; i++) {
709 if (info->cat[i].name == NULL)
710 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100711 size += strlen(info->cat[i].name) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200712 }
Harald Welte7638af92010-05-11 16:39:22 +0200713
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100714 for (i = 0; i < LOGLEVEL_DEFS; i++)
715 size += strlen(loglevel_strs[i].str) + 1;
716
717 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200718 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200719 if (!str)
720 return NULL;
721
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200722 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100723 if (ret < 0)
724 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200725 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200726
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100727 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200728 if (info->cat[i].name) {
729 int j, name_len = strlen(info->cat[i].name)+1;
730 char name[name_len];
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100731
Harald Welteb43bc042011-06-27 10:29:17 +0200732 for (j = 0; j < name_len; j++)
733 name[j] = tolower(info->cat[i].name[j]);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100734
Harald Welteb43bc042011-06-27 10:29:17 +0200735 name[name_len-1] = '\0';
736 ret = snprintf(str + offset, rem, "%s|", name+1);
737 if (ret < 0)
738 goto err;
739 OSMO_SNPRINTF_RET(ret, rem, offset, len);
740 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100741 }
742 offset--; /* to remove the trailing | */
743 rem++;
744
745 ret = snprintf(str + offset, rem, ") (");
746 if (ret < 0)
747 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200748 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100749
750 for (i = 0; i < LOGLEVEL_DEFS; i++) {
751 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
752 char loglevel_str[loglevel_str_len];
753
754 for (j = 0; j < loglevel_str_len; j++)
755 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
756
757 loglevel_str[loglevel_str_len-1] = '\0';
758 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
759 if (ret < 0)
760 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200761 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100762 }
763 offset--; /* to remove the trailing | */
764 rem++;
765
766 ret = snprintf(str + offset, rem, ")");
767 if (ret < 0)
768 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200769 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100770err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200771 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100772 return str;
773}
774
Harald Welte18fc4652011-08-17 14:14:17 +0200775/*! \brief Generates the logging command description for VTY
776 * \param[in] unused_info Deprecated parameter, no longer used!
777 */
Harald Weltece9fec32011-06-27 14:19:16 +0200778const char *log_vty_command_description(const struct log_info *unused_info)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100779{
Harald Weltece9fec32011-06-27 14:19:16 +0200780 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100781 char *str;
782 int i, ret, len = 0, offset = 0, rem;
783 unsigned int size =
784 strlen(LOGGING_STR
785 "Set the log level for a specified category\n") + 1;
786
Harald Welteb43bc042011-06-27 10:29:17 +0200787 for (i = 0; i < info->num_cat; i++) {
788 if (info->cat[i].name == NULL)
789 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100790 size += strlen(info->cat[i].description) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200791 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100792
793 for (i = 0; i < LOGLEVEL_DEFS; i++)
794 size += strlen(loglevel_descriptions[i]) + 1;
795
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200796 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100797 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200798 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100799 if (!str)
800 return NULL;
801
802 ret = snprintf(str + offset, rem, LOGGING_STR
803 "Set the log level for a specified category\n");
804 if (ret < 0)
805 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200806 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100807
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200808 ret = snprintf(str + offset, rem,
809 "Global setting for all subsystems\n");
810 if (ret < 0)
811 goto err;
812 OSMO_SNPRINTF_RET(ret, rem, offset, len);
813
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100814 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200815 if (info->cat[i].name == NULL)
816 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100817 ret = snprintf(str + offset, rem, "%s\n",
818 info->cat[i].description);
819 if (ret < 0)
820 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200821 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100822 }
823 for (i = 0; i < LOGLEVEL_DEFS; i++) {
824 ret = snprintf(str + offset, rem, "%s\n",
825 loglevel_descriptions[i]);
826 if (ret < 0)
827 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200828 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100829 }
830err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200831 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200832 return str;
833}
834
Harald Welte18fc4652011-08-17 14:14:17 +0200835/*! \brief Initialize the Osmocom logging core
836 * \param[in] inf Information regarding logging categories
837 * \param[in] ctx \ref talloc context for logging allocations
838 * \returns 0 in case of success, negative in case of error
839 */
Harald Welteb43bc042011-06-27 10:29:17 +0200840int log_init(const struct log_info *inf, void *ctx)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800841{
Harald Welteb43bc042011-06-27 10:29:17 +0200842 int i;
843
844 tall_log_ctx = talloc_named_const(ctx, 1, "logging");
845 if (!tall_log_ctx)
846 return -ENOMEM;
847
848 osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
849 if (!osmo_log_info)
850 return -ENOMEM;
851
Holger Hans Peter Freytherb7d0f462013-12-29 19:38:01 +0100852 osmo_log_info->filter_fn = inf->filter_fn;
Harald Welteb43bc042011-06-27 10:29:17 +0200853 osmo_log_info->num_cat_user = inf->num_cat;
854 /* total number = number of user cat + library cat */
Harald Weltece9fec32011-06-27 14:19:16 +0200855 osmo_log_info->num_cat = inf->num_cat + ARRAY_SIZE(internal_cat);
Harald Welteb43bc042011-06-27 10:29:17 +0200856
857 osmo_log_info->cat = talloc_zero_array(osmo_log_info,
858 struct log_info_cat,
859 osmo_log_info->num_cat);
860 if (!osmo_log_info->cat) {
861 talloc_free(osmo_log_info);
862 osmo_log_info = NULL;
863 return -ENOMEM;
864 }
865
866 /* copy over the user part */
867 for (i = 0; i < inf->num_cat; i++) {
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200868 memcpy((struct log_info_cat *) &osmo_log_info->cat[i],
869 &inf->cat[i],
Harald Welteb43bc042011-06-27 10:29:17 +0200870 sizeof(struct log_info_cat));
871 }
872
873 /* copy over the library part */
Harald Welte9fe16522011-06-27 14:00:03 +0200874 for (i = 0; i < ARRAY_SIZE(internal_cat); i++) {
Harald Weltece9fec32011-06-27 14:19:16 +0200875 unsigned int cn = osmo_log_info->num_cat_user + i;
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200876 memcpy((struct log_info_cat *) &osmo_log_info->cat[cn],
Harald Welte9fe16522011-06-27 14:00:03 +0200877 &internal_cat[i], sizeof(struct log_info_cat));
878 }
879
880 return 0;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800881}
Harald Welte18fc4652011-08-17 14:14:17 +0200882
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100883/*! \brief Check whether a log entry will be generated.
884 * \returns != 0 if a log entry might get generated by at least one target */
885int log_check_level(int subsys, unsigned int level)
886{
887 struct log_target *tar;
888
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100889 subsys = map_subsys(subsys);
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100890
891 /* TODO: The following could/should be cached (update on config) */
892
893 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100894 if (!check_log_to_target(tar, subsys, level))
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100895 continue;
896
897 /* This might get logged (ignoring filters) */
898 return 1;
899 }
900
901 /* We are sure, that this will not be logged. */
902 return 0;
903}
904
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200905/*! @} */