Line data Source code
1 : /*
2 : * Logging - VTY code
3 : * Copyright (C) 2019 Cumulus Networks, Inc.
4 : * Stephen Worley
5 : *
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)
9 : * any later version.
10 : *
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
14 : * more details.
15 : *
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
19 : */
20 :
21 : #include <zebra.h>
22 :
23 : #include "lib/log_vty.h"
24 : #include "command.h"
25 : #include "lib/log.h"
26 : #include "lib/zlog_targets.h"
27 : #include "lib/zlog_5424.h"
28 : #include "lib/lib_errors.h"
29 : #include "lib/printfrr.h"
30 : #include "lib/systemd.h"
31 :
32 : #include "lib/log_vty_clippy.c"
33 :
34 : #define ZLOG_MAXLVL(a, b) MAX(a, b)
35 :
36 0 : DEFINE_HOOK(zlog_rotate, (), ());
37 0 : DEFINE_HOOK(zlog_cli_show, (struct vty * vty), (vty));
38 :
39 : static unsigned logmsgs_with_persist_bt;
40 :
41 : static const int log_default_lvl = LOG_DEBUG;
42 :
43 : static int log_config_stdout_lvl = ZLOG_DISABLED;
44 : static int log_config_syslog_lvl = ZLOG_DISABLED;
45 : static int log_cmdline_stdout_lvl = ZLOG_DISABLED;
46 : static int log_cmdline_syslog_lvl = ZLOG_DISABLED;
47 :
48 : static struct zlog_cfg_file zt_file_cmdline = {
49 : .prio_min = ZLOG_DISABLED,
50 : };
51 : static struct zlog_cfg_file zt_file = {
52 : .prio_min = ZLOG_DISABLED,
53 : };
54 : static struct zlog_cfg_filterfile zt_filterfile = {
55 : .parent = {
56 : .prio_min = ZLOG_DISABLED,
57 : },
58 : };
59 :
60 : static struct zlog_cfg_file zt_stdout_file = {
61 : .prio_min = ZLOG_DISABLED,
62 : };
63 : static struct zlog_cfg_5424 zt_stdout_journald = {
64 : .prio_min = ZLOG_DISABLED,
65 :
66 : .fmt = ZLOG_FMT_JOURNALD,
67 : .dst = ZLOG_5424_DST_UNIX,
68 : .filename = "/run/systemd/journal/socket",
69 :
70 : /* this can't be changed through config since this target substitutes
71 : * in for the "plain" stdout target
72 : */
73 : .facility = LOG_DAEMON,
74 : .kw_version = false,
75 : .kw_location = true,
76 : .kw_uid = true,
77 : .kw_ec = true,
78 : .kw_args = true,
79 : };
80 : static bool stdout_journald_in_use;
81 :
82 : const char *zlog_progname;
83 : static const char *zlog_protoname;
84 :
85 : static const struct facility_map {
86 : int facility;
87 : const char *name;
88 : size_t match;
89 : } syslog_facilities[] = {
90 : {LOG_KERN, "kern", 1},
91 : {LOG_USER, "user", 2},
92 : {LOG_MAIL, "mail", 1},
93 : {LOG_DAEMON, "daemon", 1},
94 : {LOG_AUTH, "auth", 1},
95 : {LOG_SYSLOG, "syslog", 1},
96 : {LOG_LPR, "lpr", 2},
97 : {LOG_NEWS, "news", 1},
98 : {LOG_UUCP, "uucp", 2},
99 : {LOG_CRON, "cron", 1},
100 : #ifdef LOG_FTP
101 : {LOG_FTP, "ftp", 1},
102 : #endif
103 : {LOG_LOCAL0, "local0", 6},
104 : {LOG_LOCAL1, "local1", 6},
105 : {LOG_LOCAL2, "local2", 6},
106 : {LOG_LOCAL3, "local3", 6},
107 : {LOG_LOCAL4, "local4", 6},
108 : {LOG_LOCAL5, "local5", 6},
109 : {LOG_LOCAL6, "local6", 6},
110 : {LOG_LOCAL7, "local7", 6},
111 : {0, NULL, 0},
112 : };
113 :
114 : static const char * const zlog_priority[] = {
115 : "emergencies", "alerts", "critical", "errors", "warnings",
116 : "notifications", "informational", "debugging", NULL,
117 : };
118 :
119 0 : const char *zlog_priority_str(int priority)
120 : {
121 0 : if (priority > LOG_DEBUG)
122 : return "???";
123 0 : return zlog_priority[priority];
124 : }
125 :
126 0 : const char *facility_name(int facility)
127 : {
128 0 : const struct facility_map *fm;
129 :
130 0 : for (fm = syslog_facilities; fm->name; fm++)
131 0 : if (fm->facility == facility)
132 0 : return fm->name;
133 : return "";
134 : }
135 :
136 0 : int facility_match(const char *str)
137 : {
138 0 : const struct facility_map *fm;
139 :
140 0 : for (fm = syslog_facilities; fm->name; fm++)
141 0 : if (!strncmp(str, fm->name, fm->match))
142 0 : return fm->facility;
143 : return -1;
144 : }
145 :
146 4 : int log_level_match(const char *s)
147 : {
148 4 : int level;
149 :
150 32 : for (level = 0; zlog_priority[level] != NULL; level++)
151 32 : if (!strncmp(s, zlog_priority[level], 2))
152 4 : return level;
153 : return ZLOG_DISABLED;
154 : }
155 :
156 0 : void zlog_rotate(void)
157 : {
158 0 : zlog_file_rotate(&zt_file);
159 0 : zlog_file_rotate(&zt_filterfile.parent);
160 0 : zlog_file_rotate(&zt_file_cmdline);
161 0 : hook_call(zlog_rotate);
162 0 : }
163 :
164 :
165 0 : void log_show_syslog(struct vty *vty)
166 : {
167 0 : int level = zlog_syslog_get_prio_min();
168 :
169 0 : vty_out(vty, "Syslog logging: ");
170 0 : if (level == ZLOG_DISABLED)
171 0 : vty_out(vty, "disabled\n");
172 : else
173 0 : vty_out(vty, "level %s, facility %s, ident %s\n",
174 0 : zlog_priority[level],
175 : facility_name(zlog_syslog_get_facility()),
176 : zlog_progname);
177 0 : }
178 :
179 0 : DEFUN_NOSH (show_logging,
180 : show_logging_cmd,
181 : "show logging",
182 : SHOW_STR
183 : "Show current logging configuration\n")
184 : {
185 0 : int stdout_prio;
186 :
187 0 : log_show_syslog(vty);
188 :
189 0 : stdout_prio = stdout_journald_in_use ? zt_stdout_journald.prio_min
190 0 : : zt_stdout_file.prio_min;
191 :
192 0 : vty_out(vty, "Stdout logging: ");
193 0 : if (stdout_prio == ZLOG_DISABLED)
194 0 : vty_out(vty, "disabled");
195 : else
196 0 : vty_out(vty, "level %s", zlog_priority[stdout_prio]);
197 0 : vty_out(vty, "\n");
198 :
199 0 : vty_out(vty, "File logging: ");
200 0 : if (zt_file.prio_min == ZLOG_DISABLED || !zt_file.filename)
201 0 : vty_out(vty, "disabled");
202 : else
203 0 : vty_out(vty, "level %s, filename %s",
204 0 : zlog_priority[zt_file.prio_min], zt_file.filename);
205 0 : vty_out(vty, "\n");
206 :
207 0 : if (zt_filterfile.parent.prio_min != ZLOG_DISABLED
208 0 : && zt_filterfile.parent.filename)
209 0 : vty_out(vty, "Filtered-file logging: level %s, filename %s\n",
210 0 : zlog_priority[zt_filterfile.parent.prio_min],
211 : zt_filterfile.parent.filename);
212 :
213 0 : if (log_cmdline_syslog_lvl != ZLOG_DISABLED)
214 0 : vty_out(vty,
215 : "From command line: \"--log syslog --log-level %s\"\n",
216 0 : zlog_priority[log_cmdline_syslog_lvl]);
217 0 : if (log_cmdline_stdout_lvl != ZLOG_DISABLED)
218 0 : vty_out(vty,
219 : "From command line: \"--log stdout --log-level %s\"\n",
220 0 : zlog_priority[log_cmdline_stdout_lvl]);
221 0 : if (zt_file_cmdline.prio_min != ZLOG_DISABLED)
222 0 : vty_out(vty,
223 : "From command line: \"--log file:%s --log-level %s\"\n",
224 : zt_file_cmdline.filename,
225 0 : zlog_priority[zt_file_cmdline.prio_min]);
226 :
227 0 : vty_out(vty, "Protocol name: %s\n", zlog_protoname);
228 0 : vty_out(vty, "Record priority: %s\n",
229 0 : (zt_file.record_priority ? "enabled" : "disabled"));
230 0 : vty_out(vty, "Timestamp precision: %d\n", zt_file.ts_subsec);
231 :
232 0 : hook_call(zlog_cli_show, vty);
233 0 : return CMD_SUCCESS;
234 : }
235 :
236 2 : static void log_stdout_apply_level(void)
237 : {
238 2 : int maxlvl;
239 :
240 2 : maxlvl = ZLOG_MAXLVL(log_config_stdout_lvl, log_cmdline_stdout_lvl);
241 :
242 2 : if (stdout_journald_in_use) {
243 0 : zt_stdout_journald.prio_min = maxlvl;
244 0 : zlog_5424_apply_meta(&zt_stdout_journald);
245 : } else {
246 2 : zt_stdout_file.prio_min = maxlvl;
247 2 : zlog_file_set_other(&zt_stdout_file);
248 : }
249 2 : }
250 :
251 0 : DEFPY (config_log_stdout,
252 : config_log_stdout_cmd,
253 : "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
254 : "Logging control\n"
255 : "Set stdout logging level\n"
256 : LOG_LEVEL_DESC)
257 : {
258 0 : int level;
259 :
260 0 : if (levelarg) {
261 0 : level = log_level_match(levelarg);
262 0 : if (level == ZLOG_DISABLED)
263 : return CMD_ERR_NO_MATCH;
264 : } else
265 : level = log_default_lvl;
266 :
267 0 : log_config_stdout_lvl = level;
268 0 : log_stdout_apply_level();
269 0 : return CMD_SUCCESS;
270 : }
271 :
272 0 : DEFUN (no_config_log_stdout,
273 : no_config_log_stdout_cmd,
274 : "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
275 : NO_STR
276 : "Logging control\n"
277 : "Cancel logging to stdout\n"
278 : LOG_LEVEL_DESC)
279 : {
280 0 : log_config_stdout_lvl = ZLOG_DISABLED;
281 0 : log_stdout_apply_level();
282 0 : return CMD_SUCCESS;
283 : }
284 :
285 0 : DEFUN_HIDDEN (config_log_monitor,
286 : config_log_monitor_cmd,
287 : "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
288 : "Logging control\n"
289 : "Set terminal line (monitor) logging level\n"
290 : LOG_LEVEL_DESC)
291 : {
292 0 : vty_out(vty, "%% \"log monitor\" is deprecated and does nothing.\n");
293 0 : return CMD_SUCCESS;
294 : }
295 :
296 0 : DEFUN_HIDDEN (no_config_log_monitor,
297 : no_config_log_monitor_cmd,
298 : "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
299 : NO_STR
300 : "Logging control\n"
301 : "Disable terminal line (monitor) logging\n"
302 : LOG_LEVEL_DESC)
303 : {
304 0 : return CMD_SUCCESS;
305 : }
306 :
307 0 : DEFPY_NOSH (debug_uid_backtrace,
308 : debug_uid_backtrace_cmd,
309 : "[no] debug unique-id UID backtrace",
310 : NO_STR
311 : DEBUG_STR
312 : "Options per individual log message, by unique ID\n"
313 : "Log message unique ID (XXXXX-XXXXX)\n"
314 : "Add backtrace to log when message is printed\n")
315 : {
316 0 : struct xrefdata search, *xrd;
317 0 : struct xrefdata_logmsg *xrdl;
318 0 : uint8_t flag;
319 :
320 0 : strlcpy(search.uid, uid, sizeof(search.uid));
321 0 : xrd = xrefdata_uid_find(&xrefdata_uid, &search);
322 :
323 0 : if (!xrd)
324 : return CMD_ERR_NOTHING_TODO;
325 :
326 0 : if (xrd->xref->type != XREFT_LOGMSG) {
327 0 : vty_out(vty, "%% ID \"%s\" is not a log message\n", uid);
328 0 : return CMD_WARNING;
329 : }
330 0 : xrdl = container_of(xrd, struct xrefdata_logmsg, xrefdata);
331 :
332 0 : flag = (vty->node == CONFIG_NODE) ? LOGMSG_FLAG_PERSISTENT
333 : : LOGMSG_FLAG_EPHEMERAL;
334 :
335 0 : if ((xrdl->fl_print_bt & flag) == (no ? 0 : flag))
336 : return CMD_SUCCESS;
337 0 : if (flag == LOGMSG_FLAG_PERSISTENT)
338 0 : logmsgs_with_persist_bt += no ? -1 : 1;
339 :
340 0 : xrdl->fl_print_bt ^= flag;
341 0 : return CMD_SUCCESS;
342 : }
343 :
344 4 : static int set_log_file(struct zlog_cfg_file *target, struct vty *vty,
345 : const char *fname, int loglevel)
346 : {
347 4 : char path[MAXPATHLEN + 1];
348 4 : const char *fullpath;
349 4 : bool ok;
350 :
351 :
352 : /* Path detection. */
353 4 : if (!IS_DIRECTORY_SEP(*fname)) {
354 0 : char cwd[MAXPATHLEN + 1];
355 :
356 0 : cwd[MAXPATHLEN] = '\0';
357 :
358 0 : if (getcwd(cwd, MAXPATHLEN) == NULL) {
359 0 : flog_err_sys(EC_LIB_SYSTEM_CALL,
360 : "config_log_file: Unable to alloc mem!");
361 0 : return CMD_WARNING_CONFIG_FAILED;
362 : }
363 :
364 0 : int pr = snprintf(path, sizeof(path), "%s/%s", cwd, fname);
365 0 : if (pr < 0 || (unsigned int)pr >= sizeof(path)) {
366 0 : flog_err_sys(
367 : EC_LIB_SYSTEM_CALL,
368 : "%s: Path too long ('%s/%s'); system maximum is %u",
369 : __func__, cwd, fname, MAXPATHLEN);
370 0 : return CMD_WARNING_CONFIG_FAILED;
371 : }
372 :
373 0 : fullpath = path;
374 : } else
375 : fullpath = fname;
376 :
377 4 : target->prio_min = loglevel;
378 4 : ok = zlog_file_set_filename(target, fullpath);
379 :
380 4 : if (!ok) {
381 0 : if (vty)
382 0 : vty_out(vty, "can't open logfile %s\n", fname);
383 0 : return CMD_WARNING_CONFIG_FAILED;
384 : }
385 : return CMD_SUCCESS;
386 : }
387 :
388 4 : void command_setup_early_logging(const char *dest, const char *level)
389 : {
390 4 : int nlevel;
391 4 : char *sep;
392 4 : int len;
393 4 : char type[8];
394 :
395 4 : if (level) {
396 4 : nlevel = log_level_match(level);
397 :
398 4 : if (nlevel == ZLOG_DISABLED) {
399 0 : fprintf(stderr, "invalid log level \"%s\"\n", level);
400 0 : exit(1);
401 : }
402 : } else
403 : nlevel = log_default_lvl;
404 :
405 4 : if (!dest)
406 : return;
407 :
408 4 : sep = strchr(dest, ':');
409 4 : len = sep ? (int)(sep - dest) : (int)strlen(dest);
410 :
411 4 : snprintfrr(type, sizeof(type), "%.*s", len, dest);
412 :
413 4 : if (strcmp(type, "stdout") == 0) {
414 0 : log_cmdline_stdout_lvl = nlevel;
415 0 : log_stdout_apply_level();
416 0 : return;
417 : }
418 4 : if (strcmp(type, "syslog") == 0) {
419 0 : log_cmdline_syslog_lvl = nlevel;
420 0 : zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
421 : log_cmdline_syslog_lvl));
422 0 : return;
423 : }
424 4 : if (strcmp(type, "file") == 0 && sep) {
425 2 : sep++;
426 2 : set_log_file(&zt_file_cmdline, NULL, sep, nlevel);
427 2 : return;
428 : }
429 2 : if (strcmp(type, "monitor") == 0 && sep) {
430 2 : struct zlog_live_cfg cfg = {};
431 2 : unsigned long fd;
432 2 : char *endp;
433 :
434 2 : sep++;
435 2 : fd = strtoul(sep, &endp, 10);
436 2 : if (!*sep || *endp) {
437 0 : fprintf(stderr, "invalid monitor fd \"%s\"\n", sep);
438 0 : exit(1);
439 : }
440 :
441 2 : zlog_live_open_fd(&cfg, nlevel, fd);
442 2 : zlog_live_disown(&cfg);
443 2 : return;
444 : }
445 :
446 0 : fprintf(stderr, "invalid log target \"%s\" (\"%s\")\n", type, dest);
447 0 : exit(1);
448 : }
449 :
450 2 : DEFUN (clear_log_cmdline,
451 : clear_log_cmdline_cmd,
452 : "clear log cmdline-targets",
453 : CLEAR_STR
454 : "Logging control\n"
455 : "Disable log targets specified at startup by --log option\n")
456 : {
457 2 : zt_file_cmdline.prio_min = ZLOG_DISABLED;
458 2 : zlog_file_set_other(&zt_file_cmdline);
459 :
460 2 : log_cmdline_syslog_lvl = ZLOG_DISABLED;
461 2 : zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
462 : log_cmdline_syslog_lvl));
463 :
464 2 : log_cmdline_stdout_lvl = ZLOG_DISABLED;
465 2 : log_stdout_apply_level();
466 :
467 2 : return CMD_SUCCESS;
468 : }
469 :
470 2 : DEFPY (config_log_file,
471 : config_log_file_cmd,
472 : "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
473 : "Logging control\n"
474 : "Logging to file\n"
475 : "Logging filename\n"
476 : LOG_LEVEL_DESC)
477 : {
478 2 : int level = log_default_lvl;
479 :
480 2 : if (levelarg) {
481 0 : level = log_level_match(levelarg);
482 0 : if (level == ZLOG_DISABLED)
483 : return CMD_ERR_NO_MATCH;
484 : }
485 2 : return set_log_file(&zt_file, vty, filename, level);
486 : }
487 :
488 0 : DEFUN (no_config_log_file,
489 : no_config_log_file_cmd,
490 : "no log file [FILENAME [LEVEL]]",
491 : NO_STR
492 : "Logging control\n"
493 : "Cancel logging to file\n"
494 : "Logging file name\n"
495 : "Logging level\n")
496 : {
497 0 : zt_file.prio_min = ZLOG_DISABLED;
498 0 : zlog_file_set_other(&zt_file);
499 0 : return CMD_SUCCESS;
500 : }
501 :
502 0 : DEFPY (config_log_syslog,
503 : config_log_syslog_cmd,
504 : "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
505 : "Logging control\n"
506 : "Set syslog logging level\n"
507 : LOG_LEVEL_DESC)
508 : {
509 0 : int level;
510 :
511 0 : if (levelarg) {
512 0 : level = log_level_match(levelarg);
513 :
514 0 : if (level == ZLOG_DISABLED)
515 : return CMD_ERR_NO_MATCH;
516 : } else
517 : level = log_default_lvl;
518 :
519 0 : log_config_syslog_lvl = level;
520 0 : zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
521 : log_cmdline_syslog_lvl));
522 0 : return CMD_SUCCESS;
523 : }
524 :
525 0 : DEFUN (no_config_log_syslog,
526 : no_config_log_syslog_cmd,
527 : "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>]",
528 : NO_STR
529 : "Logging control\n"
530 : "Cancel logging to syslog\n"
531 : LOG_FACILITY_DESC
532 : LOG_LEVEL_DESC)
533 : {
534 0 : log_config_syslog_lvl = ZLOG_DISABLED;
535 0 : zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
536 : log_cmdline_syslog_lvl));
537 0 : return CMD_SUCCESS;
538 : }
539 :
540 0 : DEFPY (config_log_facility,
541 : config_log_facility_cmd,
542 : "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>$facilityarg",
543 : "Logging control\n"
544 : "Facility parameter for syslog messages\n"
545 : LOG_FACILITY_DESC)
546 : {
547 0 : int facility = facility_match(facilityarg);
548 :
549 0 : zlog_syslog_set_facility(facility);
550 0 : return CMD_SUCCESS;
551 : }
552 :
553 0 : DEFUN (no_config_log_facility,
554 : no_config_log_facility_cmd,
555 : "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
556 : NO_STR
557 : "Logging control\n"
558 : "Reset syslog facility to default (daemon)\n"
559 : LOG_FACILITY_DESC)
560 : {
561 0 : zlog_syslog_set_facility(LOG_DAEMON);
562 0 : return CMD_SUCCESS;
563 : }
564 :
565 2 : DEFUN (config_log_record_priority,
566 : config_log_record_priority_cmd,
567 : "log record-priority",
568 : "Logging control\n"
569 : "Log the priority of the message within the message\n")
570 : {
571 2 : zt_file.record_priority = true;
572 2 : zlog_file_set_other(&zt_file);
573 2 : if (!stdout_journald_in_use) {
574 2 : zt_stdout_file.record_priority = true;
575 2 : zlog_file_set_other(&zt_stdout_file);
576 : }
577 2 : zt_filterfile.parent.record_priority = true;
578 2 : zlog_file_set_other(&zt_filterfile.parent);
579 2 : return CMD_SUCCESS;
580 : }
581 :
582 0 : DEFUN (no_config_log_record_priority,
583 : no_config_log_record_priority_cmd,
584 : "no log record-priority",
585 : NO_STR
586 : "Logging control\n"
587 : "Do not log the priority of the message within the message\n")
588 : {
589 0 : zt_file.record_priority = false;
590 0 : zlog_file_set_other(&zt_file);
591 0 : if (!stdout_journald_in_use) {
592 0 : zt_stdout_file.record_priority = false;
593 0 : zlog_file_set_other(&zt_stdout_file);
594 : }
595 0 : zt_filterfile.parent.record_priority = false;
596 0 : zlog_file_set_other(&zt_filterfile.parent);
597 0 : return CMD_SUCCESS;
598 : }
599 :
600 2 : DEFPY (config_log_timestamp_precision,
601 : config_log_timestamp_precision_cmd,
602 : "log timestamp precision (0-6)",
603 : "Logging control\n"
604 : "Timestamp configuration\n"
605 : "Set the timestamp precision\n"
606 : "Number of subsecond digits\n")
607 : {
608 2 : zt_file.ts_subsec = precision;
609 2 : zlog_file_set_other(&zt_file);
610 2 : if (!stdout_journald_in_use) {
611 2 : zt_stdout_file.ts_subsec = precision;
612 2 : zlog_file_set_other(&zt_stdout_file);
613 : }
614 2 : zt_filterfile.parent.ts_subsec = precision;
615 2 : zlog_file_set_other(&zt_filterfile.parent);
616 2 : return CMD_SUCCESS;
617 : }
618 :
619 0 : DEFUN (no_config_log_timestamp_precision,
620 : no_config_log_timestamp_precision_cmd,
621 : "no log timestamp precision [(0-6)]",
622 : NO_STR
623 : "Logging control\n"
624 : "Timestamp configuration\n"
625 : "Reset the timestamp precision to the default value of 0\n"
626 : "Number of subsecond digits\n")
627 : {
628 0 : zt_file.ts_subsec = 0;
629 0 : zlog_file_set_other(&zt_file);
630 0 : if (!stdout_journald_in_use) {
631 0 : zt_stdout_file.ts_subsec = 0;
632 0 : zlog_file_set_other(&zt_stdout_file);
633 : }
634 0 : zt_filterfile.parent.ts_subsec = 0;
635 0 : zlog_file_set_other(&zt_filterfile.parent);
636 0 : return CMD_SUCCESS;
637 : }
638 :
639 0 : DEFPY (config_log_ec,
640 : config_log_ec_cmd,
641 : "[no] log error-category",
642 : NO_STR
643 : "Logging control\n"
644 : "Prefix log message text with [EC 9999] code\n")
645 : {
646 0 : zlog_set_prefix_ec(!no);
647 0 : return CMD_SUCCESS;
648 : }
649 :
650 0 : DEFPY (config_log_xid,
651 : config_log_xid_cmd,
652 : "[no] log unique-id",
653 : NO_STR
654 : "Logging control\n"
655 : "Prefix log message text with [XXXXX-XXXXX] identifier\n")
656 : {
657 0 : zlog_set_prefix_xid(!no);
658 0 : return CMD_SUCCESS;
659 : }
660 :
661 0 : DEFPY (config_log_filterfile,
662 : config_log_filterfile_cmd,
663 : "log filtered-file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
664 : "Logging control\n"
665 : "Logging to file with string filter\n"
666 : "Logging filename\n"
667 : LOG_LEVEL_DESC)
668 : {
669 0 : int level = log_default_lvl;
670 :
671 0 : if (levelarg) {
672 0 : level = log_level_match(levelarg);
673 0 : if (level == ZLOG_DISABLED)
674 : return CMD_ERR_NO_MATCH;
675 : }
676 0 : return set_log_file(&zt_filterfile.parent, vty, filename, level);
677 : }
678 :
679 0 : DEFUN (no_config_log_filterfile,
680 : no_config_log_filterfile_cmd,
681 : "no log filtered-file [FILENAME [LEVEL]]",
682 : NO_STR
683 : "Logging control\n"
684 : "Cancel logging to file with string filter\n"
685 : "Logging file name\n"
686 : "Logging level\n")
687 : {
688 0 : zt_filterfile.parent.prio_min = ZLOG_DISABLED;
689 0 : zlog_file_set_other(&zt_filterfile.parent);
690 0 : return CMD_SUCCESS;
691 : }
692 :
693 0 : DEFPY (log_filter,
694 : log_filter_cmd,
695 : "[no] log filter-text WORD$filter",
696 : NO_STR
697 : "Logging control\n"
698 : FILTER_LOG_STR
699 : "String to filter by\n")
700 : {
701 0 : int ret = 0;
702 :
703 0 : if (no)
704 0 : ret = zlog_filter_del(filter);
705 : else
706 0 : ret = zlog_filter_add(filter);
707 :
708 0 : if (ret == 1) {
709 0 : vty_out(vty, "%% filter table full\n");
710 0 : return CMD_WARNING;
711 0 : } else if (ret != 0) {
712 0 : vty_out(vty, "%% failed to %s log filter\n",
713 : (no ? "remove" : "apply"));
714 0 : return CMD_WARNING;
715 : }
716 :
717 0 : vty_out(vty, " %s\n", filter);
718 0 : return CMD_SUCCESS;
719 : }
720 :
721 : /* Clear all log filters */
722 0 : DEFPY (log_filter_clear,
723 : log_filter_clear_cmd,
724 : "clear log filter-text",
725 : CLEAR_STR
726 : "Logging control\n"
727 : FILTER_LOG_STR)
728 : {
729 0 : zlog_filter_clear();
730 0 : return CMD_SUCCESS;
731 : }
732 :
733 : /* Show log filter */
734 0 : DEFPY (show_log_filter,
735 : show_log_filter_cmd,
736 : "show logging filter-text",
737 : SHOW_STR
738 : "Show current logging configuration\n"
739 : FILTER_LOG_STR)
740 : {
741 0 : char log_filters[ZLOG_FILTERS_MAX * (ZLOG_FILTER_LENGTH_MAX + 3)] = "";
742 0 : int len = 0;
743 :
744 0 : len = zlog_filter_dump(log_filters, sizeof(log_filters));
745 :
746 0 : if (len == -1) {
747 0 : vty_out(vty, "%% failed to get filters\n");
748 0 : return CMD_WARNING;
749 : }
750 :
751 0 : if (len != 0)
752 0 : vty_out(vty, "%s", log_filters);
753 :
754 : return CMD_SUCCESS;
755 : }
756 :
757 : /* Enable/disable 'immediate' mode, with no output buffering */
758 0 : DEFPY (log_immediate_mode,
759 : log_immediate_mode_cmd,
760 : "[no] log immediate-mode",
761 : NO_STR
762 : "Logging control\n"
763 : "Output immediately, without buffering\n")
764 : {
765 0 : zlog_set_immediate(!no);
766 0 : return CMD_SUCCESS;
767 : }
768 :
769 0 : void log_config_write(struct vty *vty)
770 : {
771 0 : bool show_cmdline_hint = false;
772 :
773 0 : if (zt_file.prio_min != ZLOG_DISABLED && zt_file.filename) {
774 0 : vty_out(vty, "log file %s", zt_file.filename);
775 :
776 0 : if (zt_file.prio_min != log_default_lvl)
777 0 : vty_out(vty, " %s", zlog_priority[zt_file.prio_min]);
778 0 : vty_out(vty, "\n");
779 : }
780 :
781 0 : if (zt_filterfile.parent.prio_min != ZLOG_DISABLED
782 0 : && zt_filterfile.parent.filename) {
783 0 : vty_out(vty, "log filtered-file %s",
784 : zt_filterfile.parent.filename);
785 :
786 0 : if (zt_filterfile.parent.prio_min != log_default_lvl)
787 0 : vty_out(vty, " %s",
788 0 : zlog_priority[zt_filterfile.parent.prio_min]);
789 0 : vty_out(vty, "\n");
790 : }
791 :
792 0 : if (log_config_stdout_lvl != ZLOG_DISABLED) {
793 0 : vty_out(vty, "log stdout");
794 :
795 0 : if (log_config_stdout_lvl != log_default_lvl)
796 0 : vty_out(vty, " %s",
797 0 : zlog_priority[log_config_stdout_lvl]);
798 0 : vty_out(vty, "\n");
799 : }
800 :
801 0 : if (log_config_syslog_lvl != ZLOG_DISABLED) {
802 0 : vty_out(vty, "log syslog");
803 :
804 0 : if (log_config_syslog_lvl != log_default_lvl)
805 0 : vty_out(vty, " %s",
806 0 : zlog_priority[log_config_syslog_lvl]);
807 0 : vty_out(vty, "\n");
808 : }
809 :
810 0 : if (log_cmdline_syslog_lvl != ZLOG_DISABLED) {
811 0 : vty_out(vty,
812 : "! \"log syslog %s\" enabled by \"--log\" startup option\n",
813 0 : zlog_priority[log_cmdline_syslog_lvl]);
814 0 : show_cmdline_hint = true;
815 : }
816 0 : if (log_cmdline_stdout_lvl != ZLOG_DISABLED) {
817 0 : vty_out(vty,
818 : "! \"log stdout %s\" enabled by \"--log\" startup option\n",
819 0 : zlog_priority[log_cmdline_stdout_lvl]);
820 0 : show_cmdline_hint = true;
821 : }
822 0 : if (zt_file_cmdline.prio_min != ZLOG_DISABLED) {
823 0 : vty_out(vty,
824 : "! \"log file %s %s\" enabled by \"--log\" startup option\n",
825 : zt_file_cmdline.filename,
826 0 : zlog_priority[zt_file_cmdline.prio_min]);
827 0 : show_cmdline_hint = true;
828 : }
829 0 : if (show_cmdline_hint)
830 0 : vty_out(vty,
831 : "! use \"clear log cmdline-targets\" to remove this target\n");
832 :
833 0 : if (zlog_syslog_get_facility() != LOG_DAEMON)
834 0 : vty_out(vty, "log facility %s\n",
835 : facility_name(zlog_syslog_get_facility()));
836 :
837 0 : if (zt_file.record_priority == 1)
838 0 : vty_out(vty, "log record-priority\n");
839 :
840 0 : if (zt_file.ts_subsec > 0)
841 0 : vty_out(vty, "log timestamp precision %d\n",
842 : zt_file.ts_subsec);
843 :
844 0 : if (!zlog_get_prefix_ec())
845 0 : vty_out(vty, "no log error-category\n");
846 0 : if (!zlog_get_prefix_xid())
847 0 : vty_out(vty, "no log unique-id\n");
848 :
849 0 : if (logmsgs_with_persist_bt) {
850 0 : struct xrefdata *xrd;
851 0 : struct xrefdata_logmsg *xrdl;
852 :
853 0 : vty_out(vty, "!\n");
854 :
855 0 : frr_each (xrefdata_uid, &xrefdata_uid, xrd) {
856 0 : if (xrd->xref->type != XREFT_LOGMSG)
857 0 : continue;
858 :
859 0 : xrdl = container_of(xrd, struct xrefdata_logmsg,
860 : xrefdata);
861 0 : if (xrdl->fl_print_bt & LOGMSG_FLAG_PERSISTENT)
862 0 : vty_out(vty, "debug unique-id %s backtrace\n",
863 0 : xrd->uid);
864 : }
865 : }
866 0 : }
867 :
868 2 : static int log_vty_init(const char *progname, const char *protoname,
869 : unsigned short instance, uid_t uid, gid_t gid)
870 : {
871 2 : zlog_progname = progname;
872 2 : zlog_protoname = protoname;
873 :
874 2 : zlog_set_prefix_ec(true);
875 2 : zlog_set_prefix_xid(true);
876 :
877 2 : zlog_filterfile_init(&zt_filterfile);
878 :
879 2 : if (sd_stdout_is_journal) {
880 0 : stdout_journald_in_use = true;
881 0 : zlog_5424_init(&zt_stdout_journald);
882 0 : zlog_5424_apply_dst(&zt_stdout_journald);
883 : } else
884 2 : zlog_file_set_fd(&zt_stdout_file, STDOUT_FILENO);
885 2 : return 0;
886 : }
887 :
888 3 : __attribute__((_CONSTRUCTOR(475))) static void log_vty_preinit(void)
889 : {
890 3 : hook_register(zlog_init, log_vty_init);
891 3 : }
892 :
893 2 : void log_cmd_init(void)
894 : {
895 2 : install_element(VIEW_NODE, &show_logging_cmd);
896 2 : install_element(ENABLE_NODE, &clear_log_cmdline_cmd);
897 :
898 2 : install_element(CONFIG_NODE, &config_log_stdout_cmd);
899 2 : install_element(CONFIG_NODE, &no_config_log_stdout_cmd);
900 2 : install_element(CONFIG_NODE, &config_log_monitor_cmd);
901 2 : install_element(CONFIG_NODE, &no_config_log_monitor_cmd);
902 2 : install_element(CONFIG_NODE, &config_log_file_cmd);
903 2 : install_element(CONFIG_NODE, &no_config_log_file_cmd);
904 2 : install_element(CONFIG_NODE, &config_log_syslog_cmd);
905 2 : install_element(CONFIG_NODE, &no_config_log_syslog_cmd);
906 2 : install_element(CONFIG_NODE, &config_log_facility_cmd);
907 2 : install_element(CONFIG_NODE, &no_config_log_facility_cmd);
908 2 : install_element(CONFIG_NODE, &config_log_record_priority_cmd);
909 2 : install_element(CONFIG_NODE, &no_config_log_record_priority_cmd);
910 2 : install_element(CONFIG_NODE, &config_log_timestamp_precision_cmd);
911 2 : install_element(CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
912 2 : install_element(CONFIG_NODE, &config_log_ec_cmd);
913 2 : install_element(CONFIG_NODE, &config_log_xid_cmd);
914 :
915 2 : install_element(VIEW_NODE, &show_log_filter_cmd);
916 2 : install_element(CONFIG_NODE, &log_filter_cmd);
917 2 : install_element(CONFIG_NODE, &log_filter_clear_cmd);
918 2 : install_element(CONFIG_NODE, &config_log_filterfile_cmd);
919 2 : install_element(CONFIG_NODE, &no_config_log_filterfile_cmd);
920 2 : install_element(CONFIG_NODE, &log_immediate_mode_cmd);
921 :
922 2 : install_element(ENABLE_NODE, &debug_uid_backtrace_cmd);
923 2 : install_element(CONFIG_NODE, &debug_uid_backtrace_cmd);
924 :
925 2 : log_5424_cmd_init();
926 2 : }
|