blob: 6aad6e15b61405e9fba4c02e11da8f472e79ce3e [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 },
Pablo Neira Ayuso199f3772011-07-07 19:46:38 +020075 [INT2IDX(DINP)] = {
76 .name = "DINP",
77 .description = "A-bis Intput Subsystem",
78 .loglevel = LOGL_NOTICE,
79 .enabled = 1,
80 },
81 [INT2IDX(DMUX)] = {
82 .name = "DMUX",
83 .description = "A-bis B-Subchannel TRAU Frame Multiplex",
84 .loglevel = LOGL_NOTICE,
85 .enabled = 1,
86 },
87 [INT2IDX(DMI)] = {
88 .name = "DMI",
89 .description = "A-bis Input Driver for Signalling",
90 .enabled = 0, .loglevel = LOGL_NOTICE,
91 },
92 [INT2IDX(DMIB)] = {
93 .name = "DMIB",
94 .description = "A-bis Input Driver for B-Channels (voice)",
95 .enabled = 0, .loglevel = LOGL_NOTICE,
96 },
97 [INT2IDX(DRSL)] = {
98 .name = "DRSL",
99 .description = "A-bis Radio Siganlling Link (RSL)",
100 .color = "\033[1;35m",
101 .enabled = 1, .loglevel = LOGL_NOTICE,
102 },
103 [INT2IDX(DNM)] = {
104 .name = "DNM",
105 .description = "A-bis Network Management / O&M (NM/OML)",
106 .color = "\033[1;36m",
107 .enabled = 1, .loglevel = LOGL_INFO,
108 },
Harald Welteb43bc042011-06-27 10:29:17 +0200109};
110
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100111/* You have to keep this in sync with the structure loglevel_strs. */
112const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
113 "Log simply everything",
114 "Log debug messages and higher levels",
115 "Log informational messages and higher levels",
116 "Log noticable messages and higher levels",
117 "Log error messages and higher levels",
118 "Log only fatal messages",
119 NULL,
120};
121
Harald Welteb43bc042011-06-27 10:29:17 +0200122/* special magic for negative (library-internal) log subsystem numbers */
123static int subsys_lib2index(int subsys)
124{
125 return (subsys * -1) + (osmo_log_info->num_cat_user-1);
126}
127
Harald Welte3ae27582010-03-26 21:24:24 +0800128int log_parse_level(const char *lvl)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800129{
130 return get_string_value(loglevel_strs, lvl);
131}
132
Harald Welte9ac22252010-05-11 11:19:40 +0200133const char *log_level_str(unsigned int lvl)
134{
135 return get_value_string(loglevel_strs, lvl);
136}
137
Harald Welte3ae27582010-03-26 21:24:24 +0800138int log_parse_category(const char *category)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800139{
140 int i;
141
Harald Welte4ebdf742010-05-19 19:54:00 +0200142 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welteb43bc042011-06-27 10:29:17 +0200143 if (osmo_log_info->cat[i].name == NULL)
144 continue;
Harald Welte4ebdf742010-05-19 19:54:00 +0200145 if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
Harald Weltefaadfe22010-03-26 21:05:43 +0800146 return i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800147 }
148
149 return -EINVAL;
150}
151
152/*
153 * Parse the category mask.
154 * The format can be this: category1:category2:category3
155 * or category1,2:category2,3:...
156 */
Harald Welte3ae27582010-03-26 21:24:24 +0800157void log_parse_category_mask(struct log_target* target, const char *_mask)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800158{
159 int i = 0;
160 char *mask = strdup(_mask);
161 char *category_token = NULL;
162
163 /* Disable everything to enable it afterwards */
Harald Welteb43bc042011-06-27 10:29:17 +0200164 for (i = 0; i < osmo_log_info->num_cat; ++i)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800165 target->categories[i].enabled = 0;
166
167 category_token = strtok(mask, ":");
168 do {
Harald Welte4ebdf742010-05-19 19:54:00 +0200169 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800170 char* colon = strstr(category_token, ",");
171 int length = strlen(category_token);
172
Harald Welteb43bc042011-06-27 10:29:17 +0200173 if (!osmo_log_info->cat[i].name)
174 continue;
175
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800176 if (colon)
177 length = colon - category_token;
178
Harald Welte4ebdf742010-05-19 19:54:00 +0200179 if (strncasecmp(osmo_log_info->cat[i].name,
180 category_token, length) == 0) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800181 int level = 0;
182
183 if (colon)
184 level = atoi(colon+1);
185
Harald Weltefaadfe22010-03-26 21:05:43 +0800186 target->categories[i].enabled = 1;
187 target->categories[i].loglevel = level;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800188 }
189 }
190 } while ((category_token = strtok(NULL, ":")));
191
192 free(mask);
193}
194
195static const char* color(int subsys)
196{
Harald Welte4ebdf742010-05-19 19:54:00 +0200197 if (subsys < osmo_log_info->num_cat)
198 return osmo_log_info->cat[subsys].color;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800199
Harald Welted788f662010-03-26 09:45:03 +0800200 return NULL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800201}
202
Harald Welte3ae27582010-03-26 21:24:24 +0800203static void _output(struct log_target *target, unsigned int subsys,
Harald Welte76e72ab2011-02-17 15:52:39 +0100204 unsigned int level, char *file, int line, int cont,
205 const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800206{
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800207 char buf[4096];
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200208 int ret, len = 0, offset = 0, rem = sizeof(buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800209
210 /* are we using color */
211 if (target->use_color) {
Harald Welted788f662010-03-26 09:45:03 +0800212 const char *c = color(subsys);
213 if (c) {
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200214 ret = snprintf(buf + offset, rem, "%s", color(subsys));
215 if (ret < 0)
216 goto err;
217 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welted788f662010-03-26 09:45:03 +0800218 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800219 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800220 if (!cont) {
221 if (target->print_timestamp) {
222 char *timestr;
223 time_t tm;
224 tm = time(NULL);
225 timestr = ctime(&tm);
226 timestr[strlen(timestr)-1] = '\0';
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200227 ret = snprintf(buf + offset, rem, "%s ", timestr);
228 if (ret < 0)
229 goto err;
230 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800231 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200232 ret = snprintf(buf + offset, rem, "<%4.4x> %s:%d ",
233 subsys, file, line);
234 if (ret < 0)
235 goto err;
236 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800237 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200238 ret = vsnprintf(buf + offset, rem, format, ap);
239 if (ret < 0)
240 goto err;
241 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800242
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200243 ret = snprintf(buf + offset, rem, "%s",
244 target->use_color ? "\033[0;m" : "");
245 if (ret < 0)
246 goto err;
247 OSMO_SNPRINTF_RET(ret, rem, offset, len);
248err:
249 buf[sizeof(buf)-1] = '\0';
250 target->output(target, level, buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800251}
252
Harald Welteb43bc042011-06-27 10:29:17 +0200253static void _logp(int subsys, int level, char *file, int line,
Harald Welte3ae27582010-03-26 21:24:24 +0800254 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800255{
Harald Welte3ae27582010-03-26 21:24:24 +0800256 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800257
Harald Welteb43bc042011-06-27 10:29:17 +0200258 if (subsys < 0)
259 subsys = subsys_lib2index(subsys);
260
261 if (subsys > osmo_log_info->num_cat)
262 subsys = DLGLOBAL;
263
Harald Welte28222962011-02-18 20:37:04 +0100264 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Harald Welte3ae27582010-03-26 21:24:24 +0800265 struct log_category *category;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800266 int output = 0;
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200267 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800268
269 category = &tar->categories[subsys];
Harald Welte3ae27582010-03-26 21:24:24 +0800270 /* subsystem is not supposed to be logged */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800271 if (!category->enabled)
272 continue;
273
274 /* Check the global log level */
275 if (tar->loglevel != 0 && level < tar->loglevel)
276 continue;
277
278 /* Check the category log level */
279 if (tar->loglevel == 0 && category->loglevel != 0 &&
280 level < category->loglevel)
281 continue;
282
283 /* Apply filters here... if that becomes messy we will
284 * need to put filters in a list and each filter will
285 * say stop, continue, output */
Harald Welte3ae27582010-03-26 21:24:24 +0800286 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800287 output = 1;
Harald Welte4ebdf742010-05-19 19:54:00 +0200288 else if (osmo_log_info->filter_fn)
289 output = osmo_log_info->filter_fn(&log_context,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800290 tar);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200291 if (!output)
292 continue;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800293
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200294 /* According to the manpage, vsnprintf leaves the value of ap
295 * in undefined state. Since _output uses vsnprintf and it may
296 * be called several times, we have to pass a copy of ap. */
297 va_copy(bp, ap);
Harald Welteda127cb2011-07-02 21:51:32 +0200298 _output(tar, subsys, level, file, line, cont, format, bp);
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200299 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800300 }
301}
302
Harald Welteb43bc042011-06-27 10:29:17 +0200303void logp(int subsys, char *file, int line, int cont,
Harald Welte3ae27582010-03-26 21:24:24 +0800304 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800305{
306 va_list ap;
307
308 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800309 _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800310 va_end(ap);
311}
312
Harald Welteb43bc042011-06-27 10:29:17 +0200313void logp2(int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800314{
315 va_list ap;
316
317 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800318 _logp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800319 va_end(ap);
320}
321
Harald Welte3ae27582010-03-26 21:24:24 +0800322void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800323{
Harald Welte28222962011-02-18 20:37:04 +0100324 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800325}
326
Harald Welte3ae27582010-03-26 21:24:24 +0800327void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800328{
329 llist_del(&target->entry);
330}
331
Harald Welte3ae27582010-03-26 21:24:24 +0800332void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800333{
Harald Welte3ae27582010-03-26 21:24:24 +0800334 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800335}
336
Harald Welte3ae27582010-03-26 21:24:24 +0800337int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800338{
Harald Welte3ae27582010-03-26 21:24:24 +0800339 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800340 return -EINVAL;
341
Harald Welte3ae27582010-03-26 21:24:24 +0800342 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800343
344 return 0;
345}
346
Harald Welte3ae27582010-03-26 21:24:24 +0800347void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800348{
349 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800350 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800351 else
Harald Welte3ae27582010-03-26 21:24:24 +0800352 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800353}
354
Harald Welte3ae27582010-03-26 21:24:24 +0800355void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800356{
357 target->use_color = use_color;
358}
359
Harald Welte3ae27582010-03-26 21:24:24 +0800360void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800361{
362 target->print_timestamp = print_timestamp;
363}
364
Harald Welte3ae27582010-03-26 21:24:24 +0800365void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800366{
367 target->loglevel = log_level;
368}
369
Harald Welte3ae27582010-03-26 21:24:24 +0800370void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800371 int enable, int level)
372{
Harald Welte4ebdf742010-05-19 19:54:00 +0200373 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800374 return;
375 target->categories[category].enabled = !!enable;
376 target->categories[category].loglevel = level;
377}
378
Harald Welte76e72ab2011-02-17 15:52:39 +0100379static void _file_output(struct log_target *target, unsigned int level,
380 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800381{
Harald Welte0083cd32010-08-25 14:55:44 +0200382 fprintf(target->tgt_file.out, "%s", log);
383 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800384}
385
Harald Welte3ae27582010-03-26 21:24:24 +0800386struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800387{
Harald Welte3ae27582010-03-26 21:24:24 +0800388 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800389 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800390
Harald Welte3ae27582010-03-26 21:24:24 +0800391 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800392 if (!target)
393 return NULL;
394
Harald Welteb43bc042011-06-27 10:29:17 +0200395 target->categories = talloc_zero_array(target,
396 struct log_category,
397 osmo_log_info->num_cat);
398 if (!target->categories) {
399 talloc_free(target);
400 return NULL;
401 }
402
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800403 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800404
405 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200406 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800407 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200408 cat->enabled = osmo_log_info->cat[i].enabled;
409 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800410 }
411
412 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800413 target->use_color = 1;
414 target->print_timestamp = 0;
Harald Weltecc6313c2010-03-26 22:04:03 +0800415
416 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800417 target->loglevel = 0;
418 return target;
419}
420
Harald Welte3ae27582010-03-26 21:24:24 +0800421struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800422{
Harald Weltea3b844c2010-03-27 00:04:40 +0800423/* since C89/C99 says stderr is a macro, we can safely do this! */
424#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800425 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800426
Harald Welte3ae27582010-03-26 21:24:24 +0800427 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800428 if (!target)
429 return NULL;
430
Harald Welte28222962011-02-18 20:37:04 +0100431 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200432 target->tgt_file.out = stderr;
433 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800434 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800435#else
436 return NULL;
437#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800438}
439
Harald Welte3086c392010-08-25 19:10:50 +0200440struct log_target *log_target_create_file(const char *fname)
441{
442 struct log_target *target;
443
444 target = log_target_create();
445 if (!target)
446 return NULL;
447
Harald Welte28222962011-02-18 20:37:04 +0100448 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200449 target->tgt_file.out = fopen(fname, "a");
450 if (!target->tgt_file.out)
451 return NULL;
452
453 target->output = _file_output;
454
455 target->tgt_file.fname = talloc_strdup(target, fname);
456
457 return target;
458}
459
Harald Welte28222962011-02-18 20:37:04 +0100460struct log_target *log_target_find(int type, const char *fname)
461{
462 struct log_target *tgt;
463
464 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
465 if (tgt->type != type)
466 continue;
467 if (tgt->type == LOG_TGT_TYPE_FILE) {
468 if (!strcmp(fname, tgt->tgt_file.fname))
469 return tgt;
470 } else
471 return tgt;
472 }
473 return NULL;
474}
475
Harald Welte3086c392010-08-25 19:10:50 +0200476void log_target_destroy(struct log_target *target)
477{
478
479 /* just in case, to make sure we don't have any references */
480 log_del_target(target);
481
482 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200483/* since C89/C99 says stderr is a macro, we can safely do this! */
484#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200485 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200486 if (target->tgt_file.out != stderr)
487#endif
488 {
Harald Welte3086c392010-08-25 19:10:50 +0200489 fclose(target->tgt_file.out);
490 target->tgt_file.out = NULL;
491 }
492 }
493
494 talloc_free(target);
495}
496
497/* close and re-open a log file (for log file rotation) */
498int log_target_file_reopen(struct log_target *target)
499{
500 fclose(target->tgt_file.out);
501
502 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
503 if (!target->tgt_file.out)
504 return -errno;
505
506 /* we assume target->output already to be set */
507
508 return 0;
509}
510
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100511/* This generates the logging command string for VTY. */
Harald Weltece9fec32011-06-27 14:19:16 +0200512const char *log_vty_command_string(const struct log_info *unused_info)
Harald Welte7638af92010-05-11 16:39:22 +0200513{
Harald Weltece9fec32011-06-27 14:19:16 +0200514 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100515 int len = 0, offset = 0, ret, i, rem;
516 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200517 char *str;
518
Harald Welteb43bc042011-06-27 10:29:17 +0200519 for (i = 0; i < info->num_cat; i++) {
520 if (info->cat[i].name == NULL)
521 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100522 size += strlen(info->cat[i].name) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200523 }
Harald Welte7638af92010-05-11 16:39:22 +0200524
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100525 for (i = 0; i < LOGLEVEL_DEFS; i++)
526 size += strlen(loglevel_strs[i].str) + 1;
527
528 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200529 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200530 if (!str)
531 return NULL;
532
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200533 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100534 if (ret < 0)
535 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200536 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200537
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100538 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200539 if (info->cat[i].name) {
540 int j, name_len = strlen(info->cat[i].name)+1;
541 char name[name_len];
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100542
Harald Welteb43bc042011-06-27 10:29:17 +0200543 for (j = 0; j < name_len; j++)
544 name[j] = tolower(info->cat[i].name[j]);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100545
Harald Welteb43bc042011-06-27 10:29:17 +0200546 name[name_len-1] = '\0';
547 ret = snprintf(str + offset, rem, "%s|", name+1);
548 if (ret < 0)
549 goto err;
550 OSMO_SNPRINTF_RET(ret, rem, offset, len);
551 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100552 }
553 offset--; /* to remove the trailing | */
554 rem++;
555
556 ret = snprintf(str + offset, rem, ") (");
557 if (ret < 0)
558 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200559 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100560
561 for (i = 0; i < LOGLEVEL_DEFS; i++) {
562 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
563 char loglevel_str[loglevel_str_len];
564
565 for (j = 0; j < loglevel_str_len; j++)
566 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
567
568 loglevel_str[loglevel_str_len-1] = '\0';
569 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
570 if (ret < 0)
571 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200572 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100573 }
574 offset--; /* to remove the trailing | */
575 rem++;
576
577 ret = snprintf(str + offset, rem, ")");
578 if (ret < 0)
579 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200580 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100581err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200582 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100583 return str;
584}
585
586/* This generates the logging command description for VTY. */
Harald Weltece9fec32011-06-27 14:19:16 +0200587const char *log_vty_command_description(const struct log_info *unused_info)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100588{
Harald Weltece9fec32011-06-27 14:19:16 +0200589 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100590 char *str;
591 int i, ret, len = 0, offset = 0, rem;
592 unsigned int size =
593 strlen(LOGGING_STR
594 "Set the log level for a specified category\n") + 1;
595
Harald Welteb43bc042011-06-27 10:29:17 +0200596 for (i = 0; i < info->num_cat; i++) {
597 if (info->cat[i].name == NULL)
598 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100599 size += strlen(info->cat[i].description) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200600 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100601
602 for (i = 0; i < LOGLEVEL_DEFS; i++)
603 size += strlen(loglevel_descriptions[i]) + 1;
604
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200605 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100606 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200607 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100608 if (!str)
609 return NULL;
610
611 ret = snprintf(str + offset, rem, LOGGING_STR
612 "Set the log level for a specified category\n");
613 if (ret < 0)
614 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200615 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100616
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200617 ret = snprintf(str + offset, rem,
618 "Global setting for all subsystems\n");
619 if (ret < 0)
620 goto err;
621 OSMO_SNPRINTF_RET(ret, rem, offset, len);
622
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100623 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200624 if (info->cat[i].name == NULL)
625 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100626 ret = snprintf(str + offset, rem, "%s\n",
627 info->cat[i].description);
628 if (ret < 0)
629 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200630 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100631 }
632 for (i = 0; i < LOGLEVEL_DEFS; i++) {
633 ret = snprintf(str + offset, rem, "%s\n",
634 loglevel_descriptions[i]);
635 if (ret < 0)
636 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200637 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100638 }
639err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200640 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200641 return str;
642}
643
Harald Welteb43bc042011-06-27 10:29:17 +0200644int log_init(const struct log_info *inf, void *ctx)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800645{
Harald Welteb43bc042011-06-27 10:29:17 +0200646 int i;
647
648 tall_log_ctx = talloc_named_const(ctx, 1, "logging");
649 if (!tall_log_ctx)
650 return -ENOMEM;
651
652 osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
653 if (!osmo_log_info)
654 return -ENOMEM;
655
656 osmo_log_info->num_cat_user = inf->num_cat;
657 /* total number = number of user cat + library cat */
Harald Weltece9fec32011-06-27 14:19:16 +0200658 osmo_log_info->num_cat = inf->num_cat + ARRAY_SIZE(internal_cat);
Harald Welteb43bc042011-06-27 10:29:17 +0200659
660 osmo_log_info->cat = talloc_zero_array(osmo_log_info,
661 struct log_info_cat,
662 osmo_log_info->num_cat);
663 if (!osmo_log_info->cat) {
664 talloc_free(osmo_log_info);
665 osmo_log_info = NULL;
666 return -ENOMEM;
667 }
668
669 /* copy over the user part */
670 for (i = 0; i < inf->num_cat; i++) {
671 memcpy(&osmo_log_info->cat[i], &inf->cat[i],
672 sizeof(struct log_info_cat));
673 }
674
675 /* copy over the library part */
Harald Welte9fe16522011-06-27 14:00:03 +0200676 for (i = 0; i < ARRAY_SIZE(internal_cat); i++) {
Harald Weltece9fec32011-06-27 14:19:16 +0200677 unsigned int cn = osmo_log_info->num_cat_user + i;
678 memcpy(&osmo_log_info->cat[cn],
Harald Welte9fe16522011-06-27 14:00:03 +0200679 &internal_cat[i], sizeof(struct log_info_cat));
680 }
681
682 return 0;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800683}