LOGGING: Pass the log level down to the log target output function
[osmocom-bb.git] / src / vty / logging_vty.c
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
4  * All Rights Reserved
5  *
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.
10  *
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.
15  *
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.
19  *
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <osmocore/talloc.h>
26 #include <osmocore/logging.h>
27
28 //#include <openbsc/vty.h>
29
30 #include <osmocom/vty/command.h>
31 #include <osmocom/vty/buffer.h>
32 #include <osmocom/vty/vty.h>
33 #include <osmocom/vty/telnet_interface.h>
34 #include <osmocom/vty/logging.h>
35
36 extern const struct log_info *osmo_log_info;
37
38 static void _vty_output(struct log_target *tgt,
39                         unsigned int level, const char *line)
40 {
41         struct vty *vty = tgt->tgt_vty.vty;
42         vty_out(vty, "%s", line);
43         /* This is an ugly hack, but there is no easy way... */
44         if (strchr(line, '\n'))
45                 vty_out(vty, "\r");
46 }
47
48 struct log_target *log_target_create_vty(struct vty *vty)
49 {
50         struct log_target *target;
51
52         target = log_target_create();
53         if (!target)
54                 return NULL;
55
56         target->tgt_vty.vty = vty;
57         target->output = _vty_output;
58         return target;
59 }
60
61 DEFUN(enable_logging,
62       enable_logging_cmd,
63       "logging enable",
64         LOGGING_STR
65       "Enables logging to this vty\n")
66 {
67         struct telnet_connection *conn;
68
69         conn = (struct telnet_connection *) vty->priv;
70         if (conn->dbg) {
71                 vty_out(vty, "Logging already enabled.%s", VTY_NEWLINE);
72                 return CMD_WARNING;
73         }
74
75         conn->dbg = log_target_create_vty(vty);
76         if (!conn->dbg)
77                 return CMD_WARNING;
78
79         log_add_target(conn->dbg);
80         return CMD_SUCCESS;
81 }
82
83 DEFUN(logging_fltr_all,
84       logging_fltr_all_cmd,
85       "logging filter all (0|1)",
86         LOGGING_STR FILTER_STR
87         "Do you want to log all messages?\n"
88         "Only print messages matched by other filters\n"
89         "Bypass filter and print all messages\n")
90 {
91         struct telnet_connection *conn;
92
93         conn = (struct telnet_connection *) vty->priv;
94         if (!conn->dbg) {
95                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
96                 return CMD_WARNING;
97         }
98
99         log_set_all_filter(conn->dbg, atoi(argv[0]));
100         return CMD_SUCCESS;
101 }
102
103 DEFUN(logging_use_clr,
104       logging_use_clr_cmd,
105       "logging color (0|1)",
106         LOGGING_STR "Configure color-printing for log messages\n"
107       "Don't use color for printing messages\n"
108       "Use color for printing messages\n")
109 {
110         struct telnet_connection *conn;
111
112         conn = (struct telnet_connection *) vty->priv;
113         if (!conn->dbg) {
114                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
115                 return CMD_WARNING;
116         }
117
118         log_set_use_color(conn->dbg, atoi(argv[0]));
119         return CMD_SUCCESS;
120 }
121
122 DEFUN(logging_prnt_timestamp,
123       logging_prnt_timestamp_cmd,
124       "logging timestamp (0|1)",
125         LOGGING_STR "Configure log message timestamping\n"
126         "Don't prefix each log message\n"
127         "Prefix each log message with current timestamp\n")
128 {
129         struct telnet_connection *conn;
130
131         conn = (struct telnet_connection *) vty->priv;
132         if (!conn->dbg) {
133                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
134                 return CMD_WARNING;
135         }
136
137         log_set_print_timestamp(conn->dbg, atoi(argv[0]));
138         return CMD_SUCCESS;
139 }
140
141 /* FIXME: those have to be kept in sync with the log levels and categories */
142 #define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs|ns|bssgp|llc|sndcp|isup|m2ua|pcap|all)"
143 #define CATEGORIES_HELP \
144         "A-bis Radio Link Layer (RLL)\n"                        \
145         "Layer3 Call Control (CC)\n"                            \
146         "Layer3 Mobility Management (MM)\n"                     \
147         "Layer3 Radio Resource (RR)\n"                          \
148         "A-bis Radio Signalling Link (RSL)\n"                   \
149         "A-bis Network Management / O&M (NM/OML)\n"             \
150         "Layer3 Short Messagaging Service (SMS)\n"              \
151         "Paging Subsystem\n"                                    \
152         "MNCC API for Call Control application\n"               \
153         "A-bis Input Subsystem\n"                               \
154         "A-bis Input Driver for Signalling\n"                   \
155         "A-bis Input Driver for B-Channel (voice data)\n"       \
156         "A-bis B-Channel / Sub-channel Multiplexer\n"           \
157         "Radio Measurements\n"                                  \
158         "SCCP\n"                                                \
159         "Mobile Switching Center\n"                             \
160         "Media Gateway Control Protocol\n"                      \
161         "Hand-over\n"                                           \
162         "Database Layer\n"                                      \
163         "Reference Counting\n"                                  \
164         "GPRS Core\n"                                           \
165         "GPRS Network Service (NS)\n"                           \
166         "GPRS BSS Gateway Protocol (BSSGP)\n"                   \
167         "GPRS Logical Link Control Protocol (LLC)\n"            \
168         "GPRS Sub-Network Dependent Control Protocol (SNDCP)\n" \
169         "ISDN User Part (ISUP)\n"                               \
170         "SCTP M2UA\n"                                           \
171         "Trace message IO\n"                                    \
172         "Global setting for all subsytems\n"
173
174 #define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)"
175 #define LEVELS_HELP     \
176         "Log simply everything\n"                               \
177         "Log debug messages and higher levels\n"                \
178         "Log informational messages and higher levels\n"        \
179         "Log noticable messages and higher levels\n"            \
180         "Log error messages and higher levels\n"                \
181         "Log only fatal messages\n"
182 DEFUN(logging_level,
183       logging_level_cmd,
184       "logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS,
185       LOGGING_STR
186       "Set the log level for a specified category\n"
187       CATEGORIES_HELP
188       LEVELS_HELP)
189 {
190         struct telnet_connection *conn;
191         int category = log_parse_category(argv[0]);
192         int level = log_parse_level(argv[1]);
193
194         conn = (struct telnet_connection *) vty->priv;
195         if (!conn->dbg) {
196                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
197                 return CMD_WARNING;
198         }
199
200         if (level < 0) {
201                 vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE);
202                 return CMD_WARNING;
203         }
204
205         /* Check for special case where we want to set global log level */
206         if (!strcmp(argv[0], "all")) {
207                 log_set_log_level(conn->dbg, level);
208                 return CMD_SUCCESS;
209         }
210
211         if (category < 0) {
212                 vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE);
213                 return CMD_WARNING;
214         }
215
216         conn->dbg->categories[category].enabled = 1;
217         conn->dbg->categories[category].loglevel = level;
218
219         return CMD_SUCCESS;
220 }
221
222 DEFUN(logging_set_category_mask,
223       logging_set_category_mask_cmd,
224       "logging set log mask MASK",
225         LOGGING_STR
226       "Decide which categories to output.\n")
227 {
228         struct telnet_connection *conn;
229
230         conn = (struct telnet_connection *) vty->priv;
231         if (!conn->dbg) {
232                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
233                 return CMD_WARNING;
234         }
235
236         log_parse_category_mask(conn->dbg, argv[0]);
237         return CMD_SUCCESS;
238 }
239
240 DEFUN(diable_logging,
241       disable_logging_cmd,
242       "logging disable",
243         LOGGING_STR
244       "Disables logging to this vty\n")
245 {
246         struct telnet_connection *conn;
247
248         conn = (struct telnet_connection *) vty->priv;
249         if (!conn->dbg) {
250                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
251                 return CMD_WARNING;
252         }
253
254         log_del_target(conn->dbg);
255         talloc_free(conn->dbg);
256         conn->dbg = NULL;
257         return CMD_SUCCESS;
258 }
259
260 static void vty_print_logtarget(struct vty *vty, const struct log_info *info,
261                                 const struct log_target *tgt)
262 {
263         unsigned int i;
264
265         vty_out(vty, " Global Loglevel: %s%s",
266                 log_level_str(tgt->loglevel), VTY_NEWLINE);
267         vty_out(vty, " Use color: %s, Print Timestamp: %s%s",
268                 tgt->use_color ? "On" : "Off",
269                 tgt->print_timestamp ? "On" : "Off", VTY_NEWLINE);
270
271         vty_out(vty, " Log Level specific information:%s", VTY_NEWLINE);
272
273         for (i = 0; i < info->num_cat; i++) {
274                 const struct log_category *cat = &tgt->categories[i];
275                 vty_out(vty, "  %-10s %-10s %-8s %s%s",
276                         info->cat[i].name+1, log_level_str(cat->loglevel),
277                         cat->enabled ? "Enabled" : "Disabled",
278                         info->cat[i].description,
279                         VTY_NEWLINE);
280         }
281 }
282
283 #define SHOW_LOG_STR "Show current logging configuration\n"
284
285 DEFUN(show_logging_vty,
286       show_logging_vty_cmd,
287       "show logging vty",
288         SHOW_STR SHOW_LOG_STR
289         "Show current logging configuration for this vty\n")
290 {
291         struct telnet_connection *conn;
292
293         conn = (struct telnet_connection *) vty->priv;
294         if (!conn->dbg) {
295                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
296                 return CMD_WARNING;
297         }
298         vty_print_logtarget(vty, osmo_log_info, conn->dbg);
299
300         return CMD_SUCCESS;
301 }
302
303 gDEFUN(cfg_description, cfg_description_cmd,
304         "description .TEXT",
305         "Save human-readable decription of the object\n")
306 {
307         char **dptr = vty->index_sub;
308
309         if (!dptr) {
310                 vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
311                 return CMD_WARNING;
312         }
313
314         *dptr = argv_concat(argv, argc, 0);
315         if (!dptr)
316                 return CMD_WARNING;
317
318         return CMD_SUCCESS;
319 }
320
321 gDEFUN(cfg_no_description, cfg_no_description_cmd,
322         "no description",
323         NO_STR
324         "Remove description of the object\n")
325 {
326         char **dptr = vty->index_sub;
327
328         if (!dptr) {
329                 vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
330                 return CMD_WARNING;
331         }
332
333         if (*dptr) {
334                 talloc_free(*dptr);
335                 *dptr = NULL;
336         }
337
338         return CMD_SUCCESS;
339 }
340
341 void logging_vty_add_cmds()
342 {
343         install_element_ve(&enable_logging_cmd);
344         install_element_ve(&disable_logging_cmd);
345         install_element_ve(&logging_fltr_all_cmd);
346         install_element_ve(&logging_use_clr_cmd);
347         install_element_ve(&logging_prnt_timestamp_cmd);
348         install_element_ve(&logging_set_category_mask_cmd);
349         install_element_ve(&logging_level_cmd);
350         install_element_ve(&show_logging_vty_cmd);
351 }