blob: 526b39e325f66d82e86eb7b4e79a8b5d56680f22 [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 Welte4ebdf742010-05-19 19:54:00 +020043const struct 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
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010061/* You have to keep this in sync with the structure loglevel_strs. */
62const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
63 "Log simply everything",
64 "Log debug messages and higher levels",
65 "Log informational messages and higher levels",
66 "Log noticable messages and higher levels",
67 "Log error messages and higher levels",
68 "Log only fatal messages",
69 NULL,
70};
71
Harald Welte3ae27582010-03-26 21:24:24 +080072int log_parse_level(const char *lvl)
Harald Welte4a2bb9e2010-03-26 09:33:40 +080073{
74 return get_string_value(loglevel_strs, lvl);
75}
76
Harald Welte9ac22252010-05-11 11:19:40 +020077const char *log_level_str(unsigned int lvl)
78{
79 return get_value_string(loglevel_strs, lvl);
80}
81
Harald Welte3ae27582010-03-26 21:24:24 +080082int log_parse_category(const char *category)
Harald Welte4a2bb9e2010-03-26 09:33:40 +080083{
84 int i;
85
Harald Welte4ebdf742010-05-19 19:54:00 +020086 for (i = 0; i < osmo_log_info->num_cat; ++i) {
87 if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
Harald Weltefaadfe22010-03-26 21:05:43 +080088 return i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +080089 }
90
91 return -EINVAL;
92}
93
94/*
95 * Parse the category mask.
96 * The format can be this: category1:category2:category3
97 * or category1,2:category2,3:...
98 */
Harald Welte3ae27582010-03-26 21:24:24 +080099void log_parse_category_mask(struct log_target* target, const char *_mask)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800100{
101 int i = 0;
102 char *mask = strdup(_mask);
103 char *category_token = NULL;
104
105 /* Disable everything to enable it afterwards */
106 for (i = 0; i < ARRAY_SIZE(target->categories); ++i)
107 target->categories[i].enabled = 0;
108
109 category_token = strtok(mask, ":");
110 do {
Harald Welte4ebdf742010-05-19 19:54:00 +0200111 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800112 char* colon = strstr(category_token, ",");
113 int length = strlen(category_token);
114
115 if (colon)
116 length = colon - category_token;
117
Harald Welte4ebdf742010-05-19 19:54:00 +0200118 if (strncasecmp(osmo_log_info->cat[i].name,
119 category_token, length) == 0) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800120 int level = 0;
121
122 if (colon)
123 level = atoi(colon+1);
124
Harald Weltefaadfe22010-03-26 21:05:43 +0800125 target->categories[i].enabled = 1;
126 target->categories[i].loglevel = level;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800127 }
128 }
129 } while ((category_token = strtok(NULL, ":")));
130
131 free(mask);
132}
133
134static const char* color(int subsys)
135{
Harald Welte4ebdf742010-05-19 19:54:00 +0200136 if (subsys < osmo_log_info->num_cat)
137 return osmo_log_info->cat[subsys].color;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800138
Harald Welted788f662010-03-26 09:45:03 +0800139 return NULL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800140}
141
Harald Welte3ae27582010-03-26 21:24:24 +0800142static void _output(struct log_target *target, unsigned int subsys,
Harald Welte76e72ab2011-02-17 15:52:39 +0100143 unsigned int level, char *file, int line, int cont,
144 const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800145{
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800146 char buf[4096];
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200147 int ret, len = 0, offset = 0, rem = sizeof(buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800148
149 /* are we using color */
150 if (target->use_color) {
Harald Welted788f662010-03-26 09:45:03 +0800151 const char *c = color(subsys);
152 if (c) {
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200153 ret = snprintf(buf + offset, rem, "%s", color(subsys));
154 if (ret < 0)
155 goto err;
156 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welted788f662010-03-26 09:45:03 +0800157 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800158 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800159 if (!cont) {
160 if (target->print_timestamp) {
161 char *timestr;
162 time_t tm;
163 tm = time(NULL);
164 timestr = ctime(&tm);
165 timestr[strlen(timestr)-1] = '\0';
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200166 ret = snprintf(buf + offset, rem, "%s ", timestr);
167 if (ret < 0)
168 goto err;
169 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800170 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200171 ret = snprintf(buf + offset, rem, "<%4.4x> %s:%d ",
172 subsys, file, line);
173 if (ret < 0)
174 goto err;
175 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800176 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200177 ret = vsnprintf(buf + offset, rem, format, ap);
178 if (ret < 0)
179 goto err;
180 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800181
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200182 ret = snprintf(buf + offset, rem, "%s",
183 target->use_color ? "\033[0;m" : "");
184 if (ret < 0)
185 goto err;
186 OSMO_SNPRINTF_RET(ret, rem, offset, len);
187err:
188 buf[sizeof(buf)-1] = '\0';
189 target->output(target, level, buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800190}
191
192
Harald Welte3ae27582010-03-26 21:24:24 +0800193static void _logp(unsigned int subsys, int level, char *file, int line,
194 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800195{
Harald Welte3ae27582010-03-26 21:24:24 +0800196 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800197
Harald Welte28222962011-02-18 20:37:04 +0100198 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Harald Welte3ae27582010-03-26 21:24:24 +0800199 struct log_category *category;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800200 int output = 0;
201
202 category = &tar->categories[subsys];
Harald Welte3ae27582010-03-26 21:24:24 +0800203 /* subsystem is not supposed to be logged */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800204 if (!category->enabled)
205 continue;
206
207 /* Check the global log level */
208 if (tar->loglevel != 0 && level < tar->loglevel)
209 continue;
210
211 /* Check the category log level */
212 if (tar->loglevel == 0 && category->loglevel != 0 &&
213 level < category->loglevel)
214 continue;
215
216 /* Apply filters here... if that becomes messy we will
217 * need to put filters in a list and each filter will
218 * say stop, continue, output */
Harald Welte3ae27582010-03-26 21:24:24 +0800219 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800220 output = 1;
Harald Welte4ebdf742010-05-19 19:54:00 +0200221 else if (osmo_log_info->filter_fn)
222 output = osmo_log_info->filter_fn(&log_context,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800223 tar);
224
225 if (output) {
226 /* FIXME: copying the va_list is an ugly
227 * workaround against a bug hidden somewhere in
228 * _output. If we do not copy here, the first
229 * call to _output() will corrupt the va_list
230 * contents, and any further _output() calls
231 * with the same va_list will segfault */
232 va_list bp;
233 va_copy(bp, ap);
Harald Welte76e72ab2011-02-17 15:52:39 +0100234 _output(tar, subsys, level, file, line, cont, format, bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800235 va_end(bp);
236 }
237 }
238}
239
Harald Welte3ae27582010-03-26 21:24:24 +0800240void logp(unsigned int subsys, char *file, int line, int cont,
241 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800242{
243 va_list ap;
244
245 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800246 _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800247 va_end(ap);
248}
249
Harald Welte3ae27582010-03-26 21:24:24 +0800250void logp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800251{
252 va_list ap;
253
254 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800255 _logp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800256 va_end(ap);
257}
258
Harald Welte3ae27582010-03-26 21:24:24 +0800259void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800260{
Harald Welte28222962011-02-18 20:37:04 +0100261 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800262}
263
Harald Welte3ae27582010-03-26 21:24:24 +0800264void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800265{
266 llist_del(&target->entry);
267}
268
Harald Welte3ae27582010-03-26 21:24:24 +0800269void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800270{
Harald Welte3ae27582010-03-26 21:24:24 +0800271 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800272}
273
Harald Welte3ae27582010-03-26 21:24:24 +0800274int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800275{
Harald Welte3ae27582010-03-26 21:24:24 +0800276 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800277 return -EINVAL;
278
Harald Welte3ae27582010-03-26 21:24:24 +0800279 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800280
281 return 0;
282}
283
Harald Welte3ae27582010-03-26 21:24:24 +0800284void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800285{
286 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800287 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800288 else
Harald Welte3ae27582010-03-26 21:24:24 +0800289 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800290}
291
Harald Welte3ae27582010-03-26 21:24:24 +0800292void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800293{
294 target->use_color = use_color;
295}
296
Harald Welte3ae27582010-03-26 21:24:24 +0800297void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800298{
299 target->print_timestamp = print_timestamp;
300}
301
Harald Welte3ae27582010-03-26 21:24:24 +0800302void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800303{
304 target->loglevel = log_level;
305}
306
Harald Welte3ae27582010-03-26 21:24:24 +0800307void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800308 int enable, int level)
309{
Harald Welte4ebdf742010-05-19 19:54:00 +0200310 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800311 return;
312 target->categories[category].enabled = !!enable;
313 target->categories[category].loglevel = level;
314}
315
Harald Welte76e72ab2011-02-17 15:52:39 +0100316static void _file_output(struct log_target *target, unsigned int level,
317 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800318{
Harald Welte0083cd32010-08-25 14:55:44 +0200319 fprintf(target->tgt_file.out, "%s", log);
320 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800321}
322
Harald Welte3ae27582010-03-26 21:24:24 +0800323struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800324{
Harald Welte3ae27582010-03-26 21:24:24 +0800325 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800326 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800327
Harald Welte3ae27582010-03-26 21:24:24 +0800328 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800329 if (!target)
330 return NULL;
331
332 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800333
334 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200335 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800336 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200337 cat->enabled = osmo_log_info->cat[i].enabled;
338 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800339 }
340
341 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800342 target->use_color = 1;
343 target->print_timestamp = 0;
Harald Weltecc6313c2010-03-26 22:04:03 +0800344
345 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800346 target->loglevel = 0;
347 return target;
348}
349
Harald Welte3ae27582010-03-26 21:24:24 +0800350struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800351{
Harald Weltea3b844c2010-03-27 00:04:40 +0800352/* since C89/C99 says stderr is a macro, we can safely do this! */
353#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800354 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800355
Harald Welte3ae27582010-03-26 21:24:24 +0800356 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800357 if (!target)
358 return NULL;
359
Harald Welte28222962011-02-18 20:37:04 +0100360 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200361 target->tgt_file.out = stderr;
362 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800363 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800364#else
365 return NULL;
366#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800367}
368
Harald Welte3086c392010-08-25 19:10:50 +0200369struct log_target *log_target_create_file(const char *fname)
370{
371 struct log_target *target;
372
373 target = log_target_create();
374 if (!target)
375 return NULL;
376
Harald Welte28222962011-02-18 20:37:04 +0100377 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200378 target->tgt_file.out = fopen(fname, "a");
379 if (!target->tgt_file.out)
380 return NULL;
381
382 target->output = _file_output;
383
384 target->tgt_file.fname = talloc_strdup(target, fname);
385
386 return target;
387}
388
Harald Welte28222962011-02-18 20:37:04 +0100389struct log_target *log_target_find(int type, const char *fname)
390{
391 struct log_target *tgt;
392
393 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
394 if (tgt->type != type)
395 continue;
396 if (tgt->type == LOG_TGT_TYPE_FILE) {
397 if (!strcmp(fname, tgt->tgt_file.fname))
398 return tgt;
399 } else
400 return tgt;
401 }
402 return NULL;
403}
404
Harald Welte3086c392010-08-25 19:10:50 +0200405void log_target_destroy(struct log_target *target)
406{
407
408 /* just in case, to make sure we don't have any references */
409 log_del_target(target);
410
411 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200412/* since C89/C99 says stderr is a macro, we can safely do this! */
413#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200414 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200415 if (target->tgt_file.out != stderr)
416#endif
417 {
Harald Welte3086c392010-08-25 19:10:50 +0200418 fclose(target->tgt_file.out);
419 target->tgt_file.out = NULL;
420 }
421 }
422
423 talloc_free(target);
424}
425
426/* close and re-open a log file (for log file rotation) */
427int log_target_file_reopen(struct log_target *target)
428{
429 fclose(target->tgt_file.out);
430
431 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
432 if (!target->tgt_file.out)
433 return -errno;
434
435 /* we assume target->output already to be set */
436
437 return 0;
438}
439
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100440/* This generates the logging command string for VTY. */
441const char *log_vty_command_string(const struct log_info *info)
Harald Welte7638af92010-05-11 16:39:22 +0200442{
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100443 int len = 0, offset = 0, ret, i, rem;
444 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200445 char *str;
446
447 for (i = 0; i < info->num_cat; i++)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100448 size += strlen(info->cat[i].name) + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200449
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100450 for (i = 0; i < LOGLEVEL_DEFS; i++)
451 size += strlen(loglevel_strs[i].str) + 1;
452
453 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200454 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200455 if (!str)
456 return NULL;
457
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200458 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100459 if (ret < 0)
460 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200461 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200462
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100463 for (i = 0; i < info->num_cat; i++) {
464 int j, name_len = strlen(info->cat[i].name)+1;
465 char name[name_len];
466
467 for (j = 0; j < name_len; j++)
468 name[j] = tolower(info->cat[i].name[j]);
469
470 name[name_len-1] = '\0';
471 ret = snprintf(str + offset, rem, "%s|", name+1);
472 if (ret < 0)
473 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200474 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100475 }
476 offset--; /* to remove the trailing | */
477 rem++;
478
479 ret = snprintf(str + offset, rem, ") (");
480 if (ret < 0)
481 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200482 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100483
484 for (i = 0; i < LOGLEVEL_DEFS; i++) {
485 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
486 char loglevel_str[loglevel_str_len];
487
488 for (j = 0; j < loglevel_str_len; j++)
489 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
490
491 loglevel_str[loglevel_str_len-1] = '\0';
492 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
493 if (ret < 0)
494 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200495 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100496 }
497 offset--; /* to remove the trailing | */
498 rem++;
499
500 ret = snprintf(str + offset, rem, ")");
501 if (ret < 0)
502 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200503 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100504err:
505 return str;
506}
507
508/* This generates the logging command description for VTY. */
509const char *log_vty_command_description(const struct log_info *info)
510{
511 char *str;
512 int i, ret, len = 0, offset = 0, rem;
513 unsigned int size =
514 strlen(LOGGING_STR
515 "Set the log level for a specified category\n") + 1;
516
517 for (i = 0; i < info->num_cat; i++)
518 size += strlen(info->cat[i].description) + 1;
519
520 for (i = 0; i < LOGLEVEL_DEFS; i++)
521 size += strlen(loglevel_descriptions[i]) + 1;
522
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200523 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100524 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200525 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100526 if (!str)
527 return NULL;
528
529 ret = snprintf(str + offset, rem, LOGGING_STR
530 "Set the log level for a specified category\n");
531 if (ret < 0)
532 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200533 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100534
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200535 ret = snprintf(str + offset, rem,
536 "Global setting for all subsystems\n");
537 if (ret < 0)
538 goto err;
539 OSMO_SNPRINTF_RET(ret, rem, offset, len);
540
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100541 for (i = 0; i < info->num_cat; i++) {
542 ret = snprintf(str + offset, rem, "%s\n",
543 info->cat[i].description);
544 if (ret < 0)
545 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200546 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100547 }
548 for (i = 0; i < LOGLEVEL_DEFS; i++) {
549 ret = snprintf(str + offset, rem, "%s\n",
550 loglevel_descriptions[i]);
551 if (ret < 0)
552 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200553 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100554 }
555err:
Harald Welte7638af92010-05-11 16:39:22 +0200556 return str;
557}
558
Harald Welte3ae27582010-03-26 21:24:24 +0800559void log_init(const struct log_info *cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800560{
Harald Welte3ae27582010-03-26 21:24:24 +0800561 tall_log_ctx = talloc_named_const(NULL, 1, "logging");
Harald Welte4ebdf742010-05-19 19:54:00 +0200562 osmo_log_info = cat;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800563}