1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2021 David Lamparter for NetDEF, Inc.
13 #include "lib/command.h"
14 #include "lib/libfrr.h"
15 #include "lib/log_vty.h"
17 DEFINE_MTYPE_STATIC(LOG
, LOG_5424_CONFIG
, "extended syslog config");
18 DEFINE_MTYPE_STATIC(LOG
, LOG_5424_DATA
, "extended syslog config items");
20 static int target_cmp(const struct zlog_cfg_5424_user
*a
,
21 const struct zlog_cfg_5424_user
*b
)
23 return strcmp(a
->name
, b
->name
);
26 DECLARE_RBTREE_UNIQ(targets
, struct zlog_cfg_5424_user
, targets_item
,
28 DEFINE_QOBJ_TYPE(zlog_cfg_5424_user
);
30 static struct targets_head targets
= INIT_RBTREE_UNIQ(targets
);
31 static struct thread_master
*log_5424_master
;
33 static void clear_dst(struct zlog_cfg_5424_user
*cfg
);
41 /* clang-format off */
42 static struct log_option log_opts
[] = {
43 { "code-location", offsetof(struct zlog_cfg_5424
, kw_location
) },
44 { "version", offsetof(struct zlog_cfg_5424
, kw_version
) },
45 { "unique-id", offsetof(struct zlog_cfg_5424
, kw_uid
), true },
46 { "error-category", offsetof(struct zlog_cfg_5424
, kw_ec
), true },
47 { "format-args", offsetof(struct zlog_cfg_5424
, kw_args
) },
51 #define DFLT_TS_FLAGS (6 | ZLOG_TS_UTC)
52 #define DFLT_FACILITY LOG_DAEMON
53 #define DFLT_PRIO_MIN LOG_DEBUG
62 static struct zlog_cfg_5424_user
*log_5424_alloc(const char *name
)
64 struct zlog_cfg_5424_user
*cfg
;
66 cfg
= XCALLOC(MTYPE_LOG_5424_CONFIG
, sizeof(*cfg
));
67 cfg
->name
= XSTRDUP(MTYPE_LOG_5424_DATA
, name
);
69 cfg
->cfg
.master
= log_5424_master
;
70 cfg
->cfg
.kw_location
= true;
71 cfg
->cfg
.kw_version
= false;
72 cfg
->cfg
.facility
= DFLT_FACILITY
;
73 cfg
->cfg
.prio_min
= DFLT_PRIO_MIN
;
74 cfg
->cfg
.ts_flags
= DFLT_TS_FLAGS
;
77 for (struct log_option
*opt
= log_opts
; opt
->name
; opt
++) {
78 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
82 zlog_5424_init(&cfg
->cfg
);
84 QOBJ_REG(cfg
, zlog_cfg_5424_user
);
85 targets_add(&targets
, cfg
);
89 static void log_5424_free(struct zlog_cfg_5424_user
*cfg
, bool keepopen
)
91 targets_del(&targets
, cfg
);
94 zlog_5424_fini(&cfg
->cfg
, keepopen
);
97 XFREE(MTYPE_LOG_5424_DATA
, cfg
->filename
);
98 XFREE(MTYPE_LOG_5424_DATA
, cfg
->name
);
99 XFREE(MTYPE_LOG_5424_CONFIG
, cfg
);
102 static void clear_dst(struct zlog_cfg_5424_user
*cfg
)
104 XFREE(MTYPE_LOG_5424_DATA
, cfg
->filename
);
105 cfg
->cfg
.filename
= cfg
->filename
;
107 XFREE(MTYPE_LOG_5424_DATA
, cfg
->file_user
);
108 XFREE(MTYPE_LOG_5424_DATA
, cfg
->file_group
);
109 XFREE(MTYPE_LOG_5424_DATA
, cfg
->envvar
);
112 cfg
->cfg
.file_uid
= -1;
113 cfg
->cfg
.file_gid
= -1;
114 cfg
->cfg
.file_mode
= LOGFILE_MASK
& 0666;
115 cfg
->cfg
.file_nocreate
= false;
116 cfg
->cfg
.dst
= ZLOG_5424_DST_NONE
;
119 static int reconf_dst(struct zlog_cfg_5424_user
*cfg
, struct vty
*vty
)
121 if (!cfg
->reconf_dst
&& !cfg
->reconf_meta
&& vty
->type
!= VTY_FILE
)
123 "%% Changes will be applied when exiting this config block\n");
125 cfg
->reconf_dst
= true;
129 static int reconf_meta(struct zlog_cfg_5424_user
*cfg
, struct vty
*vty
)
131 if (!cfg
->reconf_dst
&& !cfg
->reconf_meta
&& vty
->type
!= VTY_FILE
)
133 "%% Changes will be applied when exiting this config block\n");
135 cfg
->reconf_meta
= true;
139 static int reconf_clear_dst(struct zlog_cfg_5424_user
*cfg
, struct vty
*vty
)
141 if (cfg
->cfg
.dst
== ZLOG_5424_DST_NONE
)
145 return reconf_dst(cfg
, vty
);
148 #include "lib/zlog_5424_cli_clippy.c"
150 DEFPY_NOSH(log_5424_target
,
152 "log extended-syslog EXTLOGNAME",
154 "Extended RFC5424 syslog (including file targets)\n"
155 "Name identifying this syslog target\n")
157 struct zlog_cfg_5424_user
*cfg
, ref
;
159 ref
.name
= (char *)extlogname
;
160 cfg
= targets_find(&targets
, &ref
);
163 cfg
= log_5424_alloc(extlogname
);
165 VTY_PUSH_CONTEXT(EXTLOG_NODE
, cfg
);
169 DEFPY(no_log_5424_target
,
170 no_log_5424_target_cmd
,
171 "no log extended-syslog EXTLOGNAME",
174 "Extended RFC5424 syslog (including file targets)\n"
175 "Name identifying this syslog target\n")
177 struct zlog_cfg_5424_user
*cfg
, ref
;
179 ref
.name
= (char *)extlogname
;
180 cfg
= targets_find(&targets
, &ref
);
183 vty_out(vty
, "%% No extended syslog target named \"%s\"\n",
188 log_5424_free(cfg
, false);
192 /* "format <rfc3164|rfc5424|local-syslogd|journald>$fmt" */
193 #define FORMAT_HELP \
194 "Select log message formatting\n" \
195 "RFC3164 (legacy) syslog\n" \
196 "RFC5424 (modern) syslog, supports structured data (default)\n" \
197 "modified RFC3164 without hostname for local syslogd (/dev/log)\n" \
198 "journald (systemd log) native format\n" \
201 static enum zlog_5424_format
log_5424_fmt(const char *fmt
,
202 enum zlog_5424_format dflt
)
206 else if (!strcmp(fmt
, "rfc5424"))
207 return ZLOG_FMT_5424
;
208 else if (!strcmp(fmt
, "rfc3164"))
209 return ZLOG_FMT_3164
;
210 else if (!strcmp(fmt
, "local-syslogd"))
211 return ZLOG_FMT_LOCAL
;
212 else if (!strcmp(fmt
, "journald"))
213 return ZLOG_FMT_JOURNALD
;
218 DEFPY(log_5424_destination_file
,
219 log_5424_destination_file_cmd
,
220 "[no] destination file$type PATH "
221 "[create$create [{user WORD|group WORD|mode PERMS}]"
222 "|no-create$nocreate] "
223 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
225 "Log destination setup\n"
227 "Path to destination\n"
228 "Create file if it does not exist\n"
234 "File permissions (octal)\n"
235 "Do not create file if it does not exist\n"
238 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
239 enum zlog_5424_dst dst
;
240 bool reconf
= true, warn_perm
= false;
241 char *prev_user
, *prev_group
;
242 mode_t perm_val
= LOGFILE_MASK
& 0666;
243 enum zlog_5424_format fmtv
;
246 return reconf_clear_dst(cfg
, vty
);
248 fmtv
= log_5424_fmt(fmt
, ZLOG_FMT_5424
);
251 char *errp
= (char *)perms
;
253 perm_val
= strtoul(perms
, &errp
, 8);
254 if (*errp
|| errp
== perms
|| perm_val
== 0 ||
255 (perm_val
& ~0666)) {
256 vty_out(vty
, "%% Invalid permissions value \"%s\"\n",
262 dst
= (strcmp(type
, "fifo") == 0) ? ZLOG_5424_DST_FIFO
263 : ZLOG_5424_DST_FILE
;
265 if (cfg
->filename
&& !strcmp(path
, cfg
->filename
) &&
266 dst
== cfg
->cfg
.dst
&& cfg
->cfg
.active
&& cfg
->cfg
.fmt
== fmtv
)
269 /* keep for compare below */
270 prev_user
= cfg
->file_user
;
271 prev_group
= cfg
->file_group
;
272 cfg
->file_user
= NULL
;
273 cfg
->file_group
= NULL
;
277 cfg
->filename
= XSTRDUP(MTYPE_LOG_5424_DATA
, path
);
279 cfg
->cfg
.filename
= cfg
->filename
;
283 cfg
->cfg
.file_nocreate
= true;
286 struct passwd
*pwent
;
288 warn_perm
|= (prev_user
&& strcmp(user
, prev_user
));
289 cfg
->file_user
= XSTRDUP(MTYPE_LOG_5424_DATA
, user
);
292 pwent
= getpwnam(user
);
295 "%% Could not look up user \"%s\" (%s), file owner will be left untouched!\n",
297 errno
? safe_strerror(errno
)
298 : "No entry by this user name");
300 cfg
->cfg
.file_uid
= pwent
->pw_uid
;
305 warn_perm
|= (prev_group
&& strcmp(group
, prev_group
));
306 cfg
->file_group
= XSTRDUP(MTYPE_LOG_5424_DATA
, group
);
309 grent
= getgrnam(group
);
312 "%% Could not look up group \"%s\" (%s), file group will be left untouched!\n",
314 errno
? safe_strerror(errno
)
315 : "No entry by this group name");
317 cfg
->cfg
.file_gid
= grent
->gr_gid
;
320 XFREE(MTYPE_LOG_5424_DATA
, prev_user
);
321 XFREE(MTYPE_LOG_5424_DATA
, prev_group
);
323 if (cfg
->cfg
.file_uid
!= (uid_t
)-1 || cfg
->cfg
.file_gid
!= (gid_t
)-1) {
326 if (stat(cfg
->filename
, &st
) == 0) {
327 warn_perm
|= (st
.st_uid
!= cfg
->cfg
.file_uid
);
328 warn_perm
|= (st
.st_gid
!= cfg
->cfg
.file_gid
);
333 "%% Warning: ownership and permission bits are only applied when creating\n"
334 "%% log files. Use system tools to change existing files.\n"
335 "%% FRR may also be missing necessary privileges to set these.\n");
338 return reconf_dst(cfg
, vty
);
343 /* FIFOs are for legacy /dev/log implementations; using this is very much not
344 * recommended since it can unexpectedly block in logging calls. Also the fd
345 * would need to be reopened when the process at the other end restarts. None
346 * of this is handled - use at your own caution. It's _HIDDEN for a purpose.
348 ALIAS_HIDDEN(log_5424_destination_file
,
349 log_5424_destination_fifo_cmd
,
350 "[no] destination fifo$type PATH "
351 "[create$create [{owner WORD|group WORD|permissions PERMS}]"
352 "|no-create$nocreate] "
353 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
355 "Log destination setup\n"
356 "Log to filesystem FIFO\n"
357 "Path to destination\n"
358 "Create file if it does not exist\n"
364 "File permissions (octal)\n"
365 "Do not create file if it does not exist\n"
368 static int dst_unix(struct vty
*vty
, const char *no
, const char *path
,
369 enum zlog_5424_format fmt
, enum unix_special special
)
371 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
374 return reconf_clear_dst(cfg
, vty
);
376 cfg
->unix_special
= special
;
378 if (cfg
->cfg
.dst
== ZLOG_5424_DST_UNIX
&& cfg
->filename
&&
379 !strcmp(path
, cfg
->filename
) && cfg
->cfg
.active
&&
385 cfg
->filename
= XSTRDUP(MTYPE_LOG_5424_DATA
, path
);
386 cfg
->cfg
.dst
= ZLOG_5424_DST_UNIX
;
387 cfg
->cfg
.filename
= cfg
->filename
;
390 cfg
->cfg
.reconn_backoff
= 25;
391 cfg
->cfg
.reconn_backoff_cur
= 25;
392 cfg
->cfg
.reconn_backoff_max
= 10000;
393 return reconf_dst(cfg
, vty
);
396 DEFPY(log_5424_destination_unix
,
397 log_5424_destination_unix_cmd
,
398 "[no] destination unix PATH "
399 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
401 "Log destination setup\n"
402 "Log to unix socket\n"
406 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
407 enum zlog_5424_format fmtv
= log_5424_fmt(fmt
, ZLOG_FMT_5424
);
409 return dst_unix(vty
, no
, path
, fmtv
, SPECIAL_NONE
);
412 DEFPY(log_5424_destination_journald
,
413 log_5424_destination_journald_cmd
,
414 "[no] destination journald",
416 "Log destination setup\n"
417 "Log directly to systemd's journald\n")
419 return dst_unix(vty
, no
, "/run/systemd/journal/socket",
420 ZLOG_FMT_JOURNALD
, SPECIAL_JOURNALD
);
423 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 1200061)
424 #define ZLOG_FMT_DEV_LOG ZLOG_FMT_5424
425 #elif defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 500000000)
426 #define ZLOG_FMT_DEV_LOG ZLOG_FMT_5424
428 #define ZLOG_FMT_DEV_LOG ZLOG_FMT_LOCAL
431 DEFPY(log_5424_destination_syslog
,
432 log_5424_destination_syslog_cmd
,
433 "[no] destination syslog [supports-rfc5424]$supp5424",
435 "Log destination setup\n"
436 "Log directly to syslog\n"
437 "Use RFC5424 format (please refer to documentation)\n")
439 int format
= supp5424
? ZLOG_FMT_5424
: ZLOG_FMT_DEV_LOG
;
441 /* unfortunately, there is no way to detect 5424 support */
442 return dst_unix(vty
, no
, "/dev/log", format
, SPECIAL_SYSLOG
);
445 /* could add something like
446 * "destination <udp|tcp>$proto <A.B.C.D|X:X::X:X> (1-65535)$port"
447 * here, but there are 2 reasons not to do that:
449 * - each FRR daemon would open its own connection, there's no system level
450 * aggregation. That's the system's syslogd's job. It likely also
451 * supports directing & filtering log messages with configurable rules.
452 * - we're likely not going to support DTLS or TLS for more secure logging;
453 * adding this would require a considerable amount of additional config
454 * and an entire TLS library to begin with. A proper syslogd implements
455 * all of this, why reinvent the wheel?
458 DEFPY(log_5424_destination_fd
,
459 log_5424_destination_fd_cmd
,
460 "[no] destination <fd <(0-63)$fd|envvar WORD>|stdout$fd1|stderr$fd2>"
461 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
463 "Log destination setup\n"
464 "Log to pre-opened file descriptor\n"
465 "File descriptor number (must be open at startup)\n"
466 "Read file descriptor number from environment variable\n"
467 "Environment variable name\n"
468 "Log to standard output\n"
469 "Log to standard error output\n"
472 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
473 bool envvar_problem
= false;
474 enum zlog_5424_format fmtv
;
477 return reconf_clear_dst(cfg
, vty
);
479 fmtv
= log_5424_fmt(fmt
, ZLOG_FMT_5424
);
484 envval
= getenv(envvar
);
486 envvar_problem
= true;
490 fd
= strtoul(envval
, &errp
, 0);
491 if (errp
== envval
|| *errp
)
492 envvar_problem
= true;
502 if (cfg
->cfg
.dst
== ZLOG_5424_DST_FD
&& cfg
->cfg
.fd
== fd
&&
503 cfg
->cfg
.active
&& cfg
->cfg
.fmt
== fmtv
)
508 cfg
->cfg
.dst
= ZLOG_5424_DST_FD
;
512 cfg
->envvar
= XSTRDUP(MTYPE_LOG_5424_DATA
, envvar
);
516 "%% environment variable \"%s\" not present or invalid.\n",
518 if (!frr_is_startup_fd(fd
))
520 "%% file descriptor %d was not open when this process was started\n",
522 if (envvar_problem
|| !frr_is_startup_fd(fd
))
524 "%% configuration will be saved but has no effect currently\n");
526 return reconf_dst(cfg
, vty
);
529 DEFPY(log_5424_destination_none
,
530 log_5424_destination_none_cmd
,
531 "[no] destination [none]",
533 "Log destination setup\n"
534 "Deconfigure destination\n")
536 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
538 return reconf_clear_dst(cfg
, vty
);
541 /* end of destinations */
545 "[no] priority <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg",
547 "Set minimum message priority to include for this target\n"
550 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
551 int prio_min
= log_level_match(levelarg
);
553 if (prio_min
== cfg
->cfg
.prio_min
)
556 cfg
->cfg
.prio_min
= prio_min
;
557 return reconf_meta(cfg
, vty
);
560 DEFPY(log_5424_facility
,
561 log_5424_facility_cmd
,
562 "[no] facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>$facilityarg",
564 "Set syslog facility to use\n"
567 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
568 int facility
= facility_match(facilityarg
);
570 if (cfg
->cfg
.facility
== facility
)
573 cfg
->cfg
.facility
= facility
;
574 return reconf_meta(cfg
, vty
);
579 "[no] structured-data <code-location|version|unique-id|error-category|format-args>$option",
581 "Select structured data (key/value pairs) to include in each message\n"
582 "FRR source code location\n"
584 "Unique message identifier (XXXXX-XXXXX)\n"
585 "Error category (EC numeric)\n"
586 "Individual formatted log message arguments\n")
588 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
589 bool val
= !no
, *ptr
;
590 struct log_option
*opt
= log_opts
;
592 while (opt
->name
&& strcmp(opt
->name
, option
))
597 ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
602 return reconf_meta(cfg
, vty
);
605 DEFPY(log_5424_ts_prec
,
606 log_5424_ts_prec_cmd
,
607 "[no] timestamp precision (0-9)",
609 "Timestamp options\n"
610 "Number of sub-second digits to include\n"
611 "Number of sub-second digits to include\n")
613 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
614 uint32_t ts_flags
= cfg
->cfg
.ts_flags
;
616 ts_flags
&= ~ZLOG_TS_PREC
;
618 ts_flags
|= DFLT_TS_FLAGS
& ZLOG_TS_PREC
;
620 ts_flags
|= precision
;
622 if (ts_flags
== cfg
->cfg
.ts_flags
)
625 cfg
->cfg
.ts_flags
= ts_flags
;
626 return reconf_meta(cfg
, vty
);
629 DEFPY(log_5424_ts_local
,
630 log_5424_ts_local_cmd
,
631 "[no] timestamp local-time",
633 "Timestamp options\n"
634 "Use local system time zone rather than UTC\n")
636 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
637 uint32_t ts_flags
= cfg
->cfg
.ts_flags
;
639 ts_flags
&= ~ZLOG_TS_UTC
;
641 ts_flags
|= DFLT_TS_FLAGS
& ZLOG_TS_UTC
;
643 ts_flags
|= (~DFLT_TS_FLAGS
) & ZLOG_TS_UTC
;
645 if (ts_flags
== cfg
->cfg
.ts_flags
)
648 cfg
->cfg
.ts_flags
= ts_flags
;
649 return reconf_meta(cfg
, vty
);
652 static int log_5424_node_exit(struct vty
*vty
)
654 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
656 if ((cfg
->reconf_dst
|| cfg
->reconf_meta
) && vty
->type
!= VTY_FILE
)
657 vty_out(vty
, "%% applying changes.\n");
660 zlog_5424_apply_dst(&cfg
->cfg
);
661 else if (cfg
->reconf_meta
)
662 zlog_5424_apply_meta(&cfg
->cfg
);
664 cfg
->reconf_dst
= cfg
->reconf_meta
= false;
668 static int log_5424_config_write(struct vty
*vty
)
670 struct zlog_cfg_5424_user
*cfg
;
672 frr_each (targets
, &targets
, cfg
) {
673 const char *fmt_str
= "";
675 vty_out(vty
, "log extended %s\n", cfg
->name
);
677 switch (cfg
->cfg
.fmt
) {
679 fmt_str
= " format rfc5424";
682 fmt_str
= " format rfc3164";
685 fmt_str
= " format local-syslogd";
687 case ZLOG_FMT_JOURNALD
:
688 fmt_str
= " format journald";
692 switch (cfg
->cfg
.dst
) {
693 case ZLOG_5424_DST_NONE
:
694 vty_out(vty
, " ! no destination configured\n");
697 case ZLOG_5424_DST_FD
:
698 if (cfg
->cfg
.fmt
== ZLOG_FMT_5424
)
702 vty_out(vty
, " destination fd envvar %s%s\n",
703 cfg
->envvar
, fmt_str
);
704 else if (cfg
->cfg
.fd
== 1)
705 vty_out(vty
, " destination stdout%s\n",
707 else if (cfg
->cfg
.fd
== 2)
708 vty_out(vty
, " destination stderr%s\n",
711 vty_out(vty
, " destination fd %d%s\n",
712 cfg
->cfg
.fd
, fmt_str
);
715 case ZLOG_5424_DST_FILE
:
716 case ZLOG_5424_DST_FIFO
:
717 if (cfg
->cfg
.fmt
== ZLOG_FMT_5424
)
720 vty_out(vty
, " destination %s %s",
721 (cfg
->cfg
.dst
== ZLOG_5424_DST_FIFO
) ? "fifo"
725 if (cfg
->cfg
.file_nocreate
)
726 vty_out(vty
, " no-create");
727 else if (cfg
->file_user
|| cfg
->file_group
||
728 cfg
->cfg
.file_mode
!= (LOGFILE_MASK
& 0666)) {
729 vty_out(vty
, " create");
732 vty_out(vty
, " user %s",
735 vty_out(vty
, " group %s",
737 if (cfg
->cfg
.file_mode
!= (LOGFILE_MASK
& 0666))
738 vty_out(vty
, " mode %04o",
741 vty_out(vty
, "%s\n", fmt_str
);
744 case ZLOG_5424_DST_UNIX
:
745 switch (cfg
->unix_special
) {
747 vty_out(vty
, " destination unix %s%s\n",
748 cfg
->filename
, fmt_str
);
751 if (cfg
->cfg
.fmt
== ZLOG_FMT_DEV_LOG
)
752 vty_out(vty
, " destination syslog\n");
755 " destination syslog supports-rfc5424\n");
757 case SPECIAL_JOURNALD
:
758 vty_out(vty
, " destination journald\n");
764 if (cfg
->cfg
.prio_min
!= LOG_DEBUG
)
765 vty_out(vty
, " priority %s\n",
766 zlog_priority_str(cfg
->cfg
.prio_min
));
767 if (cfg
->cfg
.facility
!= DFLT_FACILITY
)
768 vty_out(vty
, " facility %s\n",
769 facility_name(cfg
->cfg
.facility
));
771 for (struct log_option
*opt
= log_opts
; opt
->name
; opt
++) {
772 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
774 if (*ptr
!= opt
->dflt
)
775 vty_out(vty
, " %sstructured-data %s\n",
776 *ptr
? "" : "no ", opt
->name
);
779 if ((cfg
->cfg
.ts_flags
^ DFLT_TS_FLAGS
) & ZLOG_TS_PREC
)
780 vty_out(vty
, " timestamp precision %u\n",
781 cfg
->cfg
.ts_flags
& ZLOG_TS_PREC
);
783 if ((cfg
->cfg
.ts_flags
^ DFLT_TS_FLAGS
) & ZLOG_TS_UTC
) {
784 if (cfg
->cfg
.ts_flags
& ZLOG_TS_UTC
)
785 vty_out(vty
, " no timestamp local-time\n");
787 vty_out(vty
, " timestamp local-time\n");
795 static int log_5424_show(struct vty
*vty
)
797 struct zlog_cfg_5424_user
*cfg
;
799 frr_each (targets
, &targets
, cfg
) {
800 vty_out(vty
, "\nExtended log target %pSQq\n", cfg
->name
);
802 switch (cfg
->cfg
.dst
) {
803 case ZLOG_5424_DST_NONE
:
805 " Inactive (no destination configured)\n");
808 case ZLOG_5424_DST_FD
:
811 " logging to fd %d from environment variable %pSE\n",
812 cfg
->cfg
.fd
, cfg
->envvar
);
813 else if (cfg
->cfg
.fd
== 1)
814 vty_out(vty
, " logging to stdout\n");
815 else if (cfg
->cfg
.fd
== 2)
816 vty_out(vty
, " logging to stderr\n");
818 vty_out(vty
, " logging to fd %d\n",
822 case ZLOG_5424_DST_FILE
:
823 case ZLOG_5424_DST_FIFO
:
824 case ZLOG_5424_DST_UNIX
:
825 vty_out(vty
, " logging to %s: %pSE\n",
826 (cfg
->cfg
.dst
== ZLOG_5424_DST_FIFO
) ? "fifo"
827 : (cfg
->cfg
.dst
== ZLOG_5424_DST_UNIX
)
834 vty_out(vty
, " log level: %s, facility: %s\n",
835 zlog_priority_str(cfg
->cfg
.prio_min
),
836 facility_name(cfg
->cfg
.facility
));
838 bool any_meta
= false, first
= true;
840 for (struct log_option
*opt
= log_opts
; opt
->name
; opt
++) {
841 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
849 switch (cfg
->cfg
.fmt
) {
851 case ZLOG_FMT_JOURNALD
:
852 vty_out(vty
, " structured data: ");
854 for (struct log_option
*opt
= log_opts
; opt
->name
;
856 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) +
860 vty_out(vty
, "%s%s", first
? "" : ", ",
870 " structured data is not supported by the selected format\n");
879 struct timeval err_ts
;
882 zlog_5424_state(&cfg
->cfg
, &lost_msgs
, &last_errno
,
883 &stale_errno
, &err_ts
);
884 vty_out(vty
, " number of lost messages: %zu\n", lost_msgs
);
889 since
= monotime_since(&err_ts
, NULL
);
891 " last error: %s (%lld.%06llds ago, currently %s)\n",
892 last_errno
? safe_strerror(last_errno
) : "none",
893 since
/ 1000000LL, since
% 1000000LL,
894 stale_errno
? "OK" : "erroring");
899 static struct cmd_node extlog_node
= {
902 .parent_node
= CONFIG_NODE
,
903 .prompt
= "%s(config-ext-log)# ",
905 .config_write
= log_5424_config_write
,
906 .node_exit
= log_5424_node_exit
,
909 static void log_5424_autocomplete(vector comps
, struct cmd_token
*token
)
911 struct zlog_cfg_5424_user
*cfg
;
913 frr_each (targets
, &targets
, cfg
)
914 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, cfg
->name
));
917 static const struct cmd_variable_handler log_5424_var_handlers
[] = {
918 {.tokenname
= "EXTLOGNAME", .completions
= log_5424_autocomplete
},
919 {.completions
= NULL
},
922 void log_5424_cmd_init(void)
924 hook_register(zlog_cli_show
, log_5424_show
);
926 cmd_variable_handler_register(log_5424_var_handlers
);
929 install_node(&extlog_node
);
930 install_default(EXTLOG_NODE
);
932 install_element(CONFIG_NODE
, &log_5424_target_cmd
);
933 install_element(CONFIG_NODE
, &no_log_5424_target_cmd
);
935 install_element(EXTLOG_NODE
, &log_5424_destination_file_cmd
);
936 install_element(EXTLOG_NODE
, &log_5424_destination_fifo_cmd
);
937 install_element(EXTLOG_NODE
, &log_5424_destination_unix_cmd
);
938 install_element(EXTLOG_NODE
, &log_5424_destination_journald_cmd
);
939 install_element(EXTLOG_NODE
, &log_5424_destination_syslog_cmd
);
940 install_element(EXTLOG_NODE
, &log_5424_destination_fd_cmd
);
942 install_element(EXTLOG_NODE
, &log_5424_meta_cmd
);
943 install_element(EXTLOG_NODE
, &log_5424_prio_cmd
);
944 install_element(EXTLOG_NODE
, &log_5424_facility_cmd
);
945 install_element(EXTLOG_NODE
, &log_5424_ts_prec_cmd
);
946 install_element(EXTLOG_NODE
, &log_5424_ts_local_cmd
);
951 static int log_5424_early_init(struct thread_master
*master
);
952 static int log_5424_rotate(void);
953 static int log_5424_fini(void);
955 __attribute__((_CONSTRUCTOR(475))) static void zlog_5424_startup_init(void)
957 hook_register(frr_early_init
, log_5424_early_init
);
958 hook_register(zlog_rotate
, log_5424_rotate
);
959 hook_register(frr_fini
, log_5424_fini
);
962 static int log_5424_early_init(struct thread_master
*master
)
964 log_5424_master
= master
;
969 static int log_5424_rotate(void)
971 struct zlog_cfg_5424_user
*cfg
;
973 frr_each (targets
, &targets
, cfg
)
974 if (!zlog_5424_rotate(&cfg
->cfg
))
976 "log rotation on extended log target %s failed",
982 static int log_5424_fini(void)
984 struct zlog_cfg_5424_user
*cfg
;
986 while ((cfg
= targets_pop(&targets
)))
987 log_5424_free(cfg
, true);
989 log_5424_master
= NULL
;