3 * Copyright (C) 2019 Cumulus Networks, Inc.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "lib/log_vty.h"
26 #include "lib/zlog_targets.h"
27 #include "lib/lib_errors.h"
28 #include "lib/printfrr.h"
30 #ifndef VTYSH_EXTRACT_PL
31 #include "lib/log_vty_clippy.c"
34 #define ZLOG_MAXLVL(a, b) MAX(a, b)
36 DEFINE_HOOK(zlog_rotate
, (), ())
38 static const int log_default_lvl
= LOG_DEBUG
;
40 static int log_config_stdout_lvl
= ZLOG_DISABLED
;
41 static int log_config_syslog_lvl
= ZLOG_DISABLED
;
42 static int log_cmdline_stdout_lvl
= ZLOG_DISABLED
;
43 static int log_cmdline_syslog_lvl
= ZLOG_DISABLED
;
45 static struct zlog_cfg_file zt_file_cmdline
= {
46 .prio_min
= ZLOG_DISABLED
,
48 static struct zlog_cfg_file zt_file
= {
49 .prio_min
= ZLOG_DISABLED
,
51 static struct zlog_cfg_file zt_stdout
= {
52 .prio_min
= ZLOG_DISABLED
,
54 static struct zlog_cfg_filterfile zt_filterfile
= {
56 .prio_min
= ZLOG_DISABLED
,
60 static const char *zlog_progname
;
61 static const char *zlog_protoname
;
63 static const struct facility_map
{
67 } syslog_facilities
[] = {
68 {LOG_KERN
, "kern", 1},
69 {LOG_USER
, "user", 2},
70 {LOG_MAIL
, "mail", 1},
71 {LOG_DAEMON
, "daemon", 1},
72 {LOG_AUTH
, "auth", 1},
73 {LOG_SYSLOG
, "syslog", 1},
75 {LOG_NEWS
, "news", 1},
76 {LOG_UUCP
, "uucp", 2},
77 {LOG_CRON
, "cron", 1},
81 {LOG_LOCAL0
, "local0", 6},
82 {LOG_LOCAL1
, "local1", 6},
83 {LOG_LOCAL2
, "local2", 6},
84 {LOG_LOCAL3
, "local3", 6},
85 {LOG_LOCAL4
, "local4", 6},
86 {LOG_LOCAL5
, "local5", 6},
87 {LOG_LOCAL6
, "local6", 6},
88 {LOG_LOCAL7
, "local7", 6},
92 static const char * const zlog_priority
[] = {
93 "emergencies", "alerts", "critical", "errors", "warnings",
94 "notifications", "informational", "debugging", NULL
,
97 static const char *facility_name(int facility
)
99 const struct facility_map
*fm
;
101 for (fm
= syslog_facilities
; fm
->name
; fm
++)
102 if (fm
->facility
== facility
)
107 static int facility_match(const char *str
)
109 const struct facility_map
*fm
;
111 for (fm
= syslog_facilities
; fm
->name
; fm
++)
112 if (!strncmp(str
, fm
->name
, fm
->match
))
117 int log_level_match(const char *s
)
121 for (level
= 0; zlog_priority
[level
] != NULL
; level
++)
122 if (!strncmp(s
, zlog_priority
[level
], 2))
124 return ZLOG_DISABLED
;
127 void zlog_rotate(void)
129 zlog_file_rotate(&zt_file
);
130 zlog_file_rotate(&zt_filterfile
.parent
);
131 hook_call(zlog_rotate
);
135 void log_show_syslog(struct vty
*vty
)
137 int level
= zlog_syslog_get_prio_min();
139 vty_out(vty
, "Syslog logging: ");
140 if (level
== ZLOG_DISABLED
)
141 vty_out(vty
, "disabled\n");
143 vty_out(vty
, "level %s, facility %s, ident %s\n",
144 zlog_priority
[level
],
145 facility_name(zlog_syslog_get_facility()),
153 "Show current logging configuration\n")
155 log_show_syslog(vty
);
157 vty_out(vty
, "Stdout logging: ");
158 if (zt_stdout
.prio_min
== ZLOG_DISABLED
)
159 vty_out(vty
, "disabled");
161 vty_out(vty
, "level %s",
162 zlog_priority
[zt_stdout
.prio_min
]);
165 vty_out(vty
, "File logging: ");
166 if (zt_file
.prio_min
== ZLOG_DISABLED
|| !zt_file
.filename
)
167 vty_out(vty
, "disabled");
169 vty_out(vty
, "level %s, filename %s",
170 zlog_priority
[zt_file
.prio_min
], zt_file
.filename
);
173 if (zt_filterfile
.parent
.prio_min
!= ZLOG_DISABLED
174 && zt_filterfile
.parent
.filename
)
175 vty_out(vty
, "Filtered-file logging: level %s, filename %s\n",
176 zlog_priority
[zt_filterfile
.parent
.prio_min
],
177 zt_filterfile
.parent
.filename
);
179 if (log_cmdline_syslog_lvl
!= ZLOG_DISABLED
)
181 "From command line: \"--log syslog --log-level %s\"\n",
182 zlog_priority
[log_cmdline_syslog_lvl
]);
183 if (log_cmdline_stdout_lvl
!= ZLOG_DISABLED
)
185 "From command line: \"--log stdout --log-level %s\"\n",
186 zlog_priority
[log_cmdline_stdout_lvl
]);
187 if (zt_file_cmdline
.prio_min
!= ZLOG_DISABLED
)
189 "From command line: \"--log file:%s --log-level %s\"\n",
190 zt_file_cmdline
.filename
,
191 zlog_priority
[zt_file_cmdline
.prio_min
]);
193 vty_out(vty
, "Protocol name: %s\n", zlog_protoname
);
194 vty_out(vty
, "Record priority: %s\n",
195 (zt_file
.record_priority
? "enabled" : "disabled"));
196 vty_out(vty
, "Timestamp precision: %d\n", zt_file
.ts_subsec
);
200 DEFPY (config_log_stdout
,
201 config_log_stdout_cmd
,
202 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
204 "Set stdout logging level\n"
210 level
= log_level_match(levelarg
);
211 if (level
== ZLOG_DISABLED
)
212 return CMD_ERR_NO_MATCH
;
214 level
= log_default_lvl
;
216 log_config_stdout_lvl
= level
;
217 zt_stdout
.prio_min
= ZLOG_MAXLVL(log_config_stdout_lvl
,
218 log_cmdline_stdout_lvl
);
219 zlog_file_set_other(&zt_stdout
);
223 DEFUN (no_config_log_stdout
,
224 no_config_log_stdout_cmd
,
225 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
228 "Cancel logging to stdout\n"
231 log_config_stdout_lvl
= ZLOG_DISABLED
;
232 zt_stdout
.prio_min
= ZLOG_MAXLVL(log_config_stdout_lvl
,
233 log_cmdline_stdout_lvl
);
234 zlog_file_set_other(&zt_stdout
);
238 DEFUN_HIDDEN (config_log_monitor
,
239 config_log_monitor_cmd
,
240 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
242 "Set terminal line (monitor) logging level\n"
245 vty_out(vty
, "%% \"log monitor\" is deprecated and does nothing.\n");
249 DEFUN_HIDDEN (no_config_log_monitor
,
250 no_config_log_monitor_cmd
,
251 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
254 "Disable terminal line (monitor) logging\n"
260 static int set_log_file(struct zlog_cfg_file
*target
, struct vty
*vty
,
261 const char *fname
, int loglevel
)
264 const char *fullpath
;
267 /* Path detection. */
268 if (!IS_DIRECTORY_SEP(*fname
)) {
269 char cwd
[MAXPATHLEN
+ 1];
271 cwd
[MAXPATHLEN
] = '\0';
273 if (getcwd(cwd
, MAXPATHLEN
) == NULL
) {
274 flog_err_sys(EC_LIB_SYSTEM_CALL
,
275 "config_log_file: Unable to alloc mem!");
276 return CMD_WARNING_CONFIG_FAILED
;
279 p
= XMALLOC(MTYPE_TMP
, strlen(cwd
) + strlen(fname
) + 2);
280 sprintf(p
, "%s/%s", cwd
, fname
);
285 target
->prio_min
= loglevel
;
286 ok
= zlog_file_set_filename(target
, fullpath
);
292 vty_out(vty
, "can't open logfile %s\n", fname
);
293 return CMD_WARNING_CONFIG_FAILED
;
298 void command_setup_early_logging(const char *dest
, const char *level
)
306 nlevel
= log_level_match(level
);
308 if (nlevel
== ZLOG_DISABLED
) {
309 fprintf(stderr
, "invalid log level \"%s\"\n", level
);
313 nlevel
= log_default_lvl
;
318 sep
= strchr(dest
, ':');
319 len
= sep
? (int)(sep
- dest
) : (int)strlen(dest
);
321 snprintfrr(type
, sizeof(type
), "%.*s", len
, dest
);
323 if (strcmp(type
, "stdout") == 0) {
324 log_cmdline_stdout_lvl
= nlevel
;
325 zt_stdout
.prio_min
= ZLOG_MAXLVL(log_config_stdout_lvl
,
326 log_cmdline_stdout_lvl
);
327 zlog_file_set_other(&zt_stdout
);
330 if (strcmp(type
, "syslog") == 0) {
331 log_cmdline_syslog_lvl
= nlevel
;
332 zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl
,
333 log_cmdline_syslog_lvl
));
336 if (strcmp(type
, "file") == 0 && sep
) {
338 set_log_file(&zt_file_cmdline
, NULL
, sep
, nlevel
);
342 fprintf(stderr
, "invalid log target \"%s\" (\"%s\")\n", type
, dest
);
346 DEFUN (clear_log_cmdline
,
347 clear_log_cmdline_cmd
,
348 "clear log cmdline-targets",
351 "Disable log targets specified at startup by --log option\n")
353 zt_file_cmdline
.prio_min
= ZLOG_DISABLED
;
354 zlog_file_set_other(&zt_file_cmdline
);
356 log_cmdline_syslog_lvl
= ZLOG_DISABLED
;
357 zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl
,
358 log_cmdline_syslog_lvl
));
360 log_cmdline_stdout_lvl
= ZLOG_DISABLED
;
361 zt_stdout
.prio_min
= ZLOG_MAXLVL(log_config_stdout_lvl
,
362 log_cmdline_stdout_lvl
);
363 zlog_file_set_other(&zt_stdout
);
368 DEFPY (config_log_file
,
370 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
376 int level
= log_default_lvl
;
379 level
= log_level_match(levelarg
);
380 if (level
== ZLOG_DISABLED
)
381 return CMD_ERR_NO_MATCH
;
383 return set_log_file(&zt_file
, vty
, filename
, level
);
386 DEFUN (no_config_log_file
,
387 no_config_log_file_cmd
,
388 "no log file [FILENAME [LEVEL]]",
391 "Cancel logging to file\n"
392 "Logging file name\n"
395 zt_file
.prio_min
= ZLOG_DISABLED
;
396 zlog_file_set_other(&zt_file
);
400 DEFPY (config_log_syslog
,
401 config_log_syslog_cmd
,
402 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
404 "Set syslog logging level\n"
410 level
= log_level_match(levelarg
);
412 if (level
== ZLOG_DISABLED
)
413 return CMD_ERR_NO_MATCH
;
415 level
= log_default_lvl
;
417 log_config_syslog_lvl
= level
;
418 zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl
,
419 log_cmdline_syslog_lvl
));
423 DEFUN (no_config_log_syslog
,
424 no_config_log_syslog_cmd
,
425 "no log syslog [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>] [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
428 "Cancel logging to syslog\n"
432 log_config_syslog_lvl
= ZLOG_DISABLED
;
433 zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl
,
434 log_cmdline_syslog_lvl
));
438 DEFPY (config_log_facility
,
439 config_log_facility_cmd
,
440 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>$facilityarg",
442 "Facility parameter for syslog messages\n"
445 int facility
= facility_match(facilityarg
);
447 zlog_syslog_set_facility(facility
);
451 DEFUN (no_config_log_facility
,
452 no_config_log_facility_cmd
,
453 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
456 "Reset syslog facility to default (daemon)\n"
459 zlog_syslog_set_facility(LOG_DAEMON
);
463 DEFUN (config_log_record_priority
,
464 config_log_record_priority_cmd
,
465 "log record-priority",
467 "Log the priority of the message within the message\n")
469 zt_file
.record_priority
= true;
470 zlog_file_set_other(&zt_file
);
471 zt_stdout
.record_priority
= true;
472 zlog_file_set_other(&zt_stdout
);
473 zt_filterfile
.parent
.record_priority
= true;
474 zlog_file_set_other(&zt_filterfile
.parent
);
478 DEFUN (no_config_log_record_priority
,
479 no_config_log_record_priority_cmd
,
480 "no log record-priority",
483 "Do not log the priority of the message within the message\n")
485 zt_file
.record_priority
= false;
486 zlog_file_set_other(&zt_file
);
487 zt_stdout
.record_priority
= false;
488 zlog_file_set_other(&zt_stdout
);
489 zt_filterfile
.parent
.record_priority
= false;
490 zlog_file_set_other(&zt_filterfile
.parent
);
494 DEFPY (config_log_timestamp_precision
,
495 config_log_timestamp_precision_cmd
,
496 "log timestamp precision (0-6)",
498 "Timestamp configuration\n"
499 "Set the timestamp precision\n"
500 "Number of subsecond digits\n")
502 zt_file
.ts_subsec
= precision
;
503 zlog_file_set_other(&zt_file
);
504 zt_stdout
.ts_subsec
= precision
;
505 zlog_file_set_other(&zt_stdout
);
506 zt_filterfile
.parent
.ts_subsec
= precision
;
507 zlog_file_set_other(&zt_filterfile
.parent
);
511 DEFUN (no_config_log_timestamp_precision
,
512 no_config_log_timestamp_precision_cmd
,
513 "no log timestamp precision [(0-6)]",
516 "Timestamp configuration\n"
517 "Reset the timestamp precision to the default value of 0\n"
518 "Number of subsecond digits\n")
520 zt_file
.ts_subsec
= 0;
521 zlog_file_set_other(&zt_file
);
522 zt_stdout
.ts_subsec
= 0;
523 zlog_file_set_other(&zt_stdout
);
524 zt_filterfile
.parent
.ts_subsec
= 0;
525 zlog_file_set_other(&zt_filterfile
.parent
);
529 DEFPY (config_log_filterfile
,
530 config_log_filterfile_cmd
,
531 "log filtered-file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
533 "Logging to file with string filter\n"
537 int level
= log_default_lvl
;
540 level
= log_level_match(levelarg
);
541 if (level
== ZLOG_DISABLED
)
542 return CMD_ERR_NO_MATCH
;
544 return set_log_file(&zt_filterfile
.parent
, vty
, filename
, level
);
547 DEFUN (no_config_log_filterfile
,
548 no_config_log_filterfile_cmd
,
549 "no log filtered-file [FILENAME [LEVEL]]",
552 "Cancel logging to file with string filter\n"
553 "Logging file name\n"
556 zt_filterfile
.parent
.prio_min
= ZLOG_DISABLED
;
557 zlog_file_set_other(&zt_filterfile
.parent
);
563 "[no] log-filter WORD$filter",
566 "String to filter by\n")
571 ret
= zlog_filter_del(filter
);
573 ret
= zlog_filter_add(filter
);
576 vty_out(vty
, "%% filter table full\n");
578 } else if (ret
!= 0) {
579 vty_out(vty
, "%% failed to %s log filter\n",
580 (no
? "remove" : "apply"));
584 vty_out(vty
, " %s\n", filter
);
588 /* Clear all log filters */
589 DEFPY (log_filter_clear
,
590 log_filter_clear_cmd
,
599 /* Show log filter */
600 DEFPY (show_log_filter
,
606 char log_filters
[ZLOG_FILTERS_MAX
* (ZLOG_FILTER_LENGTH_MAX
+ 3)] = "";
609 len
= zlog_filter_dump(log_filters
, sizeof(log_filters
));
612 vty_out(vty
, "%% failed to get filters\n");
617 vty_out(vty
, "%s", log_filters
);
622 void log_config_write(struct vty
*vty
)
624 bool show_cmdline_hint
= false;
626 if (zt_file
.prio_min
!= ZLOG_DISABLED
&& zt_file
.filename
) {
627 vty_out(vty
, "log file %s", zt_file
.filename
);
629 if (zt_file
.prio_min
!= log_default_lvl
)
630 vty_out(vty
, " %s", zlog_priority
[zt_file
.prio_min
]);
634 if (zt_filterfile
.parent
.prio_min
!= ZLOG_DISABLED
635 && zt_filterfile
.parent
.filename
) {
636 vty_out(vty
, "log filtered-file %s",
637 zt_filterfile
.parent
.filename
);
639 if (zt_filterfile
.parent
.prio_min
!= log_default_lvl
)
641 zlog_priority
[zt_filterfile
.parent
.prio_min
]);
645 if (log_config_stdout_lvl
!= ZLOG_DISABLED
) {
646 vty_out(vty
, "log stdout");
648 if (log_config_stdout_lvl
!= log_default_lvl
)
650 zlog_priority
[log_config_stdout_lvl
]);
654 if (log_config_syslog_lvl
!= ZLOG_DISABLED
) {
655 vty_out(vty
, "log syslog");
657 if (log_config_syslog_lvl
!= log_default_lvl
)
659 zlog_priority
[log_config_syslog_lvl
]);
663 if (log_cmdline_syslog_lvl
!= ZLOG_DISABLED
) {
665 "! \"log syslog %s\" enabled by \"--log\" startup option\n",
666 zlog_priority
[log_cmdline_syslog_lvl
]);
667 show_cmdline_hint
= true;
669 if (log_cmdline_stdout_lvl
!= ZLOG_DISABLED
) {
671 "! \"log stdout %s\" enabled by \"--log\" startup option\n",
672 zlog_priority
[log_cmdline_stdout_lvl
]);
673 show_cmdline_hint
= true;
675 if (zt_file_cmdline
.prio_min
!= ZLOG_DISABLED
) {
677 "! \"log file %s %s\" enabled by \"--log\" startup option\n",
678 zt_file_cmdline
.filename
,
679 zlog_priority
[zt_file_cmdline
.prio_min
]);
680 show_cmdline_hint
= true;
682 if (show_cmdline_hint
)
684 "! use \"clear log cmdline-targets\" to remove this target\n");
686 if (zlog_syslog_get_facility() != LOG_DAEMON
)
687 vty_out(vty
, "log facility %s\n",
688 facility_name(zlog_syslog_get_facility()));
690 if (zt_file
.record_priority
== 1)
691 vty_out(vty
, "log record-priority\n");
693 if (zt_file
.ts_subsec
> 0)
694 vty_out(vty
, "log timestamp precision %d\n",
698 static int log_vty_init(const char *progname
, const char *protoname
,
699 unsigned short instance
, uid_t uid
, gid_t gid
)
701 zlog_progname
= progname
;
702 zlog_protoname
= protoname
;
704 zlog_filterfile_init(&zt_filterfile
);
706 zlog_file_set_fd(&zt_stdout
, STDOUT_FILENO
);
710 __attribute__((_CONSTRUCTOR(475))) static void log_vty_preinit(void)
712 hook_register(zlog_init
, log_vty_init
);
715 void log_cmd_init(void)
717 install_element(VIEW_NODE
, &show_logging_cmd
);
718 install_element(ENABLE_NODE
, &clear_log_cmdline_cmd
);
720 install_element(CONFIG_NODE
, &config_log_stdout_cmd
);
721 install_element(CONFIG_NODE
, &no_config_log_stdout_cmd
);
722 install_element(CONFIG_NODE
, &config_log_monitor_cmd
);
723 install_element(CONFIG_NODE
, &no_config_log_monitor_cmd
);
724 install_element(CONFIG_NODE
, &config_log_file_cmd
);
725 install_element(CONFIG_NODE
, &no_config_log_file_cmd
);
726 install_element(CONFIG_NODE
, &config_log_syslog_cmd
);
727 install_element(CONFIG_NODE
, &no_config_log_syslog_cmd
);
728 install_element(CONFIG_NODE
, &config_log_facility_cmd
);
729 install_element(CONFIG_NODE
, &no_config_log_facility_cmd
);
730 install_element(CONFIG_NODE
, &config_log_record_priority_cmd
);
731 install_element(CONFIG_NODE
, &no_config_log_record_priority_cmd
);
732 install_element(CONFIG_NODE
, &config_log_timestamp_precision_cmd
);
733 install_element(CONFIG_NODE
, &no_config_log_timestamp_precision_cmd
);
735 install_element(VIEW_NODE
, &show_log_filter_cmd
);
736 install_element(CONFIG_NODE
, &log_filter_cmd
);
737 install_element(CONFIG_NODE
, &log_filter_clear_cmd
);
738 install_element(CONFIG_NODE
, &config_log_filterfile_cmd
);
739 install_element(CONFIG_NODE
, &no_config_log_filterfile_cmd
);