LOGGING: configure logging from the vty
[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 "../../config.h"
26
27 #include <osmocore/talloc.h>
28 #include <osmocore/logging.h>
29 #include <osmocore/utils.h>
30
31 //#include <openbsc/vty.h>
32
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>
38
39 #define LOG_STR "Configure logging sub-system\n"
40
41 extern const struct log_info *osmo_log_info;
42
43 static void _vty_output(struct log_target *tgt,
44                         unsigned int level, const char *line)
45 {
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'))
50                 vty_out(vty, "\r");
51 }
52
53 struct log_target *log_target_create_vty(struct vty *vty)
54 {
55         struct log_target *target;
56
57         target = log_target_create();
58         if (!target)
59                 return NULL;
60
61         target->tgt_vty.vty = vty;
62         target->output = _vty_output;
63         return target;
64 }
65
66 DEFUN(enable_logging,
67       enable_logging_cmd,
68       "logging enable",
69         LOGGING_STR
70       "Enables logging to this vty\n")
71 {
72         struct telnet_connection *conn;
73
74         conn = (struct telnet_connection *) vty->priv;
75         if (conn->dbg) {
76                 vty_out(vty, "Logging already enabled.%s", VTY_NEWLINE);
77                 return CMD_WARNING;
78         }
79
80         conn->dbg = log_target_create_vty(vty);
81         if (!conn->dbg)
82                 return CMD_WARNING;
83
84         log_add_target(conn->dbg);
85         return CMD_SUCCESS;
86 }
87
88 DEFUN(logging_fltr_all,
89       logging_fltr_all_cmd,
90       "logging filter all (0|1)",
91         LOGGING_STR FILTER_STR
92         "Do you want to log all messages?\n"
93         "Only print messages matched by other filters\n"
94         "Bypass filter and print all messages\n")
95 {
96         struct telnet_connection *conn;
97
98         conn = (struct telnet_connection *) vty->priv;
99         if (!conn->dbg) {
100                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
101                 return CMD_WARNING;
102         }
103
104         log_set_all_filter(conn->dbg, atoi(argv[0]));
105         return CMD_SUCCESS;
106 }
107
108 DEFUN(logging_use_clr,
109       logging_use_clr_cmd,
110       "logging color (0|1)",
111         LOGGING_STR "Configure color-printing for log messages\n"
112       "Don't use color for printing messages\n"
113       "Use color for printing messages\n")
114 {
115         struct telnet_connection *conn;
116
117         conn = (struct telnet_connection *) vty->priv;
118         if (!conn->dbg) {
119                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
120                 return CMD_WARNING;
121         }
122
123         log_set_use_color(conn->dbg, atoi(argv[0]));
124         return CMD_SUCCESS;
125 }
126
127 DEFUN(logging_prnt_timestamp,
128       logging_prnt_timestamp_cmd,
129       "logging timestamp (0|1)",
130         LOGGING_STR "Configure log message timestamping\n"
131         "Don't prefix each log message\n"
132         "Prefix each log message with current timestamp\n")
133 {
134         struct telnet_connection *conn;
135
136         conn = (struct telnet_connection *) vty->priv;
137         if (!conn->dbg) {
138                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
139                 return CMD_WARNING;
140         }
141
142         log_set_print_timestamp(conn->dbg, atoi(argv[0]));
143         return CMD_SUCCESS;
144 }
145
146 /* FIXME: those have to be kept in sync with the log levels and categories */
147 #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)"
148 #define CATEGORIES_HELP \
149         "A-bis Radio Link Layer (RLL)\n"                        \
150         "Layer3 Call Control (CC)\n"                            \
151         "Layer3 Mobility Management (MM)\n"                     \
152         "Layer3 Radio Resource (RR)\n"                          \
153         "A-bis Radio Signalling Link (RSL)\n"                   \
154         "A-bis Network Management / O&M (NM/OML)\n"             \
155         "Layer3 Short Messagaging Service (SMS)\n"              \
156         "Paging Subsystem\n"                                    \
157         "MNCC API for Call Control application\n"               \
158         "A-bis Input Subsystem\n"                               \
159         "A-bis Input Driver for Signalling\n"                   \
160         "A-bis Input Driver for B-Channel (voice data)\n"       \
161         "A-bis B-Channel / Sub-channel Multiplexer\n"           \
162         "Radio Measurements\n"                                  \
163         "SCCP\n"                                                \
164         "Mobile Switching Center\n"                             \
165         "Media Gateway Control Protocol\n"                      \
166         "Hand-over\n"                                           \
167         "Database Layer\n"                                      \
168         "Reference Counting\n"                                  \
169         "GPRS Core\n"                                           \
170         "GPRS Network Service (NS)\n"                           \
171         "GPRS BSS Gateway Protocol (BSSGP)\n"                   \
172         "GPRS Logical Link Control Protocol (LLC)\n"            \
173         "GPRS Sub-Network Dependent Control Protocol (SNDCP)\n" \
174         "ISDN User Part (ISUP)\n"                               \
175         "SCTP M2UA\n"                                           \
176         "Trace message IO\n"                                    \
177         "Global setting for all subsytems\n"
178
179 #define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)"
180 #define LEVELS_HELP     \
181         "Log simply everything\n"                               \
182         "Log debug messages and higher levels\n"                \
183         "Log informational messages and higher levels\n"        \
184         "Log noticable messages and higher levels\n"            \
185         "Log error messages and higher levels\n"                \
186         "Log only fatal messages\n"
187
188 static int _logging_level(struct vty *vty, struct log_target *dbg,
189                           const char *cat_str, const char *lvl_str)
190 {
191         int category = log_parse_category(cat_str);
192         int level = log_parse_level(lvl_str);
193
194         if (level < 0) {
195                 vty_out(vty, "Invalid level `%s'%s", lvl_str, VTY_NEWLINE);
196                 return CMD_WARNING;
197         }
198
199         /* Check for special case where we want to set global log level */
200         if (!strcmp(cat_str, "all")) {
201                 log_set_log_level(dbg, level);
202                 return CMD_SUCCESS;
203         }
204
205         if (category < 0) {
206                 vty_out(vty, "Invalid category `%s'%s", cat_str, VTY_NEWLINE);
207                 return CMD_WARNING;
208         }
209
210         dbg->categories[category].enabled = 1;
211         dbg->categories[category].loglevel = level;
212
213         return CMD_SUCCESS;
214 }
215
216 DEFUN(logging_level,
217       logging_level_cmd,
218       "logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS,
219       LOGGING_STR
220       "Set the log level for a specified category\n"
221       CATEGORIES_HELP
222       LEVELS_HELP)
223 {
224         struct telnet_connection *conn;
225
226         conn = (struct telnet_connection *) vty->priv;
227         if (!conn->dbg) {
228                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
229                 return CMD_WARNING;
230         }
231
232         return _logging_level(vty, conn->dbg, argv[0], argv[1]);
233 }
234
235 DEFUN(logging_set_category_mask,
236       logging_set_category_mask_cmd,
237       "logging set log mask MASK",
238         LOGGING_STR
239       "Decide which categories to output.\n")
240 {
241         struct telnet_connection *conn;
242
243         conn = (struct telnet_connection *) vty->priv;
244         if (!conn->dbg) {
245                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
246                 return CMD_WARNING;
247         }
248
249         log_parse_category_mask(conn->dbg, argv[0]);
250         return CMD_SUCCESS;
251 }
252
253 DEFUN(diable_logging,
254       disable_logging_cmd,
255       "logging disable",
256         LOGGING_STR
257       "Disables logging to this vty\n")
258 {
259         struct telnet_connection *conn;
260
261         conn = (struct telnet_connection *) vty->priv;
262         if (!conn->dbg) {
263                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
264                 return CMD_WARNING;
265         }
266
267         log_del_target(conn->dbg);
268         talloc_free(conn->dbg);
269         conn->dbg = NULL;
270         return CMD_SUCCESS;
271 }
272
273 static void vty_print_logtarget(struct vty *vty, const struct log_info *info,
274                                 const struct log_target *tgt)
275 {
276         unsigned int i;
277
278         vty_out(vty, " Global Loglevel: %s%s",
279                 log_level_str(tgt->loglevel), VTY_NEWLINE);
280         vty_out(vty, " Use color: %s, Print Timestamp: %s%s",
281                 tgt->use_color ? "On" : "Off",
282                 tgt->print_timestamp ? "On" : "Off", VTY_NEWLINE);
283
284         vty_out(vty, " Log Level specific information:%s", VTY_NEWLINE);
285
286         for (i = 0; i < info->num_cat; i++) {
287                 const struct log_category *cat = &tgt->categories[i];
288                 vty_out(vty, "  %-10s %-10s %-8s %s%s",
289                         info->cat[i].name+1, log_level_str(cat->loglevel),
290                         cat->enabled ? "Enabled" : "Disabled",
291                         info->cat[i].description,
292                         VTY_NEWLINE);
293         }
294 }
295
296 #define SHOW_LOG_STR "Show current logging configuration\n"
297
298 DEFUN(show_logging_vty,
299       show_logging_vty_cmd,
300       "show logging vty",
301         SHOW_STR SHOW_LOG_STR
302         "Show current logging configuration for this vty\n")
303 {
304         struct telnet_connection *conn;
305
306         conn = (struct telnet_connection *) vty->priv;
307         if (!conn->dbg) {
308                 vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE);
309                 return CMD_WARNING;
310         }
311         vty_print_logtarget(vty, osmo_log_info, conn->dbg);
312
313         return CMD_SUCCESS;
314 }
315
316 gDEFUN(cfg_description, cfg_description_cmd,
317         "description .TEXT",
318         "Save human-readable decription of the object\n")
319 {
320         char **dptr = vty->index_sub;
321
322         if (!dptr) {
323                 vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
324                 return CMD_WARNING;
325         }
326
327         *dptr = argv_concat(argv, argc, 0);
328         if (!dptr)
329                 return CMD_WARNING;
330
331         return CMD_SUCCESS;
332 }
333
334 gDEFUN(cfg_no_description, cfg_no_description_cmd,
335         "no description",
336         NO_STR
337         "Remove description of the object\n")
338 {
339         char **dptr = vty->index_sub;
340
341         if (!dptr) {
342                 vty_out(vty, "vty->index_sub == NULL%s", VTY_NEWLINE);
343                 return CMD_WARNING;
344         }
345
346         if (*dptr) {
347                 talloc_free(*dptr);
348                 *dptr = NULL;
349         }
350
351         return CMD_SUCCESS;
352 }
353
354 /* Support for configuration of log targets != the current vty */
355
356 struct cmd_node cfg_log_node = {
357         CFG_LOG_NODE,
358         "%s(config-log)# ",
359         1
360 };
361
362 DEFUN(cfg_log_fltr_all,
363       cfg_log_fltr_all_cmd,
364       "logging filter all (0|1)",
365         LOGGING_STR FILTER_STR
366         "Do you want to log all messages?\n"
367         "Only print messages matched by other filters\n"
368         "Bypass filter and print all messages\n")
369 {
370         struct log_target *dbg = vty->index;
371
372         log_set_all_filter(dbg, atoi(argv[0]));
373         return CMD_SUCCESS;
374 }
375
376 DEFUN(cfg_log_use_clr,
377       cfg_log_use_clr_cmd,
378       "logging color (0|1)",
379         LOGGING_STR "Configure color-printing for log messages\n"
380       "Don't use color for printing messages\n"
381       "Use color for printing messages\n")
382 {
383         struct log_target *dbg = vty->index;
384
385         log_set_use_color(dbg, atoi(argv[0]));
386         return CMD_SUCCESS;
387 }
388
389 DEFUN(cfg_log_timestamp,
390       cfg_log_timestamp_cmd,
391       "logging timestamp (0|1)",
392         LOGGING_STR "Configure log message timestamping\n"
393         "Don't prefix each log message\n"
394         "Prefix each log message with current timestamp\n")
395 {
396         struct log_target *dbg = vty->index;
397
398         log_set_print_timestamp(dbg, atoi(argv[0]));
399         return CMD_SUCCESS;
400 }
401
402 DEFUN(cfg_log_level,
403       cfg_log_level_cmd,
404       "logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS,
405       LOGGING_STR
406       "Set the log level for a specified category\n"
407       CATEGORIES_HELP
408       LEVELS_HELP)
409 {
410         struct log_target *dbg = vty->index;
411
412         return _logging_level(vty, dbg, argv[0], argv[1]);
413 }
414
415 #ifdef HAVE_SYSLOG_H
416
417 #include <syslog.h>
418
419 static const int local_sysl_map[] = {
420         [0] = LOG_LOCAL0,
421         [1] = LOG_LOCAL1,
422         [2] = LOG_LOCAL2,
423         [3] = LOG_LOCAL3,
424         [4] = LOG_LOCAL4,
425         [5] = LOG_LOCAL5,
426         [6] = LOG_LOCAL6,
427         [7] = LOG_LOCAL7
428 };
429
430 static int _cfg_log_syslog(struct vty *vty, int facility)
431 {
432         struct log_target *tgt;
433
434         /* First delete the old syslog target, if any */
435         tgt = log_target_find(LOG_TGT_TYPE_SYSLOG, NULL);
436         if (tgt)
437                 log_target_destroy(tgt);
438
439         tgt = log_target_create_syslog("FIXME", 0, facility);
440         if (!tgt) {
441                 vty_out(vty, "%% Unable to open syslog%s", VTY_NEWLINE);
442                 return CMD_WARNING;
443         }
444         log_add_target(tgt);
445
446         vty->index = tgt;
447         vty->node = CFG_LOG_NODE;
448
449         return CMD_SUCCESS;
450 }
451
452 DEFUN(cfg_log_syslog_local, cfg_log_syslog_local_cmd,
453       "log syslog local <0-7>",
454         LOG_STR "Logging via syslog\n" "Syslog LOCAL facility\n"
455         "Local facility number\n")
456 {
457         int local = atoi(argv[0]);
458         int facility = local_sysl_map[local];
459
460         return _cfg_log_syslog(vty, facility);
461 }
462
463 static struct value_string sysl_level_names[] = {
464         { LOG_AUTHPRIV, "authpriv" },
465         { LOG_CRON,     "cron" },
466         { LOG_DAEMON,   "daemon" },
467         { LOG_FTP,      "ftp" },
468         { LOG_LPR,      "lpr" },
469         { LOG_MAIL,     "mail" },
470         { LOG_NEWS,     "news" },
471         { LOG_USER,     "user" },
472         { LOG_UUCP,     "uucp" },
473         /* only for value -> string conversion */
474         { LOG_LOCAL0,   "local 0" },
475         { LOG_LOCAL1,   "local 1" },
476         { LOG_LOCAL2,   "local 2" },
477         { LOG_LOCAL3,   "local 3" },
478         { LOG_LOCAL4,   "local 4" },
479         { LOG_LOCAL5,   "local 5" },
480         { LOG_LOCAL6,   "local 6" },
481         { LOG_LOCAL7,   "local 7" },
482         { 0, NULL }
483 };
484
485 DEFUN(cfg_log_syslog, cfg_log_syslog_cmd,
486       "log syslog (authpriv|cron|daemon|ftp|lpr|mail|news|user|uucp)",
487         LOG_STR "Logging via syslog\n")
488 {
489         int facility = get_string_value(sysl_level_names, argv[0]);
490
491         return _cfg_log_syslog(vty, facility);
492 }
493
494 DEFUN(cfg_no_log_syslog, cfg_no_log_syslog_cmd,
495         "no log syslog",
496         NO_STR LOG_STR "Logging via syslog\n")
497 {
498         struct log_target *tgt;
499
500         tgt = log_target_find(LOG_TGT_TYPE_SYSLOG, NULL);
501         if (!tgt) {
502                 vty_out(vty, "%% No syslog target found%s",
503                         VTY_NEWLINE);
504                 return CMD_WARNING;
505         }
506
507         log_target_destroy(tgt);
508
509         return CMD_SUCCESS;
510 }
511 #endif /* HAVE_SYSLOG_H */
512
513 DEFUN(cfg_log_stderr, cfg_log_stderr_cmd,
514         "log stderr",
515         LOG_STR "Logging via STDERR of the process\n")
516 {
517         struct log_target *tgt;
518
519         tgt = log_target_find(LOG_TGT_TYPE_STDERR, NULL);
520         if (!tgt) {
521                 tgt = log_target_create_stderr();
522                 if (!tgt) {
523                         vty_out(vty, "%% Unable to create stderr log%s",
524                                 VTY_NEWLINE);
525                         return CMD_WARNING;
526                 }
527                 log_add_target(tgt);
528         }
529
530         vty->index = tgt;
531         vty->node = CFG_LOG_NODE;
532
533         return CMD_SUCCESS;
534 }
535
536 DEFUN(cfg_no_log_stderr, cfg_no_log_stderr_cmd,
537         "no log stderr",
538         NO_STR LOG_STR "Logging via STDERR of the process\n")
539 {
540         struct log_target *tgt;
541
542         tgt = log_target_find(LOG_TGT_TYPE_STDERR, NULL);
543         if (!tgt) {
544                 vty_out(vty, "%% No stderr logging active%s", VTY_NEWLINE);
545                 return CMD_WARNING;
546         }
547
548         log_target_destroy(tgt);
549
550         return CMD_SUCCESS;
551 }
552
553 DEFUN(cfg_log_file, cfg_log_file_cmd,
554         "log file .FILENAME",
555         LOG_STR "Logging to text file\n" "Filename\n")
556 {
557         const char *fname = argv[0];
558         struct log_target *tgt;
559
560         tgt = log_target_find(LOG_TGT_TYPE_FILE, fname);
561         if (!tgt) {
562                 tgt = log_target_create_file(fname);
563                 if (!tgt) {
564                         vty_out(vty, "%% Unable to create file `%s'%s",
565                                 fname, VTY_NEWLINE);
566                         return CMD_WARNING;
567                 }
568                 log_add_target(tgt);
569         }
570
571         vty->index = tgt;
572         vty->node = CFG_LOG_NODE;
573
574         return CMD_SUCCESS;
575 }
576
577
578 DEFUN(cfg_no_log_file, cfg_no_log_file_cmd,
579         "no log file .FILENAME",
580         NO_STR LOG_STR "Logging to text file\n" "Filename\n")
581 {
582         const char *fname = argv[0];
583         struct log_target *tgt;
584
585         tgt = log_target_find(LOG_TGT_TYPE_FILE, fname);
586         if (!tgt) {
587                 vty_out(vty, "%% No such log file `%s'%s",
588                         fname, VTY_NEWLINE);
589                 return CMD_WARNING;
590         }
591
592         log_target_destroy(tgt);
593
594         return CMD_SUCCESS;
595 }
596
597 static int config_write_log_single(struct vty *vty, struct log_target *tgt)
598 {
599         int i;
600         char level_lower[32];
601
602         switch (tgt->type) {
603         case LOG_TGT_TYPE_VTY:
604                 return 1;
605                 break;
606         case LOG_TGT_TYPE_STDERR:
607                 vty_out(vty, "log stderr%s", VTY_NEWLINE);
608                 break;
609         case LOG_TGT_TYPE_SYSLOG:
610 #ifdef HAVE_SYSLOG_H
611                 vty_out(vty, "log syslog %s%s",
612                         get_value_string(sysl_level_names,
613                                          tgt->tgt_syslog.facility),
614                         VTY_NEWLINE);
615 #endif
616                 break;
617         case LOG_TGT_TYPE_FILE:
618                 vty_out(vty, "log file %s%s", tgt->tgt_file.fname, VTY_NEWLINE);
619                 break;
620         }
621
622         vty_out(vty, "  logging color %u%s", tgt->use_color ? 1 : 0,
623                 VTY_NEWLINE);
624         vty_out(vty, "  logging timestamp %u%s", tgt->print_timestamp ? 1 : 0,
625                 VTY_NEWLINE);
626
627         /* stupid old osmo logging API uses uppercase strings... */
628         osmo_str2lower(level_lower, log_level_str(tgt->loglevel));
629         vty_out(vty, "  logging level all %s%s", level_lower, VTY_NEWLINE);
630
631         for (i = 0; i < osmo_log_info->num_cat; i++) {
632                 const struct log_category *cat = &tgt->categories[i];
633                 char cat_lower[32];
634
635                 /* stupid old osmo logging API uses uppercase strings... */
636                 osmo_str2lower(cat_lower, osmo_log_info->cat[i].name+1);
637                 osmo_str2lower(level_lower, log_level_str(cat->loglevel));
638
639                 vty_out(vty, "  logging level %s %s%s", cat_lower, level_lower,
640                         VTY_NEWLINE);
641         }
642
643         /* FIXME: levels */
644
645         return 1;
646 }
647
648 static int config_write_log(struct vty *vty)
649 {
650         struct log_target *dbg = vty->index;
651
652         llist_for_each_entry(dbg, &osmo_log_target_list, entry)
653                 config_write_log_single(vty, dbg);
654
655         return 1;
656 }
657
658 void logging_vty_add_cmds()
659 {
660         install_element_ve(&enable_logging_cmd);
661         install_element_ve(&disable_logging_cmd);
662         install_element_ve(&logging_fltr_all_cmd);
663         install_element_ve(&logging_use_clr_cmd);
664         install_element_ve(&logging_prnt_timestamp_cmd);
665         install_element_ve(&logging_set_category_mask_cmd);
666         install_element_ve(&logging_level_cmd);
667         install_element_ve(&show_logging_vty_cmd);
668
669         install_node(&cfg_log_node, config_write_log);
670         install_element(CFG_LOG_NODE, &cfg_log_fltr_all_cmd);
671         install_element(CFG_LOG_NODE, &cfg_log_use_clr_cmd);
672         install_element(CFG_LOG_NODE, &cfg_log_timestamp_cmd);
673         install_element(CFG_LOG_NODE, &cfg_log_level_cmd);
674
675         install_element(CONFIG_NODE, &cfg_log_stderr_cmd);
676         install_element(CONFIG_NODE, &cfg_no_log_stderr_cmd);
677         install_element(CONFIG_NODE, &cfg_log_file_cmd);
678         install_element(CONFIG_NODE, &cfg_no_log_file_cmd);
679 #ifdef HAVE_SYSLOG_H
680         install_element(CONFIG_NODE, &cfg_log_syslog_cmd);
681         install_element(CONFIG_NODE, &cfg_log_syslog_local_cmd);
682         install_element(CONFIG_NODE, &cfg_no_log_syslog_cmd);
683 #endif
684 }