blob: 0911010a259c0975318f257445482604cd134605 [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);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200224 if (!output)
225 continue;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800226
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200227 _output(tar, subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800228 }
229}
230
Harald Welte3ae27582010-03-26 21:24:24 +0800231void logp(unsigned int subsys, char *file, int line, int cont,
232 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800233{
234 va_list ap;
235
236 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800237 _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800238 va_end(ap);
239}
240
Harald Welte3ae27582010-03-26 21:24:24 +0800241void logp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, 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, level, 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 log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800251{
Harald Welte28222962011-02-18 20:37:04 +0100252 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800253}
254
Harald Welte3ae27582010-03-26 21:24:24 +0800255void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800256{
257 llist_del(&target->entry);
258}
259
Harald Welte3ae27582010-03-26 21:24:24 +0800260void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800261{
Harald Welte3ae27582010-03-26 21:24:24 +0800262 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800263}
264
Harald Welte3ae27582010-03-26 21:24:24 +0800265int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800266{
Harald Welte3ae27582010-03-26 21:24:24 +0800267 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800268 return -EINVAL;
269
Harald Welte3ae27582010-03-26 21:24:24 +0800270 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800271
272 return 0;
273}
274
Harald Welte3ae27582010-03-26 21:24:24 +0800275void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800276{
277 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800278 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800279 else
Harald Welte3ae27582010-03-26 21:24:24 +0800280 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800281}
282
Harald Welte3ae27582010-03-26 21:24:24 +0800283void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800284{
285 target->use_color = use_color;
286}
287
Harald Welte3ae27582010-03-26 21:24:24 +0800288void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800289{
290 target->print_timestamp = print_timestamp;
291}
292
Harald Welte3ae27582010-03-26 21:24:24 +0800293void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800294{
295 target->loglevel = log_level;
296}
297
Harald Welte3ae27582010-03-26 21:24:24 +0800298void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800299 int enable, int level)
300{
Harald Welte4ebdf742010-05-19 19:54:00 +0200301 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800302 return;
303 target->categories[category].enabled = !!enable;
304 target->categories[category].loglevel = level;
305}
306
Harald Welte76e72ab2011-02-17 15:52:39 +0100307static void _file_output(struct log_target *target, unsigned int level,
308 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800309{
Harald Welte0083cd32010-08-25 14:55:44 +0200310 fprintf(target->tgt_file.out, "%s", log);
311 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800312}
313
Harald Welte3ae27582010-03-26 21:24:24 +0800314struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800315{
Harald Welte3ae27582010-03-26 21:24:24 +0800316 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800317 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800318
Harald Welte3ae27582010-03-26 21:24:24 +0800319 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800320 if (!target)
321 return NULL;
322
323 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800324
325 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200326 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800327 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200328 cat->enabled = osmo_log_info->cat[i].enabled;
329 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800330 }
331
332 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800333 target->use_color = 1;
334 target->print_timestamp = 0;
Harald Weltecc6313c2010-03-26 22:04:03 +0800335
336 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800337 target->loglevel = 0;
338 return target;
339}
340
Harald Welte3ae27582010-03-26 21:24:24 +0800341struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800342{
Harald Weltea3b844c2010-03-27 00:04:40 +0800343/* since C89/C99 says stderr is a macro, we can safely do this! */
344#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800345 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800346
Harald Welte3ae27582010-03-26 21:24:24 +0800347 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800348 if (!target)
349 return NULL;
350
Harald Welte28222962011-02-18 20:37:04 +0100351 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200352 target->tgt_file.out = stderr;
353 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800354 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800355#else
356 return NULL;
357#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800358}
359
Harald Welte3086c392010-08-25 19:10:50 +0200360struct log_target *log_target_create_file(const char *fname)
361{
362 struct log_target *target;
363
364 target = log_target_create();
365 if (!target)
366 return NULL;
367
Harald Welte28222962011-02-18 20:37:04 +0100368 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200369 target->tgt_file.out = fopen(fname, "a");
370 if (!target->tgt_file.out)
371 return NULL;
372
373 target->output = _file_output;
374
375 target->tgt_file.fname = talloc_strdup(target, fname);
376
377 return target;
378}
379
Harald Welte28222962011-02-18 20:37:04 +0100380struct log_target *log_target_find(int type, const char *fname)
381{
382 struct log_target *tgt;
383
384 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
385 if (tgt->type != type)
386 continue;
387 if (tgt->type == LOG_TGT_TYPE_FILE) {
388 if (!strcmp(fname, tgt->tgt_file.fname))
389 return tgt;
390 } else
391 return tgt;
392 }
393 return NULL;
394}
395
Harald Welte3086c392010-08-25 19:10:50 +0200396void log_target_destroy(struct log_target *target)
397{
398
399 /* just in case, to make sure we don't have any references */
400 log_del_target(target);
401
402 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200403/* since C89/C99 says stderr is a macro, we can safely do this! */
404#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200405 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200406 if (target->tgt_file.out != stderr)
407#endif
408 {
Harald Welte3086c392010-08-25 19:10:50 +0200409 fclose(target->tgt_file.out);
410 target->tgt_file.out = NULL;
411 }
412 }
413
414 talloc_free(target);
415}
416
417/* close and re-open a log file (for log file rotation) */
418int log_target_file_reopen(struct log_target *target)
419{
420 fclose(target->tgt_file.out);
421
422 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
423 if (!target->tgt_file.out)
424 return -errno;
425
426 /* we assume target->output already to be set */
427
428 return 0;
429}
430
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100431/* This generates the logging command string for VTY. */
432const char *log_vty_command_string(const struct log_info *info)
Harald Welte7638af92010-05-11 16:39:22 +0200433{
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100434 int len = 0, offset = 0, ret, i, rem;
435 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200436 char *str;
437
438 for (i = 0; i < info->num_cat; i++)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100439 size += strlen(info->cat[i].name) + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200440
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100441 for (i = 0; i < LOGLEVEL_DEFS; i++)
442 size += strlen(loglevel_strs[i].str) + 1;
443
444 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200445 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200446 if (!str)
447 return NULL;
448
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200449 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100450 if (ret < 0)
451 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200452 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200453
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100454 for (i = 0; i < info->num_cat; i++) {
455 int j, name_len = strlen(info->cat[i].name)+1;
456 char name[name_len];
457
458 for (j = 0; j < name_len; j++)
459 name[j] = tolower(info->cat[i].name[j]);
460
461 name[name_len-1] = '\0';
462 ret = snprintf(str + offset, rem, "%s|", name+1);
463 if (ret < 0)
464 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200465 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100466 }
467 offset--; /* to remove the trailing | */
468 rem++;
469
470 ret = snprintf(str + offset, rem, ") (");
471 if (ret < 0)
472 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200473 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100474
475 for (i = 0; i < LOGLEVEL_DEFS; i++) {
476 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
477 char loglevel_str[loglevel_str_len];
478
479 for (j = 0; j < loglevel_str_len; j++)
480 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
481
482 loglevel_str[loglevel_str_len-1] = '\0';
483 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
484 if (ret < 0)
485 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200486 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100487 }
488 offset--; /* to remove the trailing | */
489 rem++;
490
491 ret = snprintf(str + offset, rem, ")");
492 if (ret < 0)
493 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200494 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100495err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200496 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100497 return str;
498}
499
500/* This generates the logging command description for VTY. */
501const char *log_vty_command_description(const struct log_info *info)
502{
503 char *str;
504 int i, ret, len = 0, offset = 0, rem;
505 unsigned int size =
506 strlen(LOGGING_STR
507 "Set the log level for a specified category\n") + 1;
508
509 for (i = 0; i < info->num_cat; i++)
510 size += strlen(info->cat[i].description) + 1;
511
512 for (i = 0; i < LOGLEVEL_DEFS; i++)
513 size += strlen(loglevel_descriptions[i]) + 1;
514
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200515 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100516 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200517 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100518 if (!str)
519 return NULL;
520
521 ret = snprintf(str + offset, rem, LOGGING_STR
522 "Set the log level for a specified category\n");
523 if (ret < 0)
524 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200525 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100526
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200527 ret = snprintf(str + offset, rem,
528 "Global setting for all subsystems\n");
529 if (ret < 0)
530 goto err;
531 OSMO_SNPRINTF_RET(ret, rem, offset, len);
532
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100533 for (i = 0; i < info->num_cat; i++) {
534 ret = snprintf(str + offset, rem, "%s\n",
535 info->cat[i].description);
536 if (ret < 0)
537 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200538 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100539 }
540 for (i = 0; i < LOGLEVEL_DEFS; i++) {
541 ret = snprintf(str + offset, rem, "%s\n",
542 loglevel_descriptions[i]);
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 +0100546 }
547err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200548 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200549 return str;
550}
551
Harald Welte3ae27582010-03-26 21:24:24 +0800552void log_init(const struct log_info *cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800553{
Harald Welte3ae27582010-03-26 21:24:24 +0800554 tall_log_ctx = talloc_named_const(NULL, 1, "logging");
Harald Welte4ebdf742010-05-19 19:54:00 +0200555 osmo_log_info = cat;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800556}