blob: c7b199999fa3796ff9b3ef800a93cd6f40d68608 [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
Harald Welte36c5a3e2011-08-27 14:33:19 +0200313/*! \brief vararg version of logging function */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200314void osmo_vlogp(int subsys, int level, const char *file, int line,
Harald Welte36c5a3e2011-08-27 14:33:19 +0200315 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800316{
Harald Welte3ae27582010-03-26 21:24:24 +0800317 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800318
Harald Welteb43bc042011-06-27 10:29:17 +0200319 if (subsys < 0)
320 subsys = subsys_lib2index(subsys);
321
322 if (subsys > osmo_log_info->num_cat)
323 subsys = DLGLOBAL;
324
Harald Welte28222962011-02-18 20:37:04 +0100325 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Harald Welte3ae27582010-03-26 21:24:24 +0800326 struct log_category *category;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800327 int output = 0;
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200328 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800329
330 category = &tar->categories[subsys];
Harald Welte3ae27582010-03-26 21:24:24 +0800331 /* subsystem is not supposed to be logged */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800332 if (!category->enabled)
333 continue;
334
335 /* Check the global log level */
336 if (tar->loglevel != 0 && level < tar->loglevel)
337 continue;
338
339 /* Check the category log level */
340 if (tar->loglevel == 0 && category->loglevel != 0 &&
341 level < category->loglevel)
342 continue;
343
344 /* Apply filters here... if that becomes messy we will
345 * need to put filters in a list and each filter will
346 * say stop, continue, output */
Harald Welte3ae27582010-03-26 21:24:24 +0800347 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800348 output = 1;
Harald Welte4ebdf742010-05-19 19:54:00 +0200349 else if (osmo_log_info->filter_fn)
350 output = osmo_log_info->filter_fn(&log_context,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800351 tar);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200352 if (!output)
353 continue;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800354
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200355 /* According to the manpage, vsnprintf leaves the value of ap
356 * in undefined state. Since _output uses vsnprintf and it may
357 * be called several times, we have to pass a copy of ap. */
358 va_copy(bp, ap);
Harald Welteda127cb2011-07-02 21:51:32 +0200359 _output(tar, subsys, level, file, line, cont, format, bp);
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200360 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800361 }
362}
363
Harald Weltede6e4982012-12-06 21:25:27 +0100364/*! \brief logging function used by DEBUGP() macro */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200365void logp(int subsys, const char *file, int line, int cont,
Harald Welte3ae27582010-03-26 21:24:24 +0800366 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800367{
368 va_list ap;
369
370 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200371 osmo_vlogp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800372 va_end(ap);
373}
374
Harald Weltede6e4982012-12-06 21:25:27 +0100375/*! \brief logging function used by LOGP() macro */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200376void logp2(int subsys, unsigned int level, const char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800377{
378 va_list ap;
379
380 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200381 osmo_vlogp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800382 va_end(ap);
383}
384
Harald Welte18fc4652011-08-17 14:14:17 +0200385/*! \brief Register a new log target with the logging core
386 * \param[in] target Log target to be registered
387 */
Harald Welte3ae27582010-03-26 21:24:24 +0800388void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800389{
Harald Welte28222962011-02-18 20:37:04 +0100390 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800391}
392
Harald Welte18fc4652011-08-17 14:14:17 +0200393/*! \brief Unregister a log target from the logging core
394 * \param[in] target Log target to be unregistered
395 */
Harald Welte3ae27582010-03-26 21:24:24 +0800396void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800397{
398 llist_del(&target->entry);
399}
400
Harald Welte18fc4652011-08-17 14:14:17 +0200401/*! \brief Reset (clear) the logging context */
Harald Welte3ae27582010-03-26 21:24:24 +0800402void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800403{
Harald Welte3ae27582010-03-26 21:24:24 +0800404 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800405}
406
Harald Welte18fc4652011-08-17 14:14:17 +0200407/*! \brief Set the logging context
408 * \param[in] ctx_nr logging context number
409 * \param[in] value value to which the context is to be set
410 *
411 * A logging context is something like the subscriber identity to which
412 * the currently processed message relates, or the BTS through which it
413 * was received. As soon as this data is known, it can be set using
414 * this function. The main use of context information is for logging
415 * filters.
416 */
Harald Welte3ae27582010-03-26 21:24:24 +0800417int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800418{
Harald Welte3ae27582010-03-26 21:24:24 +0800419 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800420 return -EINVAL;
421
Harald Welte3ae27582010-03-26 21:24:24 +0800422 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800423
424 return 0;
425}
426
Harald Welte18fc4652011-08-17 14:14:17 +0200427/*! \brief Enable the \ref LOG_FILTER_ALL log filter
428 * \param[in] target Log target to be affected
429 * \param[in] all enable (1) or disable (0) the ALL filter
430 *
431 * When the \ref LOG_FILTER_ALL filter is enabled, all log messages will
432 * be printed. It acts as a wildcard. Setting it to \a 1 means there
433 * is no filtering.
434 */
Harald Welte3ae27582010-03-26 21:24:24 +0800435void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800436{
437 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800438 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800439 else
Harald Welte3ae27582010-03-26 21:24:24 +0800440 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800441}
442
Harald Welte18fc4652011-08-17 14:14:17 +0200443/*! \brief Enable or disable the use of colored output
444 * \param[in] target Log target to be affected
445 * \param[in] use_color Use color (1) or don't use color (0)
446 */
Harald Welte3ae27582010-03-26 21:24:24 +0800447void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800448{
449 target->use_color = use_color;
450}
451
Harald Welte18fc4652011-08-17 14:14:17 +0200452/*! \brief Enable or disable printing of timestamps while logging
453 * \param[in] target Log target to be affected
454 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
455 */
Harald Welte3ae27582010-03-26 21:24:24 +0800456void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800457{
458 target->print_timestamp = print_timestamp;
459}
460
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100461/*! \brief Enable or disable printing of extended timestamps while logging
462 * \param[in] target Log target to be affected
463 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
464 *
465 * When both timestamp and extended timestamp is enabled then only
466 * the extended timestamp will be used. The format of the timestamp
467 * is YYYYMMDDhhmmssnnn.
468 */
469void log_set_print_extended_timestamp(struct log_target *target, int print_timestamp)
470{
471 target->print_ext_timestamp = print_timestamp;
472}
473
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200474/*! \brief Enable or disable printing of the filename while logging
475 * \param[in] target Log target to be affected
476 * \param[in] print_filename Enable (1) or disable (0) filenames
477 */
478void log_set_print_filename(struct log_target *target, int print_filename)
479{
480 target->print_filename = print_filename;
481}
482
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100483/*! \brief Enable or disable printing of the category name
484 * \param[in] target Log target to be affected
485 * \param[in] print_catname Enable (1) or disable (0) filenames
486 *
487 * Print the category/subsys name in front of every log message.
488 */
489void log_set_print_category(struct log_target *target, int print_category)
490{
491 target->print_category = print_category;
492}
493
Harald Welte18fc4652011-08-17 14:14:17 +0200494/*! \brief Set the global log level for a given log target
495 * \param[in] target Log target to be affected
496 * \param[in] log_level New global log level
497 */
Harald Welte3ae27582010-03-26 21:24:24 +0800498void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800499{
500 target->loglevel = log_level;
501}
502
Harald Weltede6e4982012-12-06 21:25:27 +0100503/*! \brief Set a category filter on a given log target
504 * \param[in] target Log target to be affected
505 * \param[in] category Log category to be affected
506 * \param[in] enable whether to enable or disable the filter
507 * \param[in] level Log level of the filter
508 */
Harald Welte3ae27582010-03-26 21:24:24 +0800509void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800510 int enable, int level)
511{
Harald Welte4ebdf742010-05-19 19:54:00 +0200512 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800513 return;
514 target->categories[category].enabled = !!enable;
515 target->categories[category].loglevel = level;
516}
517
Harald Welte76e72ab2011-02-17 15:52:39 +0100518static void _file_output(struct log_target *target, unsigned int level,
519 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800520{
Harald Welte0083cd32010-08-25 14:55:44 +0200521 fprintf(target->tgt_file.out, "%s", log);
522 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800523}
524
Harald Welte18fc4652011-08-17 14:14:17 +0200525/*! \brief Create a new log target skeleton */
Harald Welte3ae27582010-03-26 21:24:24 +0800526struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800527{
Harald Welte3ae27582010-03-26 21:24:24 +0800528 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800529 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800530
Harald Welte3ae27582010-03-26 21:24:24 +0800531 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800532 if (!target)
533 return NULL;
534
Harald Welteb43bc042011-06-27 10:29:17 +0200535 target->categories = talloc_zero_array(target,
536 struct log_category,
537 osmo_log_info->num_cat);
538 if (!target->categories) {
539 talloc_free(target);
540 return NULL;
541 }
542
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800543 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800544
545 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200546 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800547 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200548 cat->enabled = osmo_log_info->cat[i].enabled;
549 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800550 }
551
552 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800553 target->use_color = 1;
554 target->print_timestamp = 0;
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200555 target->print_filename = 1;
Harald Weltecc6313c2010-03-26 22:04:03 +0800556
557 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800558 target->loglevel = 0;
559 return target;
560}
561
Harald Welte18fc4652011-08-17 14:14:17 +0200562/*! \brief Create the STDERR log target */
Harald Welte3ae27582010-03-26 21:24:24 +0800563struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800564{
Harald Weltea3b844c2010-03-27 00:04:40 +0800565/* since C89/C99 says stderr is a macro, we can safely do this! */
566#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800567 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800568
Harald Welte3ae27582010-03-26 21:24:24 +0800569 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800570 if (!target)
571 return NULL;
572
Harald Welte28222962011-02-18 20:37:04 +0100573 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200574 target->tgt_file.out = stderr;
575 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800576 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800577#else
578 return NULL;
579#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800580}
581
Harald Welte18fc4652011-08-17 14:14:17 +0200582/*! \brief Create a new file-based log target
583 * \param[in] fname File name of the new log file
584 * \returns Log target in case of success, NULL otherwise
585 */
Harald Welte3086c392010-08-25 19:10:50 +0200586struct log_target *log_target_create_file(const char *fname)
587{
588 struct log_target *target;
589
590 target = log_target_create();
591 if (!target)
592 return NULL;
593
Harald Welte28222962011-02-18 20:37:04 +0100594 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200595 target->tgt_file.out = fopen(fname, "a");
596 if (!target->tgt_file.out)
597 return NULL;
598
599 target->output = _file_output;
600
601 target->tgt_file.fname = talloc_strdup(target, fname);
602
603 return target;
604}
605
Harald Welte18fc4652011-08-17 14:14:17 +0200606/*! \brief Find a registered log target
607 * \param[in] type Log target type
608 * \param[in] fname File name
609 * \returns Log target (if found), NULL otherwise
610 */
Harald Welte28222962011-02-18 20:37:04 +0100611struct log_target *log_target_find(int type, const char *fname)
612{
613 struct log_target *tgt;
614
615 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
616 if (tgt->type != type)
617 continue;
618 if (tgt->type == LOG_TGT_TYPE_FILE) {
619 if (!strcmp(fname, tgt->tgt_file.fname))
620 return tgt;
621 } else
622 return tgt;
623 }
624 return NULL;
625}
626
Harald Welte18fc4652011-08-17 14:14:17 +0200627/*! \brief Unregister, close and delete a log target */
Harald Welte3086c392010-08-25 19:10:50 +0200628void log_target_destroy(struct log_target *target)
629{
630
631 /* just in case, to make sure we don't have any references */
632 log_del_target(target);
633
634 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200635/* since C89/C99 says stderr is a macro, we can safely do this! */
636#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200637 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200638 if (target->tgt_file.out != stderr)
639#endif
640 {
Harald Welte3086c392010-08-25 19:10:50 +0200641 fclose(target->tgt_file.out);
642 target->tgt_file.out = NULL;
643 }
644 }
645
646 talloc_free(target);
647}
648
Harald Welte18fc4652011-08-17 14:14:17 +0200649/*! \brief close and re-open a log file (for log file rotation) */
Harald Welte3086c392010-08-25 19:10:50 +0200650int log_target_file_reopen(struct log_target *target)
651{
652 fclose(target->tgt_file.out);
653
654 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
655 if (!target->tgt_file.out)
656 return -errno;
657
658 /* we assume target->output already to be set */
659
660 return 0;
661}
662
Harald Welte4de854d2013-03-18 19:01:40 +0100663/*! \brief close and re-open a log file (for log file rotation) */
664int log_targets_reopen(void)
665{
666 struct log_target *tar;
667 int rc = 0;
668
669 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
670 switch (tar->type) {
671 case LOG_TGT_TYPE_FILE:
672 if (log_target_file_reopen(tar) < 0)
673 rc = -1;
674 break;
675 default:
676 break;
677 }
678 }
679
680 return rc;
681}
682
Harald Welte18fc4652011-08-17 14:14:17 +0200683/*! \brief Generates the logging command string for VTY
684 * \param[in] unused_info Deprecated parameter, no longer used!
685 */
Harald Weltece9fec32011-06-27 14:19:16 +0200686const char *log_vty_command_string(const struct log_info *unused_info)
Harald Welte7638af92010-05-11 16:39:22 +0200687{
Harald Weltece9fec32011-06-27 14:19:16 +0200688 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100689 int len = 0, offset = 0, ret, i, rem;
690 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200691 char *str;
692
Harald Welteb43bc042011-06-27 10:29:17 +0200693 for (i = 0; i < info->num_cat; i++) {
694 if (info->cat[i].name == NULL)
695 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100696 size += strlen(info->cat[i].name) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200697 }
Harald Welte7638af92010-05-11 16:39:22 +0200698
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100699 for (i = 0; i < LOGLEVEL_DEFS; i++)
700 size += strlen(loglevel_strs[i].str) + 1;
701
702 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200703 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200704 if (!str)
705 return NULL;
706
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200707 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100708 if (ret < 0)
709 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200710 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200711
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100712 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200713 if (info->cat[i].name) {
714 int j, name_len = strlen(info->cat[i].name)+1;
715 char name[name_len];
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100716
Harald Welteb43bc042011-06-27 10:29:17 +0200717 for (j = 0; j < name_len; j++)
718 name[j] = tolower(info->cat[i].name[j]);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100719
Harald Welteb43bc042011-06-27 10:29:17 +0200720 name[name_len-1] = '\0';
721 ret = snprintf(str + offset, rem, "%s|", name+1);
722 if (ret < 0)
723 goto err;
724 OSMO_SNPRINTF_RET(ret, rem, offset, len);
725 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100726 }
727 offset--; /* to remove the trailing | */
728 rem++;
729
730 ret = snprintf(str + offset, rem, ") (");
731 if (ret < 0)
732 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200733 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100734
735 for (i = 0; i < LOGLEVEL_DEFS; i++) {
736 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
737 char loglevel_str[loglevel_str_len];
738
739 for (j = 0; j < loglevel_str_len; j++)
740 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
741
742 loglevel_str[loglevel_str_len-1] = '\0';
743 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
744 if (ret < 0)
745 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200746 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100747 }
748 offset--; /* to remove the trailing | */
749 rem++;
750
751 ret = snprintf(str + offset, rem, ")");
752 if (ret < 0)
753 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200754 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100755err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200756 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100757 return str;
758}
759
Harald Welte18fc4652011-08-17 14:14:17 +0200760/*! \brief Generates the logging command description for VTY
761 * \param[in] unused_info Deprecated parameter, no longer used!
762 */
Harald Weltece9fec32011-06-27 14:19:16 +0200763const char *log_vty_command_description(const struct log_info *unused_info)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100764{
Harald Weltece9fec32011-06-27 14:19:16 +0200765 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100766 char *str;
767 int i, ret, len = 0, offset = 0, rem;
768 unsigned int size =
769 strlen(LOGGING_STR
770 "Set the log level for a specified category\n") + 1;
771
Harald Welteb43bc042011-06-27 10:29:17 +0200772 for (i = 0; i < info->num_cat; i++) {
773 if (info->cat[i].name == NULL)
774 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100775 size += strlen(info->cat[i].description) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200776 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100777
778 for (i = 0; i < LOGLEVEL_DEFS; i++)
779 size += strlen(loglevel_descriptions[i]) + 1;
780
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200781 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100782 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200783 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100784 if (!str)
785 return NULL;
786
787 ret = snprintf(str + offset, rem, LOGGING_STR
788 "Set the log level for a specified category\n");
789 if (ret < 0)
790 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200791 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100792
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200793 ret = snprintf(str + offset, rem,
794 "Global setting for all subsystems\n");
795 if (ret < 0)
796 goto err;
797 OSMO_SNPRINTF_RET(ret, rem, offset, len);
798
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100799 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200800 if (info->cat[i].name == NULL)
801 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100802 ret = snprintf(str + offset, rem, "%s\n",
803 info->cat[i].description);
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 }
808 for (i = 0; i < LOGLEVEL_DEFS; i++) {
809 ret = snprintf(str + offset, rem, "%s\n",
810 loglevel_descriptions[i]);
811 if (ret < 0)
812 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200813 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100814 }
815err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200816 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200817 return str;
818}
819
Harald Welte18fc4652011-08-17 14:14:17 +0200820/*! \brief Initialize the Osmocom logging core
821 * \param[in] inf Information regarding logging categories
822 * \param[in] ctx \ref talloc context for logging allocations
823 * \returns 0 in case of success, negative in case of error
824 */
Harald Welteb43bc042011-06-27 10:29:17 +0200825int log_init(const struct log_info *inf, void *ctx)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800826{
Harald Welteb43bc042011-06-27 10:29:17 +0200827 int i;
828
829 tall_log_ctx = talloc_named_const(ctx, 1, "logging");
830 if (!tall_log_ctx)
831 return -ENOMEM;
832
833 osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
834 if (!osmo_log_info)
835 return -ENOMEM;
836
Holger Hans Peter Freytherb7d0f462013-12-29 19:38:01 +0100837 osmo_log_info->filter_fn = inf->filter_fn;
Harald Welteb43bc042011-06-27 10:29:17 +0200838 osmo_log_info->num_cat_user = inf->num_cat;
839 /* total number = number of user cat + library cat */
Harald Weltece9fec32011-06-27 14:19:16 +0200840 osmo_log_info->num_cat = inf->num_cat + ARRAY_SIZE(internal_cat);
Harald Welteb43bc042011-06-27 10:29:17 +0200841
842 osmo_log_info->cat = talloc_zero_array(osmo_log_info,
843 struct log_info_cat,
844 osmo_log_info->num_cat);
845 if (!osmo_log_info->cat) {
846 talloc_free(osmo_log_info);
847 osmo_log_info = NULL;
848 return -ENOMEM;
849 }
850
851 /* copy over the user part */
852 for (i = 0; i < inf->num_cat; i++) {
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200853 memcpy((struct log_info_cat *) &osmo_log_info->cat[i],
854 &inf->cat[i],
Harald Welteb43bc042011-06-27 10:29:17 +0200855 sizeof(struct log_info_cat));
856 }
857
858 /* copy over the library part */
Harald Welte9fe16522011-06-27 14:00:03 +0200859 for (i = 0; i < ARRAY_SIZE(internal_cat); i++) {
Harald Weltece9fec32011-06-27 14:19:16 +0200860 unsigned int cn = osmo_log_info->num_cat_user + i;
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200861 memcpy((struct log_info_cat *) &osmo_log_info->cat[cn],
Harald Welte9fe16522011-06-27 14:00:03 +0200862 &internal_cat[i], sizeof(struct log_info_cat));
863 }
864
865 return 0;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800866}
Harald Welte18fc4652011-08-17 14:14:17 +0200867
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100868/*! \brief Check whether a log entry will be generated.
869 * \returns != 0 if a log entry might get generated by at least one target */
870int log_check_level(int subsys, unsigned int level)
871{
872 struct log_target *tar;
873
874 if (subsys < 0)
875 subsys = subsys_lib2index(subsys);
876
877 if (subsys > osmo_log_info->num_cat)
878 subsys = DLGLOBAL;
879
880 /* TODO: The following could/should be cached (update on config) */
881
882 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
883 struct log_category *category;
884
885 category = &tar->categories[subsys];
886 /* subsystem is not supposed to be logged */
887 if (!category->enabled)
888 continue;
889
890 /* Check the global log level */
891 if (tar->loglevel != 0 && level < tar->loglevel)
892 continue;
893
894 /* Check the category log level */
895 if (tar->loglevel == 0 && category->loglevel != 0 &&
896 level < category->loglevel)
897 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/*! @} */