blob: 3c9dc03f9d15b32bc31396549070b8c30c0e02c1 [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;
Pablo Neira Ayuso82560762011-05-19 08:55:32 +0200201 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800202
203 category = &tar->categories[subsys];
Harald Welte3ae27582010-03-26 21:24:24 +0800204 /* subsystem is not supposed to be logged */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800205 if (!category->enabled)
206 continue;
207
208 /* Check the global log level */
209 if (tar->loglevel != 0 && level < tar->loglevel)
210 continue;
211
212 /* Check the category log level */
213 if (tar->loglevel == 0 && category->loglevel != 0 &&
214 level < category->loglevel)
215 continue;
216
217 /* Apply filters here... if that becomes messy we will
218 * need to put filters in a list and each filter will
219 * say stop, continue, output */
Harald Welte3ae27582010-03-26 21:24:24 +0800220 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800221 output = 1;
Harald Welte4ebdf742010-05-19 19:54:00 +0200222 else if (osmo_log_info->filter_fn)
223 output = osmo_log_info->filter_fn(&log_context,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800224 tar);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200225 if (!output)
226 continue;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800227
Pablo Neira Ayuso82560762011-05-19 08:55:32 +0200228 /* According to the manpage, vsnprintf leaves the value of ap
229 * in undefined state. Since _output uses vsnprintf and it may
230 * be called several times, we have to pass a copy of ap. */
231 va_copy(bp, ap);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200232 _output(tar, subsys, level, file, line, cont, format, ap);
Pablo Neira Ayuso82560762011-05-19 08:55:32 +0200233 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800234 }
235}
236
Harald Welte3ae27582010-03-26 21:24:24 +0800237void logp(unsigned int subsys, char *file, int line, int cont,
238 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800239{
240 va_list ap;
241
242 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800243 _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800244 va_end(ap);
245}
246
Harald Welte3ae27582010-03-26 21:24:24 +0800247void logp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800248{
249 va_list ap;
250
251 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800252 _logp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800253 va_end(ap);
254}
255
Harald Welte3ae27582010-03-26 21:24:24 +0800256void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800257{
Harald Welte28222962011-02-18 20:37:04 +0100258 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800259}
260
Harald Welte3ae27582010-03-26 21:24:24 +0800261void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800262{
263 llist_del(&target->entry);
264}
265
Harald Welte3ae27582010-03-26 21:24:24 +0800266void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800267{
Harald Welte3ae27582010-03-26 21:24:24 +0800268 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800269}
270
Harald Welte3ae27582010-03-26 21:24:24 +0800271int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800272{
Harald Welte3ae27582010-03-26 21:24:24 +0800273 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800274 return -EINVAL;
275
Harald Welte3ae27582010-03-26 21:24:24 +0800276 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800277
278 return 0;
279}
280
Harald Welte3ae27582010-03-26 21:24:24 +0800281void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800282{
283 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800284 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800285 else
Harald Welte3ae27582010-03-26 21:24:24 +0800286 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800287}
288
Harald Welte3ae27582010-03-26 21:24:24 +0800289void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800290{
291 target->use_color = use_color;
292}
293
Harald Welte3ae27582010-03-26 21:24:24 +0800294void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800295{
296 target->print_timestamp = print_timestamp;
297}
298
Harald Welte3ae27582010-03-26 21:24:24 +0800299void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800300{
301 target->loglevel = log_level;
302}
303
Harald Welte3ae27582010-03-26 21:24:24 +0800304void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800305 int enable, int level)
306{
Harald Welte4ebdf742010-05-19 19:54:00 +0200307 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800308 return;
309 target->categories[category].enabled = !!enable;
310 target->categories[category].loglevel = level;
311}
312
Harald Welte76e72ab2011-02-17 15:52:39 +0100313static void _file_output(struct log_target *target, unsigned int level,
314 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800315{
Harald Welte0083cd32010-08-25 14:55:44 +0200316 fprintf(target->tgt_file.out, "%s", log);
317 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800318}
319
Harald Welte3ae27582010-03-26 21:24:24 +0800320struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800321{
Harald Welte3ae27582010-03-26 21:24:24 +0800322 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800323 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800324
Harald Welte3ae27582010-03-26 21:24:24 +0800325 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800326 if (!target)
327 return NULL;
328
329 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800330
331 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200332 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800333 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200334 cat->enabled = osmo_log_info->cat[i].enabled;
335 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800336 }
337
338 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800339 target->use_color = 1;
340 target->print_timestamp = 0;
Harald Weltecc6313c2010-03-26 22:04:03 +0800341
342 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800343 target->loglevel = 0;
344 return target;
345}
346
Harald Welte3ae27582010-03-26 21:24:24 +0800347struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800348{
Harald Weltea3b844c2010-03-27 00:04:40 +0800349/* since C89/C99 says stderr is a macro, we can safely do this! */
350#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800351 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800352
Harald Welte3ae27582010-03-26 21:24:24 +0800353 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800354 if (!target)
355 return NULL;
356
Harald Welte28222962011-02-18 20:37:04 +0100357 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200358 target->tgt_file.out = stderr;
359 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800360 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800361#else
362 return NULL;
363#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800364}
365
Harald Welte3086c392010-08-25 19:10:50 +0200366struct log_target *log_target_create_file(const char *fname)
367{
368 struct log_target *target;
369
370 target = log_target_create();
371 if (!target)
372 return NULL;
373
Harald Welte28222962011-02-18 20:37:04 +0100374 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200375 target->tgt_file.out = fopen(fname, "a");
376 if (!target->tgt_file.out)
377 return NULL;
378
379 target->output = _file_output;
380
381 target->tgt_file.fname = talloc_strdup(target, fname);
382
383 return target;
384}
385
Harald Welte28222962011-02-18 20:37:04 +0100386struct log_target *log_target_find(int type, const char *fname)
387{
388 struct log_target *tgt;
389
390 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
391 if (tgt->type != type)
392 continue;
393 if (tgt->type == LOG_TGT_TYPE_FILE) {
394 if (!strcmp(fname, tgt->tgt_file.fname))
395 return tgt;
396 } else
397 return tgt;
398 }
399 return NULL;
400}
401
Harald Welte3086c392010-08-25 19:10:50 +0200402void log_target_destroy(struct log_target *target)
403{
404
405 /* just in case, to make sure we don't have any references */
406 log_del_target(target);
407
408 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200409/* since C89/C99 says stderr is a macro, we can safely do this! */
410#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200411 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200412 if (target->tgt_file.out != stderr)
413#endif
414 {
Harald Welte3086c392010-08-25 19:10:50 +0200415 fclose(target->tgt_file.out);
416 target->tgt_file.out = NULL;
417 }
418 }
419
420 talloc_free(target);
421}
422
423/* close and re-open a log file (for log file rotation) */
424int log_target_file_reopen(struct log_target *target)
425{
426 fclose(target->tgt_file.out);
427
428 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
429 if (!target->tgt_file.out)
430 return -errno;
431
432 /* we assume target->output already to be set */
433
434 return 0;
435}
436
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100437/* This generates the logging command string for VTY. */
438const char *log_vty_command_string(const struct log_info *info)
Harald Welte7638af92010-05-11 16:39:22 +0200439{
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100440 int len = 0, offset = 0, ret, i, rem;
441 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200442 char *str;
443
444 for (i = 0; i < info->num_cat; i++)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100445 size += strlen(info->cat[i].name) + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200446
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100447 for (i = 0; i < LOGLEVEL_DEFS; i++)
448 size += strlen(loglevel_strs[i].str) + 1;
449
450 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200451 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200452 if (!str)
453 return NULL;
454
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200455 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100456 if (ret < 0)
457 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200458 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200459
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100460 for (i = 0; i < info->num_cat; i++) {
461 int j, name_len = strlen(info->cat[i].name)+1;
462 char name[name_len];
463
464 for (j = 0; j < name_len; j++)
465 name[j] = tolower(info->cat[i].name[j]);
466
467 name[name_len-1] = '\0';
468 ret = snprintf(str + offset, rem, "%s|", name+1);
469 if (ret < 0)
470 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200471 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100472 }
473 offset--; /* to remove the trailing | */
474 rem++;
475
476 ret = snprintf(str + offset, rem, ") (");
477 if (ret < 0)
478 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200479 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100480
481 for (i = 0; i < LOGLEVEL_DEFS; i++) {
482 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
483 char loglevel_str[loglevel_str_len];
484
485 for (j = 0; j < loglevel_str_len; j++)
486 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
487
488 loglevel_str[loglevel_str_len-1] = '\0';
489 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
490 if (ret < 0)
491 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200492 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100493 }
494 offset--; /* to remove the trailing | */
495 rem++;
496
497 ret = snprintf(str + offset, rem, ")");
498 if (ret < 0)
499 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200500 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100501err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200502 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100503 return str;
504}
505
506/* This generates the logging command description for VTY. */
507const char *log_vty_command_description(const struct log_info *info)
508{
509 char *str;
510 int i, ret, len = 0, offset = 0, rem;
511 unsigned int size =
512 strlen(LOGGING_STR
513 "Set the log level for a specified category\n") + 1;
514
515 for (i = 0; i < info->num_cat; i++)
516 size += strlen(info->cat[i].description) + 1;
517
518 for (i = 0; i < LOGLEVEL_DEFS; i++)
519 size += strlen(loglevel_descriptions[i]) + 1;
520
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200521 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100522 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200523 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100524 if (!str)
525 return NULL;
526
527 ret = snprintf(str + offset, rem, LOGGING_STR
528 "Set the log level for a specified category\n");
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
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200533 ret = snprintf(str + offset, rem,
534 "Global setting for all subsystems\n");
535 if (ret < 0)
536 goto err;
537 OSMO_SNPRINTF_RET(ret, rem, offset, len);
538
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100539 for (i = 0; i < info->num_cat; i++) {
540 ret = snprintf(str + offset, rem, "%s\n",
541 info->cat[i].description);
542 if (ret < 0)
543 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200544 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100545 }
546 for (i = 0; i < LOGLEVEL_DEFS; i++) {
547 ret = snprintf(str + offset, rem, "%s\n",
548 loglevel_descriptions[i]);
549 if (ret < 0)
550 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200551 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100552 }
553err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200554 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200555 return str;
556}
557
Harald Welte3ae27582010-03-26 21:24:24 +0800558void log_init(const struct log_info *cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800559{
Harald Welte3ae27582010-03-26 21:24:24 +0800560 tall_log_ctx = talloc_named_const(NULL, 1, "logging");
Harald Welte4ebdf742010-05-19 19:54:00 +0200561 osmo_log_info = cat;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800562}