blob: 8fd2e00581b83c11884f6a253b79e9f7dc4bddec [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 },
Harald Welte1f0b8c22011-06-27 10:51:37 +020069 [INT2IDX(DLLAPDM)] = { /* -2 becomes 1 */
70 .name = "DLLAPDM",
71 .description = "LAPDm in libosmogsm",
72 .loglevel = LOGL_NOTICE,
73 .enabled = 1,
74 },
Harald Welteb43bc042011-06-27 10:29:17 +020075};
76
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010077/* You have to keep this in sync with the structure loglevel_strs. */
78const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
79 "Log simply everything",
80 "Log debug messages and higher levels",
81 "Log informational messages and higher levels",
82 "Log noticable messages and higher levels",
83 "Log error messages and higher levels",
84 "Log only fatal messages",
85 NULL,
86};
87
Harald Welteb43bc042011-06-27 10:29:17 +020088/* special magic for negative (library-internal) log subsystem numbers */
89static int subsys_lib2index(int subsys)
90{
91 return (subsys * -1) + (osmo_log_info->num_cat_user-1);
92}
93
Harald Welte3ae27582010-03-26 21:24:24 +080094int log_parse_level(const char *lvl)
Harald Welte4a2bb9e2010-03-26 09:33:40 +080095{
96 return get_string_value(loglevel_strs, lvl);
97}
98
Harald Welte9ac22252010-05-11 11:19:40 +020099const char *log_level_str(unsigned int lvl)
100{
101 return get_value_string(loglevel_strs, lvl);
102}
103
Harald Welte3ae27582010-03-26 21:24:24 +0800104int log_parse_category(const char *category)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800105{
106 int i;
107
Harald Welte4ebdf742010-05-19 19:54:00 +0200108 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welteb43bc042011-06-27 10:29:17 +0200109 if (osmo_log_info->cat[i].name == NULL)
110 continue;
Harald Welte4ebdf742010-05-19 19:54:00 +0200111 if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
Harald Weltefaadfe22010-03-26 21:05:43 +0800112 return i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800113 }
114
115 return -EINVAL;
116}
117
118/*
119 * Parse the category mask.
120 * The format can be this: category1:category2:category3
121 * or category1,2:category2,3:...
122 */
Harald Welte3ae27582010-03-26 21:24:24 +0800123void log_parse_category_mask(struct log_target* target, const char *_mask)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800124{
125 int i = 0;
126 char *mask = strdup(_mask);
127 char *category_token = NULL;
128
129 /* Disable everything to enable it afterwards */
Harald Welteb43bc042011-06-27 10:29:17 +0200130 for (i = 0; i < osmo_log_info->num_cat; ++i)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800131 target->categories[i].enabled = 0;
132
133 category_token = strtok(mask, ":");
134 do {
Harald Welte4ebdf742010-05-19 19:54:00 +0200135 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800136 char* colon = strstr(category_token, ",");
137 int length = strlen(category_token);
138
Harald Welteb43bc042011-06-27 10:29:17 +0200139 if (!osmo_log_info->cat[i].name)
140 continue;
141
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800142 if (colon)
143 length = colon - category_token;
144
Harald Welte4ebdf742010-05-19 19:54:00 +0200145 if (strncasecmp(osmo_log_info->cat[i].name,
146 category_token, length) == 0) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800147 int level = 0;
148
149 if (colon)
150 level = atoi(colon+1);
151
Harald Weltefaadfe22010-03-26 21:05:43 +0800152 target->categories[i].enabled = 1;
153 target->categories[i].loglevel = level;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800154 }
155 }
156 } while ((category_token = strtok(NULL, ":")));
157
158 free(mask);
159}
160
161static const char* color(int subsys)
162{
Harald Welte4ebdf742010-05-19 19:54:00 +0200163 if (subsys < osmo_log_info->num_cat)
164 return osmo_log_info->cat[subsys].color;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800165
Harald Welted788f662010-03-26 09:45:03 +0800166 return NULL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800167}
168
Harald Welte3ae27582010-03-26 21:24:24 +0800169static void _output(struct log_target *target, unsigned int subsys,
Harald Welte76e72ab2011-02-17 15:52:39 +0100170 unsigned int level, char *file, int line, int cont,
171 const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800172{
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800173 char buf[4096];
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200174 int ret, len = 0, offset = 0, rem = sizeof(buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800175
176 /* are we using color */
177 if (target->use_color) {
Harald Welted788f662010-03-26 09:45:03 +0800178 const char *c = color(subsys);
179 if (c) {
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200180 ret = snprintf(buf + offset, rem, "%s", color(subsys));
181 if (ret < 0)
182 goto err;
183 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welted788f662010-03-26 09:45:03 +0800184 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800185 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800186 if (!cont) {
187 if (target->print_timestamp) {
188 char *timestr;
189 time_t tm;
190 tm = time(NULL);
191 timestr = ctime(&tm);
192 timestr[strlen(timestr)-1] = '\0';
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200193 ret = snprintf(buf + offset, rem, "%s ", timestr);
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 = snprintf(buf + offset, rem, "<%4.4x> %s:%d ",
199 subsys, file, line);
200 if (ret < 0)
201 goto err;
202 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800203 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200204 ret = vsnprintf(buf + offset, rem, format, ap);
205 if (ret < 0)
206 goto err;
207 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800208
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200209 ret = snprintf(buf + offset, rem, "%s",
210 target->use_color ? "\033[0;m" : "");
211 if (ret < 0)
212 goto err;
213 OSMO_SNPRINTF_RET(ret, rem, offset, len);
214err:
215 buf[sizeof(buf)-1] = '\0';
216 target->output(target, level, buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800217}
218
Harald Welteb43bc042011-06-27 10:29:17 +0200219static void _logp(int subsys, int level, char *file, int line,
Harald Welte3ae27582010-03-26 21:24:24 +0800220 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800221{
Harald Welte3ae27582010-03-26 21:24:24 +0800222 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800223
Harald Welteb43bc042011-06-27 10:29:17 +0200224 if (subsys < 0)
225 subsys = subsys_lib2index(subsys);
226
227 if (subsys > osmo_log_info->num_cat)
228 subsys = DLGLOBAL;
229
Harald Welte28222962011-02-18 20:37:04 +0100230 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Harald Welte3ae27582010-03-26 21:24:24 +0800231 struct log_category *category;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800232 int output = 0;
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200233 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800234
235 category = &tar->categories[subsys];
Harald Welte3ae27582010-03-26 21:24:24 +0800236 /* subsystem is not supposed to be logged */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800237 if (!category->enabled)
238 continue;
239
240 /* Check the global log level */
241 if (tar->loglevel != 0 && level < tar->loglevel)
242 continue;
243
244 /* Check the category log level */
245 if (tar->loglevel == 0 && category->loglevel != 0 &&
246 level < category->loglevel)
247 continue;
248
249 /* Apply filters here... if that becomes messy we will
250 * need to put filters in a list and each filter will
251 * say stop, continue, output */
Harald Welte3ae27582010-03-26 21:24:24 +0800252 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800253 output = 1;
Harald Welte4ebdf742010-05-19 19:54:00 +0200254 else if (osmo_log_info->filter_fn)
255 output = osmo_log_info->filter_fn(&log_context,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800256 tar);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200257 if (!output)
258 continue;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800259
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200260 /* According to the manpage, vsnprintf leaves the value of ap
261 * in undefined state. Since _output uses vsnprintf and it may
262 * be called several times, we have to pass a copy of ap. */
263 va_copy(bp, ap);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200264 _output(tar, subsys, level, file, line, cont, format, ap);
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200265 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800266 }
267}
268
Harald Welteb43bc042011-06-27 10:29:17 +0200269void logp(int subsys, char *file, int line, int cont,
Harald Welte3ae27582010-03-26 21:24:24 +0800270 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800271{
272 va_list ap;
273
274 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800275 _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800276 va_end(ap);
277}
278
Harald Welteb43bc042011-06-27 10:29:17 +0200279void logp2(int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800280{
281 va_list ap;
282
283 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800284 _logp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800285 va_end(ap);
286}
287
Harald Welte3ae27582010-03-26 21:24:24 +0800288void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800289{
Harald Welte28222962011-02-18 20:37:04 +0100290 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800291}
292
Harald Welte3ae27582010-03-26 21:24:24 +0800293void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800294{
295 llist_del(&target->entry);
296}
297
Harald Welte3ae27582010-03-26 21:24:24 +0800298void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800299{
Harald Welte3ae27582010-03-26 21:24:24 +0800300 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800301}
302
Harald Welte3ae27582010-03-26 21:24:24 +0800303int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800304{
Harald Welte3ae27582010-03-26 21:24:24 +0800305 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800306 return -EINVAL;
307
Harald Welte3ae27582010-03-26 21:24:24 +0800308 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800309
310 return 0;
311}
312
Harald Welte3ae27582010-03-26 21:24:24 +0800313void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800314{
315 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800316 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800317 else
Harald Welte3ae27582010-03-26 21:24:24 +0800318 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800319}
320
Harald Welte3ae27582010-03-26 21:24:24 +0800321void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800322{
323 target->use_color = use_color;
324}
325
Harald Welte3ae27582010-03-26 21:24:24 +0800326void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800327{
328 target->print_timestamp = print_timestamp;
329}
330
Harald Welte3ae27582010-03-26 21:24:24 +0800331void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800332{
333 target->loglevel = log_level;
334}
335
Harald Welte3ae27582010-03-26 21:24:24 +0800336void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800337 int enable, int level)
338{
Harald Welte4ebdf742010-05-19 19:54:00 +0200339 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800340 return;
341 target->categories[category].enabled = !!enable;
342 target->categories[category].loglevel = level;
343}
344
Harald Welte76e72ab2011-02-17 15:52:39 +0100345static void _file_output(struct log_target *target, unsigned int level,
346 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800347{
Harald Welte0083cd32010-08-25 14:55:44 +0200348 fprintf(target->tgt_file.out, "%s", log);
349 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800350}
351
Harald Welte3ae27582010-03-26 21:24:24 +0800352struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800353{
Harald Welte3ae27582010-03-26 21:24:24 +0800354 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800355 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800356
Harald Welte3ae27582010-03-26 21:24:24 +0800357 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800358 if (!target)
359 return NULL;
360
Harald Welteb43bc042011-06-27 10:29:17 +0200361 target->categories = talloc_zero_array(target,
362 struct log_category,
363 osmo_log_info->num_cat);
364 if (!target->categories) {
365 talloc_free(target);
366 return NULL;
367 }
368
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800369 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800370
371 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200372 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800373 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200374 cat->enabled = osmo_log_info->cat[i].enabled;
375 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800376 }
377
378 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800379 target->use_color = 1;
380 target->print_timestamp = 0;
Harald Weltecc6313c2010-03-26 22:04:03 +0800381
382 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800383 target->loglevel = 0;
384 return target;
385}
386
Harald Welte3ae27582010-03-26 21:24:24 +0800387struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800388{
Harald Weltea3b844c2010-03-27 00:04:40 +0800389/* since C89/C99 says stderr is a macro, we can safely do this! */
390#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800391 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800392
Harald Welte3ae27582010-03-26 21:24:24 +0800393 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800394 if (!target)
395 return NULL;
396
Harald Welte28222962011-02-18 20:37:04 +0100397 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200398 target->tgt_file.out = stderr;
399 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800400 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800401#else
402 return NULL;
403#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800404}
405
Harald Welte3086c392010-08-25 19:10:50 +0200406struct log_target *log_target_create_file(const char *fname)
407{
408 struct log_target *target;
409
410 target = log_target_create();
411 if (!target)
412 return NULL;
413
Harald Welte28222962011-02-18 20:37:04 +0100414 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200415 target->tgt_file.out = fopen(fname, "a");
416 if (!target->tgt_file.out)
417 return NULL;
418
419 target->output = _file_output;
420
421 target->tgt_file.fname = talloc_strdup(target, fname);
422
423 return target;
424}
425
Harald Welte28222962011-02-18 20:37:04 +0100426struct log_target *log_target_find(int type, const char *fname)
427{
428 struct log_target *tgt;
429
430 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
431 if (tgt->type != type)
432 continue;
433 if (tgt->type == LOG_TGT_TYPE_FILE) {
434 if (!strcmp(fname, tgt->tgt_file.fname))
435 return tgt;
436 } else
437 return tgt;
438 }
439 return NULL;
440}
441
Harald Welte3086c392010-08-25 19:10:50 +0200442void log_target_destroy(struct log_target *target)
443{
444
445 /* just in case, to make sure we don't have any references */
446 log_del_target(target);
447
448 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200449/* since C89/C99 says stderr is a macro, we can safely do this! */
450#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200451 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200452 if (target->tgt_file.out != stderr)
453#endif
454 {
Harald Welte3086c392010-08-25 19:10:50 +0200455 fclose(target->tgt_file.out);
456 target->tgt_file.out = NULL;
457 }
458 }
459
460 talloc_free(target);
461}
462
463/* close and re-open a log file (for log file rotation) */
464int log_target_file_reopen(struct log_target *target)
465{
466 fclose(target->tgt_file.out);
467
468 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
469 if (!target->tgt_file.out)
470 return -errno;
471
472 /* we assume target->output already to be set */
473
474 return 0;
475}
476
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100477/* This generates the logging command string for VTY. */
478const char *log_vty_command_string(const struct log_info *info)
Harald Welte7638af92010-05-11 16:39:22 +0200479{
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100480 int len = 0, offset = 0, ret, i, rem;
481 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200482 char *str;
483
Harald Welteb43bc042011-06-27 10:29:17 +0200484 for (i = 0; i < info->num_cat; i++) {
485 if (info->cat[i].name == NULL)
486 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100487 size += strlen(info->cat[i].name) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200488 }
Harald Welte7638af92010-05-11 16:39:22 +0200489
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100490 for (i = 0; i < LOGLEVEL_DEFS; i++)
491 size += strlen(loglevel_strs[i].str) + 1;
492
493 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200494 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200495 if (!str)
496 return NULL;
497
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200498 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100499 if (ret < 0)
500 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200501 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200502
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100503 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200504 if (info->cat[i].name) {
505 int j, name_len = strlen(info->cat[i].name)+1;
506 char name[name_len];
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100507
Harald Welteb43bc042011-06-27 10:29:17 +0200508 for (j = 0; j < name_len; j++)
509 name[j] = tolower(info->cat[i].name[j]);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100510
Harald Welteb43bc042011-06-27 10:29:17 +0200511 name[name_len-1] = '\0';
512 ret = snprintf(str + offset, rem, "%s|", name+1);
513 if (ret < 0)
514 goto err;
515 OSMO_SNPRINTF_RET(ret, rem, offset, len);
516 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100517 }
518 offset--; /* to remove the trailing | */
519 rem++;
520
521 ret = snprintf(str + offset, rem, ") (");
522 if (ret < 0)
523 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200524 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100525
526 for (i = 0; i < LOGLEVEL_DEFS; i++) {
527 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
528 char loglevel_str[loglevel_str_len];
529
530 for (j = 0; j < loglevel_str_len; j++)
531 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
532
533 loglevel_str[loglevel_str_len-1] = '\0';
534 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
535 if (ret < 0)
536 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200537 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100538 }
539 offset--; /* to remove the trailing | */
540 rem++;
541
542 ret = snprintf(str + offset, rem, ")");
543 if (ret < 0)
544 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200545 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100546err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200547 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100548 return str;
549}
550
551/* This generates the logging command description for VTY. */
552const char *log_vty_command_description(const struct log_info *info)
553{
554 char *str;
555 int i, ret, len = 0, offset = 0, rem;
556 unsigned int size =
557 strlen(LOGGING_STR
558 "Set the log level for a specified category\n") + 1;
559
Harald Welteb43bc042011-06-27 10:29:17 +0200560 for (i = 0; i < info->num_cat; i++) {
561 if (info->cat[i].name == NULL)
562 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100563 size += strlen(info->cat[i].description) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200564 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100565
566 for (i = 0; i < LOGLEVEL_DEFS; i++)
567 size += strlen(loglevel_descriptions[i]) + 1;
568
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200569 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100570 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200571 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100572 if (!str)
573 return NULL;
574
575 ret = snprintf(str + offset, rem, LOGGING_STR
576 "Set the log level for a specified category\n");
577 if (ret < 0)
578 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200579 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100580
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200581 ret = snprintf(str + offset, rem,
582 "Global setting for all subsystems\n");
583 if (ret < 0)
584 goto err;
585 OSMO_SNPRINTF_RET(ret, rem, offset, len);
586
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100587 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200588 if (info->cat[i].name == NULL)
589 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100590 ret = snprintf(str + offset, rem, "%s\n",
591 info->cat[i].description);
592 if (ret < 0)
593 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200594 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100595 }
596 for (i = 0; i < LOGLEVEL_DEFS; i++) {
597 ret = snprintf(str + offset, rem, "%s\n",
598 loglevel_descriptions[i]);
599 if (ret < 0)
600 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200601 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100602 }
603err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200604 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200605 return str;
606}
607
Harald Welteb43bc042011-06-27 10:29:17 +0200608int log_init(const struct log_info *inf, void *ctx)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800609{
Harald Welteb43bc042011-06-27 10:29:17 +0200610 int i;
611
612 tall_log_ctx = talloc_named_const(ctx, 1, "logging");
613 if (!tall_log_ctx)
614 return -ENOMEM;
615
616 osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
617 if (!osmo_log_info)
618 return -ENOMEM;
619
620 osmo_log_info->num_cat_user = inf->num_cat;
621 /* total number = number of user cat + library cat */
622 osmo_log_info->num_cat = inf->num_cat + OSMO_NUM_DLIB;
623
624 osmo_log_info->cat = talloc_zero_array(osmo_log_info,
625 struct log_info_cat,
626 osmo_log_info->num_cat);
627 if (!osmo_log_info->cat) {
628 talloc_free(osmo_log_info);
629 osmo_log_info = NULL;
630 return -ENOMEM;
631 }
632
633 /* copy over the user part */
634 for (i = 0; i < inf->num_cat; i++) {
635 memcpy(&osmo_log_info->cat[i], &inf->cat[i],
636 sizeof(struct log_info_cat));
637 }
638
639 /* copy over the library part */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800640}