blob: b2f8d437a11ebee087b974bdb7438ac7ceaddf55 [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 Welte2d2e2cc2016-04-25 12:11:20 +0200145/*! \brief Parse a human-readable log level into a numeric value
146 * \param lvl[in] zero-terminated string containing log level name
147 * \returns numeric log level
148 */
Harald Welte3ae27582010-03-26 21:24:24 +0800149int log_parse_level(const char *lvl)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800150{
151 return get_string_value(loglevel_strs, lvl);
152}
153
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200154/*! \brief convert a numeric log level into human-readable string
155 * \param lvl[in] numeric log level
156 * \returns zero-terminated string (log level name)
157 */
Harald Welte9ac22252010-05-11 11:19:40 +0200158const char *log_level_str(unsigned int lvl)
159{
160 return get_value_string(loglevel_strs, lvl);
161}
162
Harald Welte18fc4652011-08-17 14:14:17 +0200163/*! \brief parse a human-readable log category into numeric form
164 * \param[in] category human-readable log category name
165 * \returns numeric category value, or -EINVAL otherwise
166 */
Harald Welte3ae27582010-03-26 21:24:24 +0800167int log_parse_category(const char *category)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800168{
169 int i;
170
Harald Welte4ebdf742010-05-19 19:54:00 +0200171 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welteb43bc042011-06-27 10:29:17 +0200172 if (osmo_log_info->cat[i].name == NULL)
173 continue;
Harald Welte4ebdf742010-05-19 19:54:00 +0200174 if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
Harald Weltefaadfe22010-03-26 21:05:43 +0800175 return i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800176 }
177
178 return -EINVAL;
179}
180
Harald Welte18fc4652011-08-17 14:14:17 +0200181/*! \brief parse the log category mask
182 * \param[in] target log target to be configured
183 * \param[in] _mask log category mask string
184 *
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800185 * The format can be this: category1:category2:category3
186 * or category1,2:category2,3:...
187 */
Harald Welte3ae27582010-03-26 21:24:24 +0800188void log_parse_category_mask(struct log_target* target, const char *_mask)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800189{
190 int i = 0;
191 char *mask = strdup(_mask);
192 char *category_token = NULL;
193
194 /* Disable everything to enable it afterwards */
Harald Welteb43bc042011-06-27 10:29:17 +0200195 for (i = 0; i < osmo_log_info->num_cat; ++i)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800196 target->categories[i].enabled = 0;
197
198 category_token = strtok(mask, ":");
Neels Hofmeyrda1b20c2016-04-14 15:12:16 +0200199 OSMO_ASSERT(category_token);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800200 do {
Harald Welte4ebdf742010-05-19 19:54:00 +0200201 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Nico Golde0262d3f2012-09-21 17:44:58 +0200202 size_t length, cat_length;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800203 char* colon = strstr(category_token, ",");
Nico Golde0262d3f2012-09-21 17:44:58 +0200204
205 if (!osmo_log_info->cat[i].name)
206 continue;
207
208 length = strlen(category_token);
209 cat_length = strlen(osmo_log_info->cat[i].name);
Pablo Neira Ayuso300e78d2011-08-11 13:24:18 +0200210
211 /* Use longest length not to match subocurrences. */
212 if (cat_length > length)
213 length = cat_length;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800214
215 if (colon)
216 length = colon - category_token;
217
Harald Welte4ebdf742010-05-19 19:54:00 +0200218 if (strncasecmp(osmo_log_info->cat[i].name,
219 category_token, length) == 0) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800220 int level = 0;
221
222 if (colon)
223 level = atoi(colon+1);
224
Harald Weltefaadfe22010-03-26 21:05:43 +0800225 target->categories[i].enabled = 1;
226 target->categories[i].loglevel = level;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800227 }
228 }
229 } while ((category_token = strtok(NULL, ":")));
230
231 free(mask);
232}
233
234static const char* color(int subsys)
235{
Harald Welte4ebdf742010-05-19 19:54:00 +0200236 if (subsys < osmo_log_info->num_cat)
237 return osmo_log_info->cat[subsys].color;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800238
Harald Welted788f662010-03-26 09:45:03 +0800239 return NULL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800240}
241
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100242static const char* category_name(int subsys)
243{
244 if (subsys < osmo_log_info->num_cat)
245 return osmo_log_info->cat[subsys].name;
246
247 return NULL;
248}
249
Harald Welte3ae27582010-03-26 21:24:24 +0800250static void _output(struct log_target *target, unsigned int subsys,
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200251 unsigned int level, const char *file, int line, int cont,
Harald Welte76e72ab2011-02-17 15:52:39 +0100252 const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800253{
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800254 char buf[4096];
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200255 int ret, len = 0, offset = 0, rem = sizeof(buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800256
257 /* are we using color */
258 if (target->use_color) {
Harald Welted788f662010-03-26 09:45:03 +0800259 const char *c = color(subsys);
260 if (c) {
Holger Hans Peter Freyther5f91a402014-12-05 10:29:45 +0100261 ret = snprintf(buf + offset, rem, "%s", c);
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200262 if (ret < 0)
263 goto err;
264 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welted788f662010-03-26 09:45:03 +0800265 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800266 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800267 if (!cont) {
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100268 if (target->print_ext_timestamp) {
269 struct tm tm;
Jacob Erlbeckb61b2ca2015-03-17 10:21:15 +0100270 struct timeval tv;
271 gettimeofday(&tv, NULL);
272 localtime_r(&tv.tv_sec, &tm);
273 ret = snprintf(buf + offset, rem, "%04d%02d%02d%02d%02d%02d%03d ",
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100274 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
Jacob Erlbeckb61b2ca2015-03-17 10:21:15 +0100275 tm.tm_hour, tm.tm_min, tm.tm_sec,
276 (int)(tv.tv_usec / 1000));
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100277 if (ret < 0)
278 goto err;
279 OSMO_SNPRINTF_RET(ret, rem, offset, len);
280 } else if (target->print_timestamp) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800281 char *timestr;
282 time_t tm;
283 tm = time(NULL);
284 timestr = ctime(&tm);
285 timestr[strlen(timestr)-1] = '\0';
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200286 ret = snprintf(buf + offset, rem, "%s ", timestr);
287 if (ret < 0)
288 goto err;
289 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800290 }
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100291 if (target->print_category) {
292 ret = snprintf(buf + offset, rem, "%s ", category_name(subsys));
293 if (ret < 0)
294 goto err;
295 OSMO_SNPRINTF_RET(ret, rem, offset, len);
296 }
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200297 if (target->print_filename) {
298 ret = snprintf(buf + offset, rem, "<%4.4x> %s:%d ",
299 subsys, file, line);
300 if (ret < 0)
301 goto err;
302 OSMO_SNPRINTF_RET(ret, rem, offset, len);
303 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800304 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200305 ret = vsnprintf(buf + offset, rem, format, ap);
306 if (ret < 0)
307 goto err;
308 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800309
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200310 ret = snprintf(buf + offset, rem, "%s",
311 target->use_color ? "\033[0;m" : "");
312 if (ret < 0)
313 goto err;
314 OSMO_SNPRINTF_RET(ret, rem, offset, len);
315err:
316 buf[sizeof(buf)-1] = '\0';
317 target->output(target, level, buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800318}
319
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100320static inline int map_subsys(int subsys)
321{
322 if (subsys < 0)
323 subsys = subsys_lib2index(subsys);
324
325 if (subsys > osmo_log_info->num_cat)
326 subsys = DLGLOBAL;
327 return subsys;
328}
329
330static inline int check_log_to_target(struct log_target *tar, int subsys, int level)
331{
332 struct log_category *category;
333
334 category = &tar->categories[subsys];
335
336 /* subsystem is not supposed to be logged */
337 if (!category->enabled)
338 return 0;
339
340 /* Check the global log level */
341 if (tar->loglevel != 0 && level < tar->loglevel)
342 return 0;
343
344 /* Check the category log level */
345 if (tar->loglevel == 0 && category->loglevel != 0 &&
346 level < category->loglevel)
347 return 0;
348
Holger Hans Peter Freyther79599ac2016-01-15 16:49:06 +0100349 /* Apply filters here... if that becomes messy we will
350 * need to put filters in a list and each filter will
351 * say stop, continue, output */
352 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
353 return 1;
354
355 if (osmo_log_info->filter_fn)
356 return osmo_log_info->filter_fn(&log_context, tar);
357
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100358 /* TODO: Check the filter/selector too? */
359 return 1;
360}
361
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200362/*! \brief vararg version of logging function
363 * \param[in] subsys Logging sub-system
364 * \param[in] level Log level
365 * \param[in] file name of source code file
366 * \param[in] cont continuation (1) or new line (0)
367 * \param[in] format format string
368 * \param[in] ap vararg-list containing format string arguments
369 */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200370void osmo_vlogp(int subsys, int level, const char *file, int line,
Harald Welte36c5a3e2011-08-27 14:33:19 +0200371 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800372{
Harald Welte3ae27582010-03-26 21:24:24 +0800373 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800374
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100375 subsys = map_subsys(subsys);
Harald Welteb43bc042011-06-27 10:29:17 +0200376
Harald Welte28222962011-02-18 20:37:04 +0100377 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200378 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800379
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100380 if (!check_log_to_target(tar, subsys, level))
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800381 continue;
382
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200383 /* According to the manpage, vsnprintf leaves the value of ap
384 * in undefined state. Since _output uses vsnprintf and it may
385 * be called several times, we have to pass a copy of ap. */
386 va_copy(bp, ap);
Harald Welteda127cb2011-07-02 21:51:32 +0200387 _output(tar, subsys, level, file, line, cont, format, bp);
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200388 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800389 }
390}
391
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200392/*! \brief logging function used by DEBUGP() macro
393 * \param[in] subsys Logging sub-system
394 * \param[in] file name of source code file
395 * \param[in] cont continuation (1) or new line (0)
396 * \param[in] format format string
397 */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200398void logp(int subsys, const char *file, int line, int cont,
Harald Welte3ae27582010-03-26 21:24:24 +0800399 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800400{
401 va_list ap;
402
403 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200404 osmo_vlogp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800405 va_end(ap);
406}
407
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200408/*! \brief logging function used by LOGP() macro
409 * \param[in] subsys Logging sub-system
410 * \param[in] level Log level
411 * \param[in] file name of source code file
412 * \param[in] cont continuation (1) or new line (0)
413 * \param[in] format format string
414 */
Holger Hans Peter Freytherfb4bfc22012-07-12 09:26:25 +0200415void logp2(int subsys, unsigned int level, const char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800416{
417 va_list ap;
418
419 va_start(ap, format);
Harald Welte36c5a3e2011-08-27 14:33:19 +0200420 osmo_vlogp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800421 va_end(ap);
422}
423
Harald Welte18fc4652011-08-17 14:14:17 +0200424/*! \brief Register a new log target with the logging core
425 * \param[in] target Log target to be registered
426 */
Harald Welte3ae27582010-03-26 21:24:24 +0800427void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800428{
Harald Welte28222962011-02-18 20:37:04 +0100429 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800430}
431
Harald Welte18fc4652011-08-17 14:14:17 +0200432/*! \brief Unregister a log target from the logging core
433 * \param[in] target Log target to be unregistered
434 */
Harald Welte3ae27582010-03-26 21:24:24 +0800435void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800436{
437 llist_del(&target->entry);
438}
439
Harald Welte18fc4652011-08-17 14:14:17 +0200440/*! \brief Reset (clear) the logging context */
Harald Welte3ae27582010-03-26 21:24:24 +0800441void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800442{
Harald Welte3ae27582010-03-26 21:24:24 +0800443 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800444}
445
Harald Welte18fc4652011-08-17 14:14:17 +0200446/*! \brief Set the logging context
447 * \param[in] ctx_nr logging context number
448 * \param[in] value value to which the context is to be set
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200449 * \returns 0 in case of success; negative otherwise
Harald Welte18fc4652011-08-17 14:14:17 +0200450 *
451 * A logging context is something like the subscriber identity to which
452 * the currently processed message relates, or the BTS through which it
453 * was received. As soon as this data is known, it can be set using
454 * this function. The main use of context information is for logging
455 * filters.
456 */
Harald Welte3ae27582010-03-26 21:24:24 +0800457int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800458{
Harald Welte3ae27582010-03-26 21:24:24 +0800459 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800460 return -EINVAL;
461
Harald Welte3ae27582010-03-26 21:24:24 +0800462 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800463
464 return 0;
465}
466
Harald Welte18fc4652011-08-17 14:14:17 +0200467/*! \brief Enable the \ref LOG_FILTER_ALL log filter
468 * \param[in] target Log target to be affected
469 * \param[in] all enable (1) or disable (0) the ALL filter
470 *
471 * When the \ref LOG_FILTER_ALL filter is enabled, all log messages will
472 * be printed. It acts as a wildcard. Setting it to \a 1 means there
473 * is no filtering.
474 */
Harald Welte3ae27582010-03-26 21:24:24 +0800475void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800476{
477 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800478 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800479 else
Harald Welte3ae27582010-03-26 21:24:24 +0800480 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800481}
482
Harald Welte18fc4652011-08-17 14:14:17 +0200483/*! \brief Enable or disable the use of colored output
484 * \param[in] target Log target to be affected
485 * \param[in] use_color Use color (1) or don't use color (0)
486 */
Harald Welte3ae27582010-03-26 21:24:24 +0800487void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800488{
489 target->use_color = use_color;
490}
491
Harald Welte18fc4652011-08-17 14:14:17 +0200492/*! \brief Enable or disable printing of timestamps while logging
493 * \param[in] target Log target to be affected
494 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
495 */
Harald Welte3ae27582010-03-26 21:24:24 +0800496void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800497{
498 target->print_timestamp = print_timestamp;
499}
500
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100501/*! \brief Enable or disable printing of extended timestamps while logging
502 * \param[in] target Log target to be affected
503 * \param[in] print_timestamp Enable (1) or disable (0) timestamps
504 *
505 * When both timestamp and extended timestamp is enabled then only
506 * the extended timestamp will be used. The format of the timestamp
507 * is YYYYMMDDhhmmssnnn.
508 */
509void log_set_print_extended_timestamp(struct log_target *target, int print_timestamp)
510{
511 target->print_ext_timestamp = print_timestamp;
512}
513
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200514/*! \brief Enable or disable printing of the filename while logging
515 * \param[in] target Log target to be affected
516 * \param[in] print_filename Enable (1) or disable (0) filenames
517 */
518void log_set_print_filename(struct log_target *target, int print_filename)
519{
520 target->print_filename = print_filename;
521}
522
Holger Hans Peter Freyther2d6ad132014-12-05 09:35:30 +0100523/*! \brief Enable or disable printing of the category name
524 * \param[in] target Log target to be affected
525 * \param[in] print_catname Enable (1) or disable (0) filenames
526 *
527 * Print the category/subsys name in front of every log message.
528 */
529void log_set_print_category(struct log_target *target, int print_category)
530{
531 target->print_category = print_category;
532}
533
Harald Welte18fc4652011-08-17 14:14:17 +0200534/*! \brief Set the global log level for a given log target
535 * \param[in] target Log target to be affected
536 * \param[in] log_level New global log level
537 */
Harald Welte3ae27582010-03-26 21:24:24 +0800538void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800539{
540 target->loglevel = log_level;
541}
542
Harald Weltede6e4982012-12-06 21:25:27 +0100543/*! \brief Set a category filter on a given log target
544 * \param[in] target Log target to be affected
545 * \param[in] category Log category to be affected
546 * \param[in] enable whether to enable or disable the filter
547 * \param[in] level Log level of the filter
548 */
Harald Welte3ae27582010-03-26 21:24:24 +0800549void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800550 int enable, int level)
551{
Harald Welte4ebdf742010-05-19 19:54:00 +0200552 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800553 return;
554 target->categories[category].enabled = !!enable;
555 target->categories[category].loglevel = level;
556}
557
Harald Welte76e72ab2011-02-17 15:52:39 +0100558static void _file_output(struct log_target *target, unsigned int level,
559 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800560{
Harald Welte0083cd32010-08-25 14:55:44 +0200561 fprintf(target->tgt_file.out, "%s", log);
562 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800563}
564
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200565/*! \brief Create a new log target skeleton
566 * \returns dynamically-allocated log target
567 * This funcition allocates a \ref log_target and initializes it
568 * with some default values. The newly created target is not
569 * registered yet.
570 */
Harald Welte3ae27582010-03-26 21:24:24 +0800571struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800572{
Harald Welte3ae27582010-03-26 21:24:24 +0800573 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800574 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800575
Harald Welte3ae27582010-03-26 21:24:24 +0800576 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800577 if (!target)
578 return NULL;
579
Harald Welteb43bc042011-06-27 10:29:17 +0200580 target->categories = talloc_zero_array(target,
581 struct log_category,
582 osmo_log_info->num_cat);
583 if (!target->categories) {
584 talloc_free(target);
585 return NULL;
586 }
587
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800588 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800589
590 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200591 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800592 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200593 cat->enabled = osmo_log_info->cat[i].enabled;
594 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800595 }
596
597 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800598 target->use_color = 1;
599 target->print_timestamp = 0;
Holger Hans Peter Freytherdb153362012-09-11 11:24:51 +0200600 target->print_filename = 1;
Harald Weltecc6313c2010-03-26 22:04:03 +0800601
602 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800603 target->loglevel = 0;
604 return target;
605}
606
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200607/*! \brief Create the STDERR log target
608 * \returns dynamically-allocated \ref log_target for STDERR */
Harald Welte3ae27582010-03-26 21:24:24 +0800609struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800610{
Harald Weltea3b844c2010-03-27 00:04:40 +0800611/* since C89/C99 says stderr is a macro, we can safely do this! */
612#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800613 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800614
Harald Welte3ae27582010-03-26 21:24:24 +0800615 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800616 if (!target)
617 return NULL;
618
Harald Welte28222962011-02-18 20:37:04 +0100619 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200620 target->tgt_file.out = stderr;
621 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800622 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800623#else
624 return NULL;
625#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800626}
627
Harald Welte18fc4652011-08-17 14:14:17 +0200628/*! \brief Create a new file-based log target
629 * \param[in] fname File name of the new log file
630 * \returns Log target in case of success, NULL otherwise
631 */
Harald Welte3086c392010-08-25 19:10:50 +0200632struct log_target *log_target_create_file(const char *fname)
633{
634 struct log_target *target;
635
636 target = log_target_create();
637 if (!target)
638 return NULL;
639
Harald Welte28222962011-02-18 20:37:04 +0100640 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200641 target->tgt_file.out = fopen(fname, "a");
642 if (!target->tgt_file.out)
643 return NULL;
644
645 target->output = _file_output;
646
647 target->tgt_file.fname = talloc_strdup(target, fname);
648
649 return target;
650}
651
Harald Welte18fc4652011-08-17 14:14:17 +0200652/*! \brief Find a registered log target
653 * \param[in] type Log target type
654 * \param[in] fname File name
655 * \returns Log target (if found), NULL otherwise
656 */
Harald Welte28222962011-02-18 20:37:04 +0100657struct log_target *log_target_find(int type, const char *fname)
658{
659 struct log_target *tgt;
660
661 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
662 if (tgt->type != type)
663 continue;
664 if (tgt->type == LOG_TGT_TYPE_FILE) {
665 if (!strcmp(fname, tgt->tgt_file.fname))
666 return tgt;
667 } else
668 return tgt;
669 }
670 return NULL;
671}
672
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200673/*! \brief Unregister, close and delete a log target
674 * \param target[in] log target to unregister, close and delete */
Harald Welte3086c392010-08-25 19:10:50 +0200675void log_target_destroy(struct log_target *target)
676{
677
678 /* just in case, to make sure we don't have any references */
679 log_del_target(target);
680
681 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200682/* since C89/C99 says stderr is a macro, we can safely do this! */
683#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200684 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200685 if (target->tgt_file.out != stderr)
686#endif
687 {
Harald Welte3086c392010-08-25 19:10:50 +0200688 fclose(target->tgt_file.out);
689 target->tgt_file.out = NULL;
690 }
691 }
692
693 talloc_free(target);
694}
695
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200696/*! \brief close and re-open a log file (for log file rotation)
697 * \param[in] target log target to re-open
698 * \returns 0 in case of success; negative otherwise */
Harald Welte3086c392010-08-25 19:10:50 +0200699int log_target_file_reopen(struct log_target *target)
700{
701 fclose(target->tgt_file.out);
702
703 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
704 if (!target->tgt_file.out)
705 return -errno;
706
707 /* we assume target->output already to be set */
708
709 return 0;
710}
711
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200712/*! \brief close and re-open all log files (for log file rotation)
713 * \returns 0 in case of success; negative otherwise */
Harald Welte4de854d2013-03-18 19:01:40 +0100714int log_targets_reopen(void)
715{
716 struct log_target *tar;
717 int rc = 0;
718
719 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
720 switch (tar->type) {
721 case LOG_TGT_TYPE_FILE:
722 if (log_target_file_reopen(tar) < 0)
723 rc = -1;
724 break;
725 default:
726 break;
727 }
728 }
729
730 return rc;
731}
732
Harald Welte18fc4652011-08-17 14:14:17 +0200733/*! \brief Generates the logging command string for VTY
734 * \param[in] unused_info Deprecated parameter, no longer used!
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200735 * \returns vty command string for use by VTY command node
Harald Welte18fc4652011-08-17 14:14:17 +0200736 */
Harald Weltece9fec32011-06-27 14:19:16 +0200737const char *log_vty_command_string(const struct log_info *unused_info)
Harald Welte7638af92010-05-11 16:39:22 +0200738{
Harald Weltece9fec32011-06-27 14:19:16 +0200739 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100740 int len = 0, offset = 0, ret, i, rem;
741 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200742 char *str;
743
Harald Welteb43bc042011-06-27 10:29:17 +0200744 for (i = 0; i < info->num_cat; i++) {
745 if (info->cat[i].name == NULL)
746 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100747 size += strlen(info->cat[i].name) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200748 }
Harald Welte7638af92010-05-11 16:39:22 +0200749
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100750 for (i = 0; i < LOGLEVEL_DEFS; i++)
751 size += strlen(loglevel_strs[i].str) + 1;
752
753 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200754 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200755 if (!str)
756 return NULL;
757
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200758 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100759 if (ret < 0)
760 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200761 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200762
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100763 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200764 if (info->cat[i].name) {
765 int j, name_len = strlen(info->cat[i].name)+1;
766 char name[name_len];
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100767
Harald Welteb43bc042011-06-27 10:29:17 +0200768 for (j = 0; j < name_len; j++)
769 name[j] = tolower(info->cat[i].name[j]);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100770
Harald Welteb43bc042011-06-27 10:29:17 +0200771 name[name_len-1] = '\0';
772 ret = snprintf(str + offset, rem, "%s|", name+1);
773 if (ret < 0)
774 goto err;
775 OSMO_SNPRINTF_RET(ret, rem, offset, len);
776 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100777 }
778 offset--; /* to remove the trailing | */
779 rem++;
780
781 ret = snprintf(str + offset, rem, ") (");
782 if (ret < 0)
783 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200784 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100785
786 for (i = 0; i < LOGLEVEL_DEFS; i++) {
787 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
788 char loglevel_str[loglevel_str_len];
789
790 for (j = 0; j < loglevel_str_len; j++)
791 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
792
793 loglevel_str[loglevel_str_len-1] = '\0';
794 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
795 if (ret < 0)
796 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200797 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100798 }
799 offset--; /* to remove the trailing | */
800 rem++;
801
802 ret = snprintf(str + offset, rem, ")");
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 +0100806err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200807 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100808 return str;
809}
810
Harald Welte18fc4652011-08-17 14:14:17 +0200811/*! \brief Generates the logging command description for VTY
812 * \param[in] unused_info Deprecated parameter, no longer used!
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200813 * \returns logging command description for use by VTY command node
Harald Welte18fc4652011-08-17 14:14:17 +0200814 */
Harald Weltece9fec32011-06-27 14:19:16 +0200815const char *log_vty_command_description(const struct log_info *unused_info)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100816{
Harald Weltece9fec32011-06-27 14:19:16 +0200817 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100818 char *str;
819 int i, ret, len = 0, offset = 0, rem;
820 unsigned int size =
821 strlen(LOGGING_STR
822 "Set the log level for a specified category\n") + 1;
823
Harald Welteb43bc042011-06-27 10:29:17 +0200824 for (i = 0; i < info->num_cat; i++) {
825 if (info->cat[i].name == NULL)
826 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100827 size += strlen(info->cat[i].description) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200828 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100829
830 for (i = 0; i < LOGLEVEL_DEFS; i++)
831 size += strlen(loglevel_descriptions[i]) + 1;
832
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200833 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100834 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200835 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100836 if (!str)
837 return NULL;
838
839 ret = snprintf(str + offset, rem, LOGGING_STR
840 "Set the log level for a specified category\n");
841 if (ret < 0)
842 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200843 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100844
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200845 ret = snprintf(str + offset, rem,
846 "Global setting for all subsystems\n");
847 if (ret < 0)
848 goto err;
849 OSMO_SNPRINTF_RET(ret, rem, offset, len);
850
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100851 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200852 if (info->cat[i].name == NULL)
853 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100854 ret = snprintf(str + offset, rem, "%s\n",
855 info->cat[i].description);
856 if (ret < 0)
857 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200858 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100859 }
860 for (i = 0; i < LOGLEVEL_DEFS; i++) {
861 ret = snprintf(str + offset, rem, "%s\n",
862 loglevel_descriptions[i]);
863 if (ret < 0)
864 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200865 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100866 }
867err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200868 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200869 return str;
870}
871
Harald Welte18fc4652011-08-17 14:14:17 +0200872/*! \brief Initialize the Osmocom logging core
873 * \param[in] inf Information regarding logging categories
874 * \param[in] ctx \ref talloc context for logging allocations
875 * \returns 0 in case of success, negative in case of error
876 */
Harald Welteb43bc042011-06-27 10:29:17 +0200877int log_init(const struct log_info *inf, void *ctx)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800878{
Harald Welteb43bc042011-06-27 10:29:17 +0200879 int i;
880
881 tall_log_ctx = talloc_named_const(ctx, 1, "logging");
882 if (!tall_log_ctx)
883 return -ENOMEM;
884
885 osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
886 if (!osmo_log_info)
887 return -ENOMEM;
888
Holger Hans Peter Freytherb7d0f462013-12-29 19:38:01 +0100889 osmo_log_info->filter_fn = inf->filter_fn;
Harald Welteb43bc042011-06-27 10:29:17 +0200890 osmo_log_info->num_cat_user = inf->num_cat;
891 /* total number = number of user cat + library cat */
Harald Weltece9fec32011-06-27 14:19:16 +0200892 osmo_log_info->num_cat = inf->num_cat + ARRAY_SIZE(internal_cat);
Harald Welteb43bc042011-06-27 10:29:17 +0200893
894 osmo_log_info->cat = talloc_zero_array(osmo_log_info,
895 struct log_info_cat,
896 osmo_log_info->num_cat);
897 if (!osmo_log_info->cat) {
898 talloc_free(osmo_log_info);
899 osmo_log_info = NULL;
900 return -ENOMEM;
901 }
902
903 /* copy over the user part */
904 for (i = 0; i < inf->num_cat; i++) {
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200905 memcpy((struct log_info_cat *) &osmo_log_info->cat[i],
906 &inf->cat[i],
Harald Welteb43bc042011-06-27 10:29:17 +0200907 sizeof(struct log_info_cat));
908 }
909
910 /* copy over the library part */
Harald Welte9fe16522011-06-27 14:00:03 +0200911 for (i = 0; i < ARRAY_SIZE(internal_cat); i++) {
Harald Weltece9fec32011-06-27 14:19:16 +0200912 unsigned int cn = osmo_log_info->num_cat_user + i;
Holger Hans Peter Freyther06f64552012-09-11 10:31:29 +0200913 memcpy((struct log_info_cat *) &osmo_log_info->cat[cn],
Harald Welte9fe16522011-06-27 14:00:03 +0200914 &internal_cat[i], sizeof(struct log_info_cat));
915 }
916
917 return 0;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800918}
Harald Welte18fc4652011-08-17 14:14:17 +0200919
Harald Welte69e6c3c2016-04-20 10:41:27 +0200920/* \brief De-initialize the Osmocom logging core
921 * This function destroys all targets and releases associated memory */
922void log_fini(void)
923{
924 struct log_target *tar, *tar2;
925
926 llist_for_each_entry_safe(tar, tar2, &osmo_log_target_list, entry)
927 log_target_destroy(tar);
928
929 talloc_free(osmo_log_info);
930 osmo_log_info = NULL;
931 talloc_free(tall_log_ctx);
932 tall_log_ctx = NULL;
933}
934
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100935/*! \brief Check whether a log entry will be generated.
936 * \returns != 0 if a log entry might get generated by at least one target */
937int log_check_level(int subsys, unsigned int level)
938{
939 struct log_target *tar;
940
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100941 subsys = map_subsys(subsys);
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100942
943 /* TODO: The following could/should be cached (update on config) */
944
945 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Holger Hans Peter Freythere0dc6a12015-12-21 14:45:16 +0100946 if (!check_log_to_target(tar, subsys, level))
Jacob Erlbeckde6dd722015-11-17 11:52:24 +0100947 continue;
948
949 /* This might get logged (ignoring filters) */
950 return 1;
951 }
952
953 /* We are sure, that this will not be logged. */
954 return 0;
955}
956
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200957/*! @} */