blob: def13b3b9cf01806d4c002be6d4b9dc7ba86b8e9 [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 Welte01fd5cb2010-03-26 23:51:31 +080023#include "../config.h"
24
Harald Welte4a2bb9e2010-03-26 09:33:40 +080025#include <stdarg.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010029#include <ctype.h>
Harald Welte01fd5cb2010-03-26 23:51:31 +080030
31#ifdef HAVE_STRINGS_H
Harald Welte4a2bb9e2010-03-26 09:33:40 +080032#include <strings.h>
Harald Welte01fd5cb2010-03-26 23:51:31 +080033#endif
Harald Welte4a2bb9e2010-03-26 09:33:40 +080034#include <time.h>
35#include <errno.h>
36
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010037#include <osmocom/core/talloc.h>
38#include <osmocom/core/utils.h>
39#include <osmocom/core/logging.h>
Harald Welte4a2bb9e2010-03-26 09:33:40 +080040
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010041#include <osmocom/vty/logging.h> /* for LOGGING_STR. */
42
Harald Welteb43bc042011-06-27 10:29:17 +020043struct log_info *osmo_log_info;
Harald Welte4a2bb9e2010-03-26 09:33:40 +080044
Harald Welte3ae27582010-03-26 21:24:24 +080045static struct log_context log_context;
46static void *tall_log_ctx = NULL;
Harald Welte28222962011-02-18 20:37:04 +010047LLIST_HEAD(osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +080048
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010049#define LOGLEVEL_DEFS 6 /* Number of loglevels.*/
50
51static const struct value_string loglevel_strs[LOGLEVEL_DEFS+1] = {
Harald Welte4a2bb9e2010-03-26 09:33:40 +080052 { 0, "EVERYTHING" },
53 { LOGL_DEBUG, "DEBUG" },
54 { LOGL_INFO, "INFO" },
55 { LOGL_NOTICE, "NOTICE" },
56 { LOGL_ERROR, "ERROR" },
57 { LOGL_FATAL, "FATAL" },
58 { 0, NULL },
59};
60
Harald Welteb43bc042011-06-27 10:29:17 +020061#define INT2IDX(x) (-1*(x)-1)
62static const struct log_info_cat internal_cat[OSMO_NUM_DLIB] = {
63 [INT2IDX(DLGLOBAL)] = { /* -1 becomes 0 */
64 .name = "DLGLOBAL",
65 .description = "Library-internal global log family",
66 .loglevel = LOGL_NOTICE,
67 .enabled = 1,
68 },
69};
70
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010071/* You have to keep this in sync with the structure loglevel_strs. */
72const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
73 "Log simply everything",
74 "Log debug messages and higher levels",
75 "Log informational messages and higher levels",
76 "Log noticable messages and higher levels",
77 "Log error messages and higher levels",
78 "Log only fatal messages",
79 NULL,
80};
81
Harald Welteb43bc042011-06-27 10:29:17 +020082/* special magic for negative (library-internal) log subsystem numbers */
83static int subsys_lib2index(int subsys)
84{
85 return (subsys * -1) + (osmo_log_info->num_cat_user-1);
86}
87
Harald Welte3ae27582010-03-26 21:24:24 +080088int log_parse_level(const char *lvl)
Harald Welte4a2bb9e2010-03-26 09:33:40 +080089{
90 return get_string_value(loglevel_strs, lvl);
91}
92
Harald Welte9ac22252010-05-11 11:19:40 +020093const char *log_level_str(unsigned int lvl)
94{
95 return get_value_string(loglevel_strs, lvl);
96}
97
Harald Welte3ae27582010-03-26 21:24:24 +080098int log_parse_category(const char *category)
Harald Welte4a2bb9e2010-03-26 09:33:40 +080099{
100 int i;
101
Harald Welte4ebdf742010-05-19 19:54:00 +0200102 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welteb43bc042011-06-27 10:29:17 +0200103 if (osmo_log_info->cat[i].name == NULL)
104 continue;
Harald Welte4ebdf742010-05-19 19:54:00 +0200105 if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
Harald Weltefaadfe22010-03-26 21:05:43 +0800106 return i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800107 }
108
109 return -EINVAL;
110}
111
112/*
113 * Parse the category mask.
114 * The format can be this: category1:category2:category3
115 * or category1,2:category2,3:...
116 */
Harald Welte3ae27582010-03-26 21:24:24 +0800117void log_parse_category_mask(struct log_target* target, const char *_mask)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800118{
119 int i = 0;
120 char *mask = strdup(_mask);
121 char *category_token = NULL;
122
123 /* Disable everything to enable it afterwards */
Harald Welteb43bc042011-06-27 10:29:17 +0200124 for (i = 0; i < osmo_log_info->num_cat; ++i)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800125 target->categories[i].enabled = 0;
126
127 category_token = strtok(mask, ":");
128 do {
Harald Welte4ebdf742010-05-19 19:54:00 +0200129 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800130 char* colon = strstr(category_token, ",");
131 int length = strlen(category_token);
132
Harald Welteb43bc042011-06-27 10:29:17 +0200133 if (!osmo_log_info->cat[i].name)
134 continue;
135
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800136 if (colon)
137 length = colon - category_token;
138
Harald Welte4ebdf742010-05-19 19:54:00 +0200139 if (strncasecmp(osmo_log_info->cat[i].name,
140 category_token, length) == 0) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800141 int level = 0;
142
143 if (colon)
144 level = atoi(colon+1);
145
Harald Weltefaadfe22010-03-26 21:05:43 +0800146 target->categories[i].enabled = 1;
147 target->categories[i].loglevel = level;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800148 }
149 }
150 } while ((category_token = strtok(NULL, ":")));
151
152 free(mask);
153}
154
155static const char* color(int subsys)
156{
Harald Welte4ebdf742010-05-19 19:54:00 +0200157 if (subsys < osmo_log_info->num_cat)
158 return osmo_log_info->cat[subsys].color;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800159
Harald Welted788f662010-03-26 09:45:03 +0800160 return NULL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800161}
162
Harald Welte3ae27582010-03-26 21:24:24 +0800163static void _output(struct log_target *target, unsigned int subsys,
Harald Welte76e72ab2011-02-17 15:52:39 +0100164 unsigned int level, char *file, int line, int cont,
165 const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800166{
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800167 char buf[4096];
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200168 int ret, len = 0, offset = 0, rem = sizeof(buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800169
170 /* are we using color */
171 if (target->use_color) {
Harald Welted788f662010-03-26 09:45:03 +0800172 const char *c = color(subsys);
173 if (c) {
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200174 ret = snprintf(buf + offset, rem, "%s", color(subsys));
175 if (ret < 0)
176 goto err;
177 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welted788f662010-03-26 09:45:03 +0800178 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800179 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800180 if (!cont) {
181 if (target->print_timestamp) {
182 char *timestr;
183 time_t tm;
184 tm = time(NULL);
185 timestr = ctime(&tm);
186 timestr[strlen(timestr)-1] = '\0';
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200187 ret = snprintf(buf + offset, rem, "%s ", timestr);
188 if (ret < 0)
189 goto err;
190 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800191 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200192 ret = snprintf(buf + offset, rem, "<%4.4x> %s:%d ",
193 subsys, file, line);
194 if (ret < 0)
195 goto err;
196 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800197 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200198 ret = vsnprintf(buf + offset, rem, format, ap);
199 if (ret < 0)
200 goto err;
201 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800202
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200203 ret = snprintf(buf + offset, rem, "%s",
204 target->use_color ? "\033[0;m" : "");
205 if (ret < 0)
206 goto err;
207 OSMO_SNPRINTF_RET(ret, rem, offset, len);
208err:
209 buf[sizeof(buf)-1] = '\0';
210 target->output(target, level, buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800211}
212
Harald Welteb43bc042011-06-27 10:29:17 +0200213static void _logp(int subsys, int level, char *file, int line,
Harald Welte3ae27582010-03-26 21:24:24 +0800214 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800215{
Harald Welte3ae27582010-03-26 21:24:24 +0800216 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800217
Harald Welteb43bc042011-06-27 10:29:17 +0200218 if (subsys < 0)
219 subsys = subsys_lib2index(subsys);
220
221 if (subsys > osmo_log_info->num_cat)
222 subsys = DLGLOBAL;
223
Harald Welte28222962011-02-18 20:37:04 +0100224 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Harald Welte3ae27582010-03-26 21:24:24 +0800225 struct log_category *category;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800226 int output = 0;
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200227 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800228
229 category = &tar->categories[subsys];
Harald Welte3ae27582010-03-26 21:24:24 +0800230 /* subsystem is not supposed to be logged */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800231 if (!category->enabled)
232 continue;
233
234 /* Check the global log level */
235 if (tar->loglevel != 0 && level < tar->loglevel)
236 continue;
237
238 /* Check the category log level */
239 if (tar->loglevel == 0 && category->loglevel != 0 &&
240 level < category->loglevel)
241 continue;
242
243 /* Apply filters here... if that becomes messy we will
244 * need to put filters in a list and each filter will
245 * say stop, continue, output */
Harald Welte3ae27582010-03-26 21:24:24 +0800246 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800247 output = 1;
Harald Welte4ebdf742010-05-19 19:54:00 +0200248 else if (osmo_log_info->filter_fn)
249 output = osmo_log_info->filter_fn(&log_context,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800250 tar);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200251 if (!output)
252 continue;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800253
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200254 /* According to the manpage, vsnprintf leaves the value of ap
255 * in undefined state. Since _output uses vsnprintf and it may
256 * be called several times, we have to pass a copy of ap. */
257 va_copy(bp, ap);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200258 _output(tar, subsys, level, file, line, cont, format, ap);
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200259 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800260 }
261}
262
Harald Welteb43bc042011-06-27 10:29:17 +0200263void logp(int subsys, char *file, int line, int cont,
Harald Welte3ae27582010-03-26 21:24:24 +0800264 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800265{
266 va_list ap;
267
268 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800269 _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800270 va_end(ap);
271}
272
Harald Welteb43bc042011-06-27 10:29:17 +0200273void logp2(int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800274{
275 va_list ap;
276
277 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800278 _logp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800279 va_end(ap);
280}
281
Harald Welte3ae27582010-03-26 21:24:24 +0800282void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800283{
Harald Welte28222962011-02-18 20:37:04 +0100284 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800285}
286
Harald Welte3ae27582010-03-26 21:24:24 +0800287void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800288{
289 llist_del(&target->entry);
290}
291
Harald Welte3ae27582010-03-26 21:24:24 +0800292void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800293{
Harald Welte3ae27582010-03-26 21:24:24 +0800294 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800295}
296
Harald Welte3ae27582010-03-26 21:24:24 +0800297int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800298{
Harald Welte3ae27582010-03-26 21:24:24 +0800299 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800300 return -EINVAL;
301
Harald Welte3ae27582010-03-26 21:24:24 +0800302 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800303
304 return 0;
305}
306
Harald Welte3ae27582010-03-26 21:24:24 +0800307void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800308{
309 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800310 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800311 else
Harald Welte3ae27582010-03-26 21:24:24 +0800312 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800313}
314
Harald Welte3ae27582010-03-26 21:24:24 +0800315void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800316{
317 target->use_color = use_color;
318}
319
Harald Welte3ae27582010-03-26 21:24:24 +0800320void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800321{
322 target->print_timestamp = print_timestamp;
323}
324
Harald Welte3ae27582010-03-26 21:24:24 +0800325void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800326{
327 target->loglevel = log_level;
328}
329
Harald Welte3ae27582010-03-26 21:24:24 +0800330void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800331 int enable, int level)
332{
Harald Welte4ebdf742010-05-19 19:54:00 +0200333 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800334 return;
335 target->categories[category].enabled = !!enable;
336 target->categories[category].loglevel = level;
337}
338
Harald Welte76e72ab2011-02-17 15:52:39 +0100339static void _file_output(struct log_target *target, unsigned int level,
340 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800341{
Harald Welte0083cd32010-08-25 14:55:44 +0200342 fprintf(target->tgt_file.out, "%s", log);
343 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800344}
345
Harald Welte3ae27582010-03-26 21:24:24 +0800346struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800347{
Harald Welte3ae27582010-03-26 21:24:24 +0800348 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800349 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800350
Harald Welte3ae27582010-03-26 21:24:24 +0800351 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800352 if (!target)
353 return NULL;
354
Harald Welteb43bc042011-06-27 10:29:17 +0200355 target->categories = talloc_zero_array(target,
356 struct log_category,
357 osmo_log_info->num_cat);
358 if (!target->categories) {
359 talloc_free(target);
360 return NULL;
361 }
362
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800363 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800364
365 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200366 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800367 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200368 cat->enabled = osmo_log_info->cat[i].enabled;
369 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800370 }
371
372 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800373 target->use_color = 1;
374 target->print_timestamp = 0;
Harald Weltecc6313c2010-03-26 22:04:03 +0800375
376 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800377 target->loglevel = 0;
378 return target;
379}
380
Harald Welte3ae27582010-03-26 21:24:24 +0800381struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800382{
Harald Weltea3b844c2010-03-27 00:04:40 +0800383/* since C89/C99 says stderr is a macro, we can safely do this! */
384#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800385 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800386
Harald Welte3ae27582010-03-26 21:24:24 +0800387 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800388 if (!target)
389 return NULL;
390
Harald Welte28222962011-02-18 20:37:04 +0100391 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200392 target->tgt_file.out = stderr;
393 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800394 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800395#else
396 return NULL;
397#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800398}
399
Harald Welte3086c392010-08-25 19:10:50 +0200400struct log_target *log_target_create_file(const char *fname)
401{
402 struct log_target *target;
403
404 target = log_target_create();
405 if (!target)
406 return NULL;
407
Harald Welte28222962011-02-18 20:37:04 +0100408 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200409 target->tgt_file.out = fopen(fname, "a");
410 if (!target->tgt_file.out)
411 return NULL;
412
413 target->output = _file_output;
414
415 target->tgt_file.fname = talloc_strdup(target, fname);
416
417 return target;
418}
419
Harald Welte28222962011-02-18 20:37:04 +0100420struct log_target *log_target_find(int type, const char *fname)
421{
422 struct log_target *tgt;
423
424 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
425 if (tgt->type != type)
426 continue;
427 if (tgt->type == LOG_TGT_TYPE_FILE) {
428 if (!strcmp(fname, tgt->tgt_file.fname))
429 return tgt;
430 } else
431 return tgt;
432 }
433 return NULL;
434}
435
Harald Welte3086c392010-08-25 19:10:50 +0200436void log_target_destroy(struct log_target *target)
437{
438
439 /* just in case, to make sure we don't have any references */
440 log_del_target(target);
441
442 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200443/* since C89/C99 says stderr is a macro, we can safely do this! */
444#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200445 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200446 if (target->tgt_file.out != stderr)
447#endif
448 {
Harald Welte3086c392010-08-25 19:10:50 +0200449 fclose(target->tgt_file.out);
450 target->tgt_file.out = NULL;
451 }
452 }
453
454 talloc_free(target);
455}
456
457/* close and re-open a log file (for log file rotation) */
458int log_target_file_reopen(struct log_target *target)
459{
460 fclose(target->tgt_file.out);
461
462 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
463 if (!target->tgt_file.out)
464 return -errno;
465
466 /* we assume target->output already to be set */
467
468 return 0;
469}
470
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100471/* This generates the logging command string for VTY. */
472const char *log_vty_command_string(const struct log_info *info)
Harald Welte7638af92010-05-11 16:39:22 +0200473{
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100474 int len = 0, offset = 0, ret, i, rem;
475 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200476 char *str;
477
Harald Welteb43bc042011-06-27 10:29:17 +0200478 for (i = 0; i < info->num_cat; i++) {
479 if (info->cat[i].name == NULL)
480 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100481 size += strlen(info->cat[i].name) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200482 }
Harald Welte7638af92010-05-11 16:39:22 +0200483
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100484 for (i = 0; i < LOGLEVEL_DEFS; i++)
485 size += strlen(loglevel_strs[i].str) + 1;
486
487 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200488 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200489 if (!str)
490 return NULL;
491
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200492 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100493 if (ret < 0)
494 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200495 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200496
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100497 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200498 if (info->cat[i].name) {
499 int j, name_len = strlen(info->cat[i].name)+1;
500 char name[name_len];
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100501
Harald Welteb43bc042011-06-27 10:29:17 +0200502 for (j = 0; j < name_len; j++)
503 name[j] = tolower(info->cat[i].name[j]);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100504
Harald Welteb43bc042011-06-27 10:29:17 +0200505 name[name_len-1] = '\0';
506 ret = snprintf(str + offset, rem, "%s|", name+1);
507 if (ret < 0)
508 goto err;
509 OSMO_SNPRINTF_RET(ret, rem, offset, len);
510 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100511 }
512 offset--; /* to remove the trailing | */
513 rem++;
514
515 ret = snprintf(str + offset, rem, ") (");
516 if (ret < 0)
517 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200518 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100519
520 for (i = 0; i < LOGLEVEL_DEFS; i++) {
521 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
522 char loglevel_str[loglevel_str_len];
523
524 for (j = 0; j < loglevel_str_len; j++)
525 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
526
527 loglevel_str[loglevel_str_len-1] = '\0';
528 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
529 if (ret < 0)
530 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200531 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100532 }
533 offset--; /* to remove the trailing | */
534 rem++;
535
536 ret = snprintf(str + offset, rem, ")");
537 if (ret < 0)
538 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200539 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100540err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200541 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100542 return str;
543}
544
545/* This generates the logging command description for VTY. */
546const char *log_vty_command_description(const struct log_info *info)
547{
548 char *str;
549 int i, ret, len = 0, offset = 0, rem;
550 unsigned int size =
551 strlen(LOGGING_STR
552 "Set the log level for a specified category\n") + 1;
553
Harald Welteb43bc042011-06-27 10:29:17 +0200554 for (i = 0; i < info->num_cat; i++) {
555 if (info->cat[i].name == NULL)
556 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100557 size += strlen(info->cat[i].description) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200558 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100559
560 for (i = 0; i < LOGLEVEL_DEFS; i++)
561 size += strlen(loglevel_descriptions[i]) + 1;
562
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200563 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100564 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200565 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100566 if (!str)
567 return NULL;
568
569 ret = snprintf(str + offset, rem, LOGGING_STR
570 "Set the log level for a specified category\n");
571 if (ret < 0)
572 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200573 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100574
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200575 ret = snprintf(str + offset, rem,
576 "Global setting for all subsystems\n");
577 if (ret < 0)
578 goto err;
579 OSMO_SNPRINTF_RET(ret, rem, offset, len);
580
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100581 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200582 if (info->cat[i].name == NULL)
583 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100584 ret = snprintf(str + offset, rem, "%s\n",
585 info->cat[i].description);
586 if (ret < 0)
587 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200588 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100589 }
590 for (i = 0; i < LOGLEVEL_DEFS; i++) {
591 ret = snprintf(str + offset, rem, "%s\n",
592 loglevel_descriptions[i]);
593 if (ret < 0)
594 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200595 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100596 }
597err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200598 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200599 return str;
600}
601
Harald Welteb43bc042011-06-27 10:29:17 +0200602int log_init(const struct log_info *inf, void *ctx)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800603{
Harald Welteb43bc042011-06-27 10:29:17 +0200604 int i;
605
606 tall_log_ctx = talloc_named_const(ctx, 1, "logging");
607 if (!tall_log_ctx)
608 return -ENOMEM;
609
610 osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
611 if (!osmo_log_info)
612 return -ENOMEM;
613
614 osmo_log_info->num_cat_user = inf->num_cat;
615 /* total number = number of user cat + library cat */
616 osmo_log_info->num_cat = inf->num_cat + OSMO_NUM_DLIB;
617
618 osmo_log_info->cat = talloc_zero_array(osmo_log_info,
619 struct log_info_cat,
620 osmo_log_info->num_cat);
621 if (!osmo_log_info->cat) {
622 talloc_free(osmo_log_info);
623 osmo_log_info = NULL;
624 return -ENOMEM;
625 }
626
627 /* copy over the user part */
628 for (i = 0; i < inf->num_cat; i++) {
629 memcpy(&osmo_log_info->cat[i], &inf->cat[i],
630 sizeof(struct log_info_cat));
631 }
632
633 /* copy over the library part */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800634}