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