1 /* OpenBSC logging helper for the VTY */
2 /* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
3 * (C) 2009-2010 by Holger Hans Peter Freyther
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "../../config.h"
27 #include <osmocom/core/talloc.h>
28 #include <osmocom/core/logging.h>
29 #include <osmocom/core/utils.h>
31 //#include <openbsc/vty.h>
33 #include <osmocom/vty/command.h>
34 #include <osmocom/vty/buffer.h>
35 #include <osmocom/vty/vty.h>
36 #include <osmocom/vty/telnet_interface.h>
37 #include <osmocom/vty/logging.h>
39 #define LOG_STR "Configure logging sub-system\n"
41 extern const struct log_info *osmo_log_info;
43 static void _vty_output(struct log_target *tgt,
44 unsigned int level, const char *line)
46 struct vty *vty = tgt->tgt_vty.vty;
47 vty_out(vty, "%s", line);
48 /* This is an ugly hack, but there is no easy way... */
49 if (strchr(line, '\n'))
53 struct log_target *log_target_create_vty(struct vty *vty)
55 struct log_target *target;
57 target = log_target_create();
61 target->tgt_vty.vty = vty;
62 target->output = _vty_output;
70 "Enables logging to this vty\n")
72 struct telnet_connection *conn;
74 conn = (struct telnet_connection *) vty->priv;
76 vty_out(vty, "Logging already enabled.%s", VTY_NEWLINE);
80 conn->dbg = log_target_create_vty(vty);
84 log_add_target(conn->dbg);
88 struct log_target *osmo_log_vty2tgt(struct vty *vty)
90 struct telnet_connection *conn;
92 if (vty->node == CFG_LOG_NODE)
96 conn = (struct telnet_connection *) vty->priv;
98 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
103 DEFUN(logging_fltr_all,
104 logging_fltr_all_cmd,
105 "logging filter all (0|1)",
106 LOGGING_STR FILTER_STR
107 "Do you want to log all messages?\n"
108 "Only print messages matched by other filters\n"
109 "Bypass filter and print all messages\n")
111 struct log_target *tgt = osmo_log_vty2tgt(vty);
116 log_set_all_filter(tgt, atoi(argv[0]));
120 DEFUN(logging_use_clr,
122 "logging color (0|1)",
123 LOGGING_STR "Configure color-printing for log messages\n"
124 "Don't use color for printing messages\n"
125 "Use color for printing messages\n")
127 struct log_target *tgt = osmo_log_vty2tgt(vty);
132 log_set_use_color(tgt, atoi(argv[0]));
136 DEFUN(logging_prnt_timestamp,
137 logging_prnt_timestamp_cmd,
138 "logging timestamp (0|1)",
139 LOGGING_STR "Configure log message timestamping\n"
140 "Don't prefix each log message\n"
141 "Prefix each log message with current timestamp\n")
143 struct log_target *tgt = osmo_log_vty2tgt(vty);
148 log_set_print_timestamp(tgt, atoi(argv[0]));
154 NULL, /* cmdstr is dynamically set in logging_vty_add_cmds(). */
155 NULL) /* same thing for helpstr. */
157 int category = log_parse_category(argv[0]);
158 int level = log_parse_level(argv[1]);
159 struct log_target *tgt = osmo_log_vty2tgt(vty);
165 vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE);
169 /* Check for special case where we want to set global log level */
170 if (!strcmp(argv[0], "all")) {
171 log_set_log_level(tgt, level);
176 vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE);
180 tgt->categories[category].enabled = 1;
181 tgt->categories[category].loglevel = level;
186 DEFUN(logging_set_category_mask,
187 logging_set_category_mask_cmd,
188 "logging set log mask MASK",
190 "Decide which categories to output.\n")
192 struct log_target *tgt = osmo_log_vty2tgt(vty);
197 log_parse_category_mask(tgt, argv[0]);
201 DEFUN(diable_logging,
205 "Disables logging to this vty\n")
207 struct log_target *tgt = osmo_log_vty2tgt(vty);
208 struct telnet_connection *conn = (struct telnet_connection *) vty->priv;
220 static void vty_print_logtarget(struct vty *vty, const struct log_info *info,
221 const struct log_target *tgt)
225 vty_out(vty, " Global Loglevel: %s%s",
226 log_level_str(tgt->loglevel), VTY_NEWLINE);
227 vty_out(vty, " Use color: %s, Print Timestamp: %s%s",
228 tgt->use_color ? "On" : "Off",
229 tgt->print_timestamp ? "On" : "Off", VTY_NEWLINE);
231 vty_out(vty, " Log Level specific information:%s", VTY_NEWLINE);
233 for (i = 0; i < info->num_cat; i++) {
234 const struct log_category *cat = &tgt->categories[i];
235 vty_out(vty, " %-10s %-10s %-8s %s%s",
236 info->cat[i].name+1, log_level_str(cat->loglevel),
237 cat->enabled ? "Enabled" : "Disabled",
238 info->cat[i].description,
243 #define SHOW_LOG_STR "Show current logging configuration\n"
245 DEFUN(show_logging_vty,
246 show_logging_vty_cmd,
248 SHOW_STR SHOW_LOG_STR
249 "Show current logging configuration for this vty\n")
251 struct log_target *tgt = osmo_log_vty2tgt(vty);
256 vty_print_logtarget(vty, osmo_log_info, tgt);
261 gDEFUN(cfg_description, cfg_description_cmd,
263 "Save human-readable decription of the object\n")
265 char **dptr = vty->index_sub;
268 vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
272 *dptr = argv_concat(argv, argc, 0);
279 gDEFUN(cfg_no_description, cfg_no_description_cmd,
282 "Remove description of the object\n")
284 char **dptr = vty->index_sub;
287 vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
299 /* Support for configuration of log targets != the current vty */
301 struct cmd_node cfg_log_node = {
311 static const int local_sysl_map[] = {
322 /* From VTY core code */
323 extern struct host host;
325 static int _cfg_log_syslog(struct vty *vty, int facility)
327 struct log_target *tgt;
329 /* First delete the old syslog target, if any */
330 tgt = log_target_find(LOG_TGT_TYPE_SYSLOG, NULL);
332 log_target_destroy(tgt);
334 tgt = log_target_create_syslog(host.app_info->name, 0, facility);
336 vty_out(vty, "%% Unable to open syslog%s", VTY_NEWLINE);
342 vty->node = CFG_LOG_NODE;
347 DEFUN(cfg_log_syslog_local, cfg_log_syslog_local_cmd,
348 "log syslog local <0-7>",
349 LOG_STR "Logging via syslog\n" "Syslog LOCAL facility\n"
350 "Local facility number\n")
352 int local = atoi(argv[0]);
353 int facility = local_sysl_map[local];
355 return _cfg_log_syslog(vty, facility);
358 static struct value_string sysl_level_names[] = {
359 { LOG_AUTHPRIV, "authpriv" },
360 { LOG_CRON, "cron" },
361 { LOG_DAEMON, "daemon" },
364 { LOG_MAIL, "mail" },
365 { LOG_NEWS, "news" },
366 { LOG_USER, "user" },
367 { LOG_UUCP, "uucp" },
368 /* only for value -> string conversion */
369 { LOG_LOCAL0, "local 0" },
370 { LOG_LOCAL1, "local 1" },
371 { LOG_LOCAL2, "local 2" },
372 { LOG_LOCAL3, "local 3" },
373 { LOG_LOCAL4, "local 4" },
374 { LOG_LOCAL5, "local 5" },
375 { LOG_LOCAL6, "local 6" },
376 { LOG_LOCAL7, "local 7" },
380 DEFUN(cfg_log_syslog, cfg_log_syslog_cmd,
381 "log syslog (authpriv|cron|daemon|ftp|lpr|mail|news|user|uucp)",
382 LOG_STR "Logging via syslog\n")
384 int facility = get_string_value(sysl_level_names, argv[0]);
386 return _cfg_log_syslog(vty, facility);
389 DEFUN(cfg_no_log_syslog, cfg_no_log_syslog_cmd,
391 NO_STR LOG_STR "Logging via syslog\n")
393 struct log_target *tgt;
395 tgt = log_target_find(LOG_TGT_TYPE_SYSLOG, NULL);
397 vty_out(vty, "%% No syslog target found%s",
402 log_target_destroy(tgt);
406 #endif /* HAVE_SYSLOG_H */
408 DEFUN(cfg_log_stderr, cfg_log_stderr_cmd,
410 LOG_STR "Logging via STDERR of the process\n")
412 struct log_target *tgt;
414 tgt = log_target_find(LOG_TGT_TYPE_STDERR, NULL);
416 tgt = log_target_create_stderr();
418 vty_out(vty, "%% Unable to create stderr log%s",
426 vty->node = CFG_LOG_NODE;
431 DEFUN(cfg_no_log_stderr, cfg_no_log_stderr_cmd,
433 NO_STR LOG_STR "Logging via STDERR of the process\n")
435 struct log_target *tgt;
437 tgt = log_target_find(LOG_TGT_TYPE_STDERR, NULL);
439 vty_out(vty, "%% No stderr logging active%s", VTY_NEWLINE);
443 log_target_destroy(tgt);
448 DEFUN(cfg_log_file, cfg_log_file_cmd,
449 "log file .FILENAME",
450 LOG_STR "Logging to text file\n" "Filename\n")
452 const char *fname = argv[0];
453 struct log_target *tgt;
455 tgt = log_target_find(LOG_TGT_TYPE_FILE, fname);
457 tgt = log_target_create_file(fname);
459 vty_out(vty, "%% Unable to create file `%s'%s",
467 vty->node = CFG_LOG_NODE;
473 DEFUN(cfg_no_log_file, cfg_no_log_file_cmd,
474 "no log file .FILENAME",
475 NO_STR LOG_STR "Logging to text file\n" "Filename\n")
477 const char *fname = argv[0];
478 struct log_target *tgt;
480 tgt = log_target_find(LOG_TGT_TYPE_FILE, fname);
482 vty_out(vty, "%% No such log file `%s'%s",
487 log_target_destroy(tgt);
492 static int config_write_log_single(struct vty *vty, struct log_target *tgt)
495 char level_lower[32];
498 case LOG_TGT_TYPE_VTY:
501 case LOG_TGT_TYPE_STDERR:
502 vty_out(vty, "log stderr%s", VTY_NEWLINE);
504 case LOG_TGT_TYPE_SYSLOG:
506 vty_out(vty, "log syslog %s%s",
507 get_value_string(sysl_level_names,
508 tgt->tgt_syslog.facility),
512 case LOG_TGT_TYPE_FILE:
513 vty_out(vty, "log file %s%s", tgt->tgt_file.fname, VTY_NEWLINE);
517 vty_out(vty, " logging color %u%s", tgt->use_color ? 1 : 0,
519 vty_out(vty, " logging timestamp %u%s", tgt->print_timestamp ? 1 : 0,
522 /* stupid old osmo logging API uses uppercase strings... */
523 osmo_str2lower(level_lower, log_level_str(tgt->loglevel));
524 vty_out(vty, " logging level all %s%s", level_lower, VTY_NEWLINE);
526 for (i = 0; i < osmo_log_info->num_cat; i++) {
527 const struct log_category *cat = &tgt->categories[i];
530 /* stupid old osmo logging API uses uppercase strings... */
531 osmo_str2lower(cat_lower, osmo_log_info->cat[i].name+1);
532 osmo_str2lower(level_lower, log_level_str(cat->loglevel));
534 vty_out(vty, " logging level %s %s%s", cat_lower, level_lower,
543 static int config_write_log(struct vty *vty)
545 struct log_target *dbg = vty->index;
547 llist_for_each_entry(dbg, &osmo_log_target_list, entry)
548 config_write_log_single(vty, dbg);
553 void logging_vty_add_cmds(const struct log_info *cat)
555 install_element_ve(&enable_logging_cmd);
556 install_element_ve(&disable_logging_cmd);
557 install_element_ve(&logging_fltr_all_cmd);
558 install_element_ve(&logging_use_clr_cmd);
559 install_element_ve(&logging_prnt_timestamp_cmd);
560 install_element_ve(&logging_set_category_mask_cmd);
562 /* Logging level strings are generated dynamically. */
563 logging_level_cmd.string = log_vty_command_string(cat);
564 logging_level_cmd.doc = log_vty_command_description(cat);
565 install_element_ve(&logging_level_cmd);
566 install_element_ve(&show_logging_vty_cmd);
568 install_node(&cfg_log_node, config_write_log);
569 install_element(CFG_LOG_NODE, &logging_fltr_all_cmd);
570 install_element(CFG_LOG_NODE, &logging_use_clr_cmd);
571 install_element(CFG_LOG_NODE, &logging_prnt_timestamp_cmd);
572 install_element(CFG_LOG_NODE, &logging_level_cmd);
574 install_element(CONFIG_NODE, &cfg_log_stderr_cmd);
575 install_element(CONFIG_NODE, &cfg_no_log_stderr_cmd);
576 install_element(CONFIG_NODE, &cfg_log_file_cmd);
577 install_element(CONFIG_NODE, &cfg_no_log_file_cmd);
579 install_element(CONFIG_NODE, &cfg_log_syslog_cmd);
580 install_element(CONFIG_NODE, &cfg_log_syslog_local_cmd);
581 install_element(CONFIG_NODE, &cfg_no_log_syslog_cmd);