blob: 11d63ac98c4542e141fb523084a67f0d6b626dd8 [file] [log] [blame]
Harald Welte4a2bb9e2010-03-26 09:33:40 +08001/* Debugging/Logging support code */
2
3/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
Harald Welte01fd5cb2010-03-26 23:51:31 +080023#include "../config.h"
24
Harald Welte4a2bb9e2010-03-26 09:33:40 +080025#include <stdarg.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010029#include <ctype.h>
Harald Welte01fd5cb2010-03-26 23:51:31 +080030
31#ifdef HAVE_STRINGS_H
Harald Welte4a2bb9e2010-03-26 09:33:40 +080032#include <strings.h>
Harald Welte01fd5cb2010-03-26 23:51:31 +080033#endif
Harald Welte4a2bb9e2010-03-26 09:33:40 +080034#include <time.h>
35#include <errno.h>
36
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010037#include <osmocom/core/talloc.h>
38#include <osmocom/core/utils.h>
39#include <osmocom/core/logging.h>
Harald Welte4a2bb9e2010-03-26 09:33:40 +080040
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010041#include <osmocom/vty/logging.h> /* for LOGGING_STR. */
42
Harald Welteb43bc042011-06-27 10:29:17 +020043struct log_info *osmo_log_info;
Harald Welte4a2bb9e2010-03-26 09:33:40 +080044
Harald Welte3ae27582010-03-26 21:24:24 +080045static struct log_context log_context;
46static void *tall_log_ctx = NULL;
Harald Welte28222962011-02-18 20:37:04 +010047LLIST_HEAD(osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +080048
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010049#define LOGLEVEL_DEFS 6 /* Number of loglevels.*/
50
51static const struct value_string loglevel_strs[LOGLEVEL_DEFS+1] = {
Harald Welte4a2bb9e2010-03-26 09:33:40 +080052 { 0, "EVERYTHING" },
53 { LOGL_DEBUG, "DEBUG" },
54 { LOGL_INFO, "INFO" },
55 { LOGL_NOTICE, "NOTICE" },
56 { LOGL_ERROR, "ERROR" },
57 { LOGL_FATAL, "FATAL" },
58 { 0, NULL },
59};
60
Harald Welteb43bc042011-06-27 10:29:17 +020061#define INT2IDX(x) (-1*(x)-1)
62static const struct log_info_cat internal_cat[OSMO_NUM_DLIB] = {
63 [INT2IDX(DLGLOBAL)] = { /* -1 becomes 0 */
64 .name = "DLGLOBAL",
65 .description = "Library-internal global log family",
66 .loglevel = LOGL_NOTICE,
67 .enabled = 1,
68 },
Harald Welte1f0b8c22011-06-27 10:51:37 +020069 [INT2IDX(DLLAPDM)] = { /* -2 becomes 1 */
70 .name = "DLLAPDM",
71 .description = "LAPDm in libosmogsm",
72 .loglevel = LOGL_NOTICE,
73 .enabled = 1,
74 },
Harald Welte892e6212011-07-19 14:31:44 +020075 [INT2IDX(DLINP)] = {
Harald Welte087e1132011-07-29 11:43:39 +020076 .name = "DLINP",
Pablo Neira Ayuso199f3772011-07-07 19:46:38 +020077 .description = "A-bis Intput Subsystem",
78 .loglevel = LOGL_NOTICE,
79 .enabled = 1,
80 },
Harald Welte892e6212011-07-19 14:31:44 +020081 [INT2IDX(DLMUX)] = {
Harald Welte087e1132011-07-29 11:43:39 +020082 .name = "DLMUX",
Pablo Neira Ayuso199f3772011-07-07 19:46:38 +020083 .description = "A-bis B-Subchannel TRAU Frame Multiplex",
84 .loglevel = LOGL_NOTICE,
85 .enabled = 1,
86 },
Harald Welte892e6212011-07-19 14:31:44 +020087 [INT2IDX(DLMI)] = {
Harald Welte087e1132011-07-29 11:43:39 +020088 .name = "DLMI",
Pablo Neira Ayuso199f3772011-07-07 19:46:38 +020089 .description = "A-bis Input Driver for Signalling",
90 .enabled = 0, .loglevel = LOGL_NOTICE,
91 },
Harald Welte892e6212011-07-19 14:31:44 +020092 [INT2IDX(DLMIB)] = {
Harald Welte087e1132011-07-29 11:43:39 +020093 .name = "DLMIB",
Pablo Neira Ayuso199f3772011-07-07 19:46:38 +020094 .description = "A-bis Input Driver for B-Channels (voice)",
95 .enabled = 0, .loglevel = LOGL_NOTICE,
96 },
Harald Welteb43bc042011-06-27 10:29:17 +020097};
98
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +010099/* You have to keep this in sync with the structure loglevel_strs. */
100const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
101 "Log simply everything",
102 "Log debug messages and higher levels",
103 "Log informational messages and higher levels",
104 "Log noticable messages and higher levels",
105 "Log error messages and higher levels",
106 "Log only fatal messages",
107 NULL,
108};
109
Harald Welteb43bc042011-06-27 10:29:17 +0200110/* special magic for negative (library-internal) log subsystem numbers */
111static int subsys_lib2index(int subsys)
112{
113 return (subsys * -1) + (osmo_log_info->num_cat_user-1);
114}
115
Harald Welte3ae27582010-03-26 21:24:24 +0800116int log_parse_level(const char *lvl)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800117{
118 return get_string_value(loglevel_strs, lvl);
119}
120
Harald Welte9ac22252010-05-11 11:19:40 +0200121const char *log_level_str(unsigned int lvl)
122{
123 return get_value_string(loglevel_strs, lvl);
124}
125
Harald Welte3ae27582010-03-26 21:24:24 +0800126int log_parse_category(const char *category)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800127{
128 int i;
129
Harald Welte4ebdf742010-05-19 19:54:00 +0200130 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welteb43bc042011-06-27 10:29:17 +0200131 if (osmo_log_info->cat[i].name == NULL)
132 continue;
Harald Welte4ebdf742010-05-19 19:54:00 +0200133 if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
Harald Weltefaadfe22010-03-26 21:05:43 +0800134 return i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800135 }
136
137 return -EINVAL;
138}
139
140/*
141 * Parse the category mask.
142 * The format can be this: category1:category2:category3
143 * or category1,2:category2,3:...
144 */
Harald Welte3ae27582010-03-26 21:24:24 +0800145void log_parse_category_mask(struct log_target* target, const char *_mask)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800146{
147 int i = 0;
148 char *mask = strdup(_mask);
149 char *category_token = NULL;
150
151 /* Disable everything to enable it afterwards */
Harald Welteb43bc042011-06-27 10:29:17 +0200152 for (i = 0; i < osmo_log_info->num_cat; ++i)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800153 target->categories[i].enabled = 0;
154
155 category_token = strtok(mask, ":");
156 do {
Harald Welte4ebdf742010-05-19 19:54:00 +0200157 for (i = 0; i < osmo_log_info->num_cat; ++i) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800158 char* colon = strstr(category_token, ",");
159 int length = strlen(category_token);
160
Harald Welteb43bc042011-06-27 10:29:17 +0200161 if (!osmo_log_info->cat[i].name)
162 continue;
163
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800164 if (colon)
165 length = colon - category_token;
166
Harald Welte4ebdf742010-05-19 19:54:00 +0200167 if (strncasecmp(osmo_log_info->cat[i].name,
168 category_token, length) == 0) {
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800169 int level = 0;
170
171 if (colon)
172 level = atoi(colon+1);
173
Harald Weltefaadfe22010-03-26 21:05:43 +0800174 target->categories[i].enabled = 1;
175 target->categories[i].loglevel = level;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800176 }
177 }
178 } while ((category_token = strtok(NULL, ":")));
179
180 free(mask);
181}
182
183static const char* color(int subsys)
184{
Harald Welte4ebdf742010-05-19 19:54:00 +0200185 if (subsys < osmo_log_info->num_cat)
186 return osmo_log_info->cat[subsys].color;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800187
Harald Welted788f662010-03-26 09:45:03 +0800188 return NULL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800189}
190
Harald Welte3ae27582010-03-26 21:24:24 +0800191static void _output(struct log_target *target, unsigned int subsys,
Harald Welte76e72ab2011-02-17 15:52:39 +0100192 unsigned int level, char *file, int line, int cont,
193 const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800194{
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800195 char buf[4096];
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200196 int ret, len = 0, offset = 0, rem = sizeof(buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800197
198 /* are we using color */
199 if (target->use_color) {
Harald Welted788f662010-03-26 09:45:03 +0800200 const char *c = color(subsys);
201 if (c) {
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200202 ret = snprintf(buf + offset, rem, "%s", color(subsys));
203 if (ret < 0)
204 goto err;
205 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welted788f662010-03-26 09:45:03 +0800206 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800207 }
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800208 if (!cont) {
209 if (target->print_timestamp) {
210 char *timestr;
211 time_t tm;
212 tm = time(NULL);
213 timestr = ctime(&tm);
214 timestr[strlen(timestr)-1] = '\0';
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200215 ret = snprintf(buf + offset, rem, "%s ", timestr);
216 if (ret < 0)
217 goto err;
218 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800219 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200220 ret = snprintf(buf + offset, rem, "<%4.4x> %s:%d ",
221 subsys, file, line);
222 if (ret < 0)
223 goto err;
224 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800225 }
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200226 ret = vsnprintf(buf + offset, rem, format, ap);
227 if (ret < 0)
228 goto err;
229 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800230
Pablo Neira Ayuso7503fb82011-05-03 22:32:43 +0200231 ret = snprintf(buf + offset, rem, "%s",
232 target->use_color ? "\033[0;m" : "");
233 if (ret < 0)
234 goto err;
235 OSMO_SNPRINTF_RET(ret, rem, offset, len);
236err:
237 buf[sizeof(buf)-1] = '\0';
238 target->output(target, level, buf);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800239}
240
Harald Welteb43bc042011-06-27 10:29:17 +0200241static void _logp(int subsys, int level, char *file, int line,
Harald Welte3ae27582010-03-26 21:24:24 +0800242 int cont, const char *format, va_list ap)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800243{
Harald Welte3ae27582010-03-26 21:24:24 +0800244 struct log_target *tar;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800245
Harald Welteb43bc042011-06-27 10:29:17 +0200246 if (subsys < 0)
247 subsys = subsys_lib2index(subsys);
248
249 if (subsys > osmo_log_info->num_cat)
250 subsys = DLGLOBAL;
251
Harald Welte28222962011-02-18 20:37:04 +0100252 llist_for_each_entry(tar, &osmo_log_target_list, entry) {
Harald Welte3ae27582010-03-26 21:24:24 +0800253 struct log_category *category;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800254 int output = 0;
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200255 va_list bp;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800256
257 category = &tar->categories[subsys];
Harald Welte3ae27582010-03-26 21:24:24 +0800258 /* subsystem is not supposed to be logged */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800259 if (!category->enabled)
260 continue;
261
262 /* Check the global log level */
263 if (tar->loglevel != 0 && level < tar->loglevel)
264 continue;
265
266 /* Check the category log level */
267 if (tar->loglevel == 0 && category->loglevel != 0 &&
268 level < category->loglevel)
269 continue;
270
271 /* Apply filters here... if that becomes messy we will
272 * need to put filters in a list and each filter will
273 * say stop, continue, output */
Harald Welte3ae27582010-03-26 21:24:24 +0800274 if ((tar->filter_map & LOG_FILTER_ALL) != 0)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800275 output = 1;
Harald Welte4ebdf742010-05-19 19:54:00 +0200276 else if (osmo_log_info->filter_fn)
277 output = osmo_log_info->filter_fn(&log_context,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800278 tar);
Pablo Neira Ayuso81e96362011-05-03 22:32:48 +0200279 if (!output)
280 continue;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800281
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200282 /* According to the manpage, vsnprintf leaves the value of ap
283 * in undefined state. Since _output uses vsnprintf and it may
284 * be called several times, we have to pass a copy of ap. */
285 va_copy(bp, ap);
Harald Welteda127cb2011-07-02 21:51:32 +0200286 _output(tar, subsys, level, file, line, cont, format, bp);
Pablo Neira Ayusodd93bf42011-05-19 01:40:43 +0200287 va_end(bp);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800288 }
289}
290
Harald Welteb43bc042011-06-27 10:29:17 +0200291void logp(int subsys, char *file, int line, int cont,
Harald Welte3ae27582010-03-26 21:24:24 +0800292 const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800293{
294 va_list ap;
295
296 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800297 _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800298 va_end(ap);
299}
300
Harald Welteb43bc042011-06-27 10:29:17 +0200301void logp2(int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800302{
303 va_list ap;
304
305 va_start(ap, format);
Harald Welte3ae27582010-03-26 21:24:24 +0800306 _logp(subsys, level, file, line, cont, format, ap);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800307 va_end(ap);
308}
309
Harald Welte3ae27582010-03-26 21:24:24 +0800310void log_add_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800311{
Harald Welte28222962011-02-18 20:37:04 +0100312 llist_add_tail(&target->entry, &osmo_log_target_list);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800313}
314
Harald Welte3ae27582010-03-26 21:24:24 +0800315void log_del_target(struct log_target *target)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800316{
317 llist_del(&target->entry);
318}
319
Harald Welte3ae27582010-03-26 21:24:24 +0800320void log_reset_context(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800321{
Harald Welte3ae27582010-03-26 21:24:24 +0800322 memset(&log_context, 0, sizeof(log_context));
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800323}
324
Harald Welte3ae27582010-03-26 21:24:24 +0800325int log_set_context(uint8_t ctx_nr, void *value)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800326{
Harald Welte3ae27582010-03-26 21:24:24 +0800327 if (ctx_nr > LOG_MAX_CTX)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800328 return -EINVAL;
329
Harald Welte3ae27582010-03-26 21:24:24 +0800330 log_context.ctx[ctx_nr] = value;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800331
332 return 0;
333}
334
Harald Welte3ae27582010-03-26 21:24:24 +0800335void log_set_all_filter(struct log_target *target, int all)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800336{
337 if (all)
Harald Welte3ae27582010-03-26 21:24:24 +0800338 target->filter_map |= LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800339 else
Harald Welte3ae27582010-03-26 21:24:24 +0800340 target->filter_map &= ~LOG_FILTER_ALL;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800341}
342
Harald Welte3ae27582010-03-26 21:24:24 +0800343void log_set_use_color(struct log_target *target, int use_color)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800344{
345 target->use_color = use_color;
346}
347
Harald Welte3ae27582010-03-26 21:24:24 +0800348void log_set_print_timestamp(struct log_target *target, int print_timestamp)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800349{
350 target->print_timestamp = print_timestamp;
351}
352
Harald Welte3ae27582010-03-26 21:24:24 +0800353void log_set_log_level(struct log_target *target, int log_level)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800354{
355 target->loglevel = log_level;
356}
357
Harald Welte3ae27582010-03-26 21:24:24 +0800358void log_set_category_filter(struct log_target *target, int category,
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800359 int enable, int level)
360{
Harald Welte4ebdf742010-05-19 19:54:00 +0200361 if (category >= osmo_log_info->num_cat)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800362 return;
363 target->categories[category].enabled = !!enable;
364 target->categories[category].loglevel = level;
365}
366
Harald Welte76e72ab2011-02-17 15:52:39 +0100367static void _file_output(struct log_target *target, unsigned int level,
368 const char *log)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800369{
Harald Welte0083cd32010-08-25 14:55:44 +0200370 fprintf(target->tgt_file.out, "%s", log);
371 fflush(target->tgt_file.out);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800372}
373
Harald Welte3ae27582010-03-26 21:24:24 +0800374struct log_target *log_target_create(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800375{
Harald Welte3ae27582010-03-26 21:24:24 +0800376 struct log_target *target;
Harald Weltecc6313c2010-03-26 22:04:03 +0800377 unsigned int i;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800378
Harald Welte3ae27582010-03-26 21:24:24 +0800379 target = talloc_zero(tall_log_ctx, struct log_target);
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800380 if (!target)
381 return NULL;
382
Harald Welteb43bc042011-06-27 10:29:17 +0200383 target->categories = talloc_zero_array(target,
384 struct log_category,
385 osmo_log_info->num_cat);
386 if (!target->categories) {
387 talloc_free(target);
388 return NULL;
389 }
390
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800391 INIT_LLIST_HEAD(&target->entry);
Harald Weltecc6313c2010-03-26 22:04:03 +0800392
393 /* initialize the per-category enabled/loglevel from defaults */
Harald Welte4ebdf742010-05-19 19:54:00 +0200394 for (i = 0; i < osmo_log_info->num_cat; i++) {
Harald Weltecc6313c2010-03-26 22:04:03 +0800395 struct log_category *cat = &target->categories[i];
Harald Welte4ebdf742010-05-19 19:54:00 +0200396 cat->enabled = osmo_log_info->cat[i].enabled;
397 cat->loglevel = osmo_log_info->cat[i].loglevel;
Harald Weltecc6313c2010-03-26 22:04:03 +0800398 }
399
400 /* global settings */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800401 target->use_color = 1;
402 target->print_timestamp = 0;
Harald Weltecc6313c2010-03-26 22:04:03 +0800403
404 /* global log level */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800405 target->loglevel = 0;
406 return target;
407}
408
Harald Welte3ae27582010-03-26 21:24:24 +0800409struct log_target *log_target_create_stderr(void)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800410{
Harald Weltea3b844c2010-03-27 00:04:40 +0800411/* since C89/C99 says stderr is a macro, we can safely do this! */
412#ifdef stderr
Harald Welte3ae27582010-03-26 21:24:24 +0800413 struct log_target *target;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800414
Harald Welte3ae27582010-03-26 21:24:24 +0800415 target = log_target_create();
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800416 if (!target)
417 return NULL;
418
Harald Welte28222962011-02-18 20:37:04 +0100419 target->type = LOG_TGT_TYPE_STDERR;
Harald Welte0083cd32010-08-25 14:55:44 +0200420 target->tgt_file.out = stderr;
421 target->output = _file_output;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800422 return target;
Harald Weltea3b844c2010-03-27 00:04:40 +0800423#else
424 return NULL;
425#endif /* stderr */
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800426}
427
Harald Welte3086c392010-08-25 19:10:50 +0200428struct log_target *log_target_create_file(const char *fname)
429{
430 struct log_target *target;
431
432 target = log_target_create();
433 if (!target)
434 return NULL;
435
Harald Welte28222962011-02-18 20:37:04 +0100436 target->type = LOG_TGT_TYPE_FILE;
Harald Welte3086c392010-08-25 19:10:50 +0200437 target->tgt_file.out = fopen(fname, "a");
438 if (!target->tgt_file.out)
439 return NULL;
440
441 target->output = _file_output;
442
443 target->tgt_file.fname = talloc_strdup(target, fname);
444
445 return target;
446}
447
Harald Welte28222962011-02-18 20:37:04 +0100448struct log_target *log_target_find(int type, const char *fname)
449{
450 struct log_target *tgt;
451
452 llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
453 if (tgt->type != type)
454 continue;
455 if (tgt->type == LOG_TGT_TYPE_FILE) {
456 if (!strcmp(fname, tgt->tgt_file.fname))
457 return tgt;
458 } else
459 return tgt;
460 }
461 return NULL;
462}
463
Harald Welte3086c392010-08-25 19:10:50 +0200464void log_target_destroy(struct log_target *target)
465{
466
467 /* just in case, to make sure we don't have any references */
468 log_del_target(target);
469
470 if (target->output == &_file_output) {
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200471/* since C89/C99 says stderr is a macro, we can safely do this! */
472#ifdef stderr
Harald Welte3086c392010-08-25 19:10:50 +0200473 /* don't close stderr */
Sylvain Munautaf5ee342010-09-17 14:38:17 +0200474 if (target->tgt_file.out != stderr)
475#endif
476 {
Harald Welte3086c392010-08-25 19:10:50 +0200477 fclose(target->tgt_file.out);
478 target->tgt_file.out = NULL;
479 }
480 }
481
482 talloc_free(target);
483}
484
485/* close and re-open a log file (for log file rotation) */
486int log_target_file_reopen(struct log_target *target)
487{
488 fclose(target->tgt_file.out);
489
490 target->tgt_file.out = fopen(target->tgt_file.fname, "a");
491 if (!target->tgt_file.out)
492 return -errno;
493
494 /* we assume target->output already to be set */
495
496 return 0;
497}
498
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100499/* This generates the logging command string for VTY. */
Harald Weltece9fec32011-06-27 14:19:16 +0200500const char *log_vty_command_string(const struct log_info *unused_info)
Harald Welte7638af92010-05-11 16:39:22 +0200501{
Harald Weltece9fec32011-06-27 14:19:16 +0200502 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100503 int len = 0, offset = 0, ret, i, rem;
504 int size = strlen("logging level () ()") + 1;
Harald Welte7638af92010-05-11 16:39:22 +0200505 char *str;
506
Harald Welteb43bc042011-06-27 10:29:17 +0200507 for (i = 0; i < info->num_cat; i++) {
508 if (info->cat[i].name == NULL)
509 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100510 size += strlen(info->cat[i].name) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200511 }
Harald Welte7638af92010-05-11 16:39:22 +0200512
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100513 for (i = 0; i < LOGLEVEL_DEFS; i++)
514 size += strlen(loglevel_strs[i].str) + 1;
515
516 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200517 str = talloc_zero_size(tall_log_ctx, size);
Harald Welte7638af92010-05-11 16:39:22 +0200518 if (!str)
519 return NULL;
520
Holger Hans Peter Freyther952a18e2011-03-29 17:03:56 +0200521 ret = snprintf(str + offset, rem, "logging level (all|");
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100522 if (ret < 0)
523 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200524 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Harald Welte7638af92010-05-11 16:39:22 +0200525
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100526 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200527 if (info->cat[i].name) {
528 int j, name_len = strlen(info->cat[i].name)+1;
529 char name[name_len];
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100530
Harald Welteb43bc042011-06-27 10:29:17 +0200531 for (j = 0; j < name_len; j++)
532 name[j] = tolower(info->cat[i].name[j]);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100533
Harald Welteb43bc042011-06-27 10:29:17 +0200534 name[name_len-1] = '\0';
535 ret = snprintf(str + offset, rem, "%s|", name+1);
536 if (ret < 0)
537 goto err;
538 OSMO_SNPRINTF_RET(ret, rem, offset, len);
539 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100540 }
541 offset--; /* to remove the trailing | */
542 rem++;
543
544 ret = snprintf(str + offset, rem, ") (");
545 if (ret < 0)
546 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200547 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100548
549 for (i = 0; i < LOGLEVEL_DEFS; i++) {
550 int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
551 char loglevel_str[loglevel_str_len];
552
553 for (j = 0; j < loglevel_str_len; j++)
554 loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
555
556 loglevel_str[loglevel_str_len-1] = '\0';
557 ret = snprintf(str + offset, rem, "%s|", loglevel_str);
558 if (ret < 0)
559 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200560 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100561 }
562 offset--; /* to remove the trailing | */
563 rem++;
564
565 ret = snprintf(str + offset, rem, ")");
566 if (ret < 0)
567 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200568 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100569err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200570 str[size-1] = '\0';
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100571 return str;
572}
573
574/* This generates the logging command description for VTY. */
Harald Weltece9fec32011-06-27 14:19:16 +0200575const char *log_vty_command_description(const struct log_info *unused_info)
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100576{
Harald Weltece9fec32011-06-27 14:19:16 +0200577 struct log_info *info = osmo_log_info;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100578 char *str;
579 int i, ret, len = 0, offset = 0, rem;
580 unsigned int size =
581 strlen(LOGGING_STR
582 "Set the log level for a specified category\n") + 1;
583
Harald Welteb43bc042011-06-27 10:29:17 +0200584 for (i = 0; i < info->num_cat; i++) {
585 if (info->cat[i].name == NULL)
586 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100587 size += strlen(info->cat[i].description) + 1;
Harald Welteb43bc042011-06-27 10:29:17 +0200588 }
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100589
590 for (i = 0; i < LOGLEVEL_DEFS; i++)
591 size += strlen(loglevel_descriptions[i]) + 1;
592
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200593 size += strlen("Global setting for all subsystems") + 1;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100594 rem = size;
Pablo Neira Ayusof1fae4d2011-05-03 22:32:42 +0200595 str = talloc_zero_size(tall_log_ctx, size);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100596 if (!str)
597 return NULL;
598
599 ret = snprintf(str + offset, rem, LOGGING_STR
600 "Set the log level for a specified category\n");
601 if (ret < 0)
602 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200603 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100604
Pablo Neira Ayusod6b51952011-05-03 22:32:32 +0200605 ret = snprintf(str + offset, rem,
606 "Global setting for all subsystems\n");
607 if (ret < 0)
608 goto err;
609 OSMO_SNPRINTF_RET(ret, rem, offset, len);
610
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100611 for (i = 0; i < info->num_cat; i++) {
Harald Welteb43bc042011-06-27 10:29:17 +0200612 if (info->cat[i].name == NULL)
613 continue;
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100614 ret = snprintf(str + offset, rem, "%s\n",
615 info->cat[i].description);
616 if (ret < 0)
617 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200618 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100619 }
620 for (i = 0; i < LOGLEVEL_DEFS; i++) {
621 ret = snprintf(str + offset, rem, "%s\n",
622 loglevel_descriptions[i]);
623 if (ret < 0)
624 goto err;
Pablo Neira Ayuso3abad6a2011-03-28 19:24:22 +0200625 OSMO_SNPRINTF_RET(ret, rem, offset, len);
Pablo Neira Ayuso04139f12011-03-09 13:05:08 +0100626 }
627err:
Pablo Neira Ayuso534ba812011-05-03 22:32:48 +0200628 str[size-1] = '\0';
Harald Welte7638af92010-05-11 16:39:22 +0200629 return str;
630}
631
Harald Welteb43bc042011-06-27 10:29:17 +0200632int log_init(const struct log_info *inf, void *ctx)
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800633{
Harald Welteb43bc042011-06-27 10:29:17 +0200634 int i;
635
636 tall_log_ctx = talloc_named_const(ctx, 1, "logging");
637 if (!tall_log_ctx)
638 return -ENOMEM;
639
640 osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
641 if (!osmo_log_info)
642 return -ENOMEM;
643
644 osmo_log_info->num_cat_user = inf->num_cat;
645 /* total number = number of user cat + library cat */
Harald Weltece9fec32011-06-27 14:19:16 +0200646 osmo_log_info->num_cat = inf->num_cat + ARRAY_SIZE(internal_cat);
Harald Welteb43bc042011-06-27 10:29:17 +0200647
648 osmo_log_info->cat = talloc_zero_array(osmo_log_info,
649 struct log_info_cat,
650 osmo_log_info->num_cat);
651 if (!osmo_log_info->cat) {
652 talloc_free(osmo_log_info);
653 osmo_log_info = NULL;
654 return -ENOMEM;
655 }
656
657 /* copy over the user part */
658 for (i = 0; i < inf->num_cat; i++) {
659 memcpy(&osmo_log_info->cat[i], &inf->cat[i],
660 sizeof(struct log_info_cat));
661 }
662
663 /* copy over the library part */
Harald Welte9fe16522011-06-27 14:00:03 +0200664 for (i = 0; i < ARRAY_SIZE(internal_cat); i++) {
Harald Weltece9fec32011-06-27 14:19:16 +0200665 unsigned int cn = osmo_log_info->num_cat_user + i;
666 memcpy(&osmo_log_info->cat[cn],
Harald Welte9fe16522011-06-27 14:00:03 +0200667 &internal_cat[i], sizeof(struct log_info_cat));
668 }
669
670 return 0;
Harald Welte4a2bb9e2010-03-26 09:33:40 +0800671}