2 * Copyright (C) 2021 David Lamparter for NetDEF, Inc.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "zlog_5424.h"
22 #include <sys/types.h>
26 #include "lib/command.h"
27 #include "lib/libfrr.h"
28 #include "lib/log_vty.h"
30 DEFINE_MTYPE_STATIC(LOG
, LOG_5424_CONFIG
, "extended syslog config");
31 DEFINE_MTYPE_STATIC(LOG
, LOG_5424_DATA
, "extended syslog config items");
33 static int target_cmp(const struct zlog_cfg_5424_user
*a
,
34 const struct zlog_cfg_5424_user
*b
)
36 return strcmp(a
->name
, b
->name
);
39 DECLARE_RBTREE_UNIQ(targets
, struct zlog_cfg_5424_user
, targets_item
,
41 DEFINE_QOBJ_TYPE(zlog_cfg_5424_user
);
43 static struct targets_head targets
= INIT_RBTREE_UNIQ(targets
);
44 static struct thread_master
*log_5424_master
;
46 static void clear_dst(struct zlog_cfg_5424_user
*cfg
);
54 /* clang-format off */
55 static struct log_option log_opts
[] = {
56 { "code-location", offsetof(struct zlog_cfg_5424
, kw_location
) },
57 { "version", offsetof(struct zlog_cfg_5424
, kw_version
) },
58 { "unique-id", offsetof(struct zlog_cfg_5424
, kw_uid
), true },
59 { "error-category", offsetof(struct zlog_cfg_5424
, kw_ec
), true },
60 { "format-args", offsetof(struct zlog_cfg_5424
, kw_args
) },
64 #define DFLT_TS_FLAGS (6 | ZLOG_TS_UTC)
65 #define DFLT_FACILITY LOG_DAEMON
66 #define DFLT_PRIO_MIN LOG_DEBUG
75 static struct zlog_cfg_5424_user
*log_5424_alloc(const char *name
)
77 struct zlog_cfg_5424_user
*cfg
;
79 cfg
= XCALLOC(MTYPE_LOG_5424_CONFIG
, sizeof(*cfg
));
80 cfg
->name
= XSTRDUP(MTYPE_LOG_5424_DATA
, name
);
82 cfg
->cfg
.master
= log_5424_master
;
83 cfg
->cfg
.kw_location
= true;
84 cfg
->cfg
.kw_version
= false;
85 cfg
->cfg
.facility
= DFLT_FACILITY
;
86 cfg
->cfg
.prio_min
= DFLT_PRIO_MIN
;
87 cfg
->cfg
.ts_flags
= DFLT_TS_FLAGS
;
90 for (struct log_option
*opt
= log_opts
; opt
->name
; opt
++) {
91 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
95 zlog_5424_init(&cfg
->cfg
);
97 QOBJ_REG(cfg
, zlog_cfg_5424_user
);
98 targets_add(&targets
, cfg
);
102 static void log_5424_free(struct zlog_cfg_5424_user
*cfg
, bool keepopen
)
104 targets_del(&targets
, cfg
);
107 zlog_5424_fini(&cfg
->cfg
, keepopen
);
110 XFREE(MTYPE_LOG_5424_DATA
, cfg
->filename
);
111 XFREE(MTYPE_LOG_5424_DATA
, cfg
->name
);
112 XFREE(MTYPE_LOG_5424_CONFIG
, cfg
);
115 static void clear_dst(struct zlog_cfg_5424_user
*cfg
)
117 XFREE(MTYPE_LOG_5424_DATA
, cfg
->filename
);
118 cfg
->cfg
.filename
= cfg
->filename
;
120 XFREE(MTYPE_LOG_5424_DATA
, cfg
->file_user
);
121 XFREE(MTYPE_LOG_5424_DATA
, cfg
->file_group
);
122 XFREE(MTYPE_LOG_5424_DATA
, cfg
->envvar
);
125 cfg
->cfg
.file_uid
= -1;
126 cfg
->cfg
.file_gid
= -1;
127 cfg
->cfg
.file_mode
= LOGFILE_MASK
& 0666;
128 cfg
->cfg
.file_nocreate
= false;
129 cfg
->cfg
.dst
= ZLOG_5424_DST_NONE
;
132 static int reconf_dst(struct zlog_cfg_5424_user
*cfg
, struct vty
*vty
)
134 if (!cfg
->reconf_dst
&& !cfg
->reconf_meta
&& vty
->type
!= VTY_FILE
)
136 "%% Changes will be applied when exiting this config block\n");
138 cfg
->reconf_dst
= true;
142 static int reconf_meta(struct zlog_cfg_5424_user
*cfg
, struct vty
*vty
)
144 if (!cfg
->reconf_dst
&& !cfg
->reconf_meta
&& vty
->type
!= VTY_FILE
)
146 "%% Changes will be applied when exiting this config block\n");
148 cfg
->reconf_meta
= true;
152 static int reconf_clear_dst(struct zlog_cfg_5424_user
*cfg
, struct vty
*vty
)
154 if (cfg
->cfg
.dst
== ZLOG_5424_DST_NONE
)
158 return reconf_dst(cfg
, vty
);
161 #ifndef VTYSH_EXTRACT_PL
162 #include "lib/zlog_5424_cli_clippy.c"
165 DEFPY_NOSH(log_5424_target
,
167 "log extended-syslog EXTLOGNAME",
169 "Extended RFC5424 syslog (including file targets)\n"
170 "Name identifying this syslog target\n")
172 struct zlog_cfg_5424_user
*cfg
, ref
;
174 ref
.name
= (char *)extlogname
;
175 cfg
= targets_find(&targets
, &ref
);
178 cfg
= log_5424_alloc(extlogname
);
180 VTY_PUSH_CONTEXT(EXTLOG_NODE
, cfg
);
184 DEFPY(no_log_5424_target
,
185 no_log_5424_target_cmd
,
186 "no log extended-syslog EXTLOGNAME",
189 "Extended RFC5424 syslog (including file targets)\n"
190 "Name identifying this syslog target\n")
192 struct zlog_cfg_5424_user
*cfg
, ref
;
194 ref
.name
= (char *)extlogname
;
195 cfg
= targets_find(&targets
, &ref
);
198 vty_out(vty
, "%% No extended syslog target named \"%s\"\n",
203 log_5424_free(cfg
, false);
207 /* "format <rfc3164|rfc5424|local-syslogd|journald>$fmt" */
208 #define FORMAT_HELP \
209 "Select log message formatting\n" \
210 "RFC3164 (legacy) syslog\n" \
211 "RFC5424 (modern) syslog, supports structured data (default)\n" \
212 "modified RFC3164 without hostname for local syslogd (/dev/log)\n" \
213 "journald (systemd log) native format\n" \
216 static enum zlog_5424_format
log_5424_fmt(const char *fmt
,
217 enum zlog_5424_format dflt
)
221 else if (!strcmp(fmt
, "rfc5424"))
222 return ZLOG_FMT_5424
;
223 else if (!strcmp(fmt
, "rfc3164"))
224 return ZLOG_FMT_3164
;
225 else if (!strcmp(fmt
, "local-syslogd"))
226 return ZLOG_FMT_LOCAL
;
227 else if (!strcmp(fmt
, "journald"))
228 return ZLOG_FMT_JOURNALD
;
233 DEFPY(log_5424_destination_file
,
234 log_5424_destination_file_cmd
,
235 "[no] destination file$type PATH "
236 "[create$create [{user WORD|group WORD|mode PERMS}]"
237 "|no-create$nocreate] "
238 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
240 "Log destination setup\n"
242 "Path to destination\n"
243 "Create file if it does not exist\n"
249 "File permissions (octal)\n"
250 "Do not create file if it does not exist\n"
253 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
254 enum zlog_5424_dst dst
;
255 bool reconf
= true, warn_perm
= false;
256 char *prev_user
, *prev_group
;
257 mode_t perm_val
= LOGFILE_MASK
& 0666;
258 enum zlog_5424_format fmtv
;
261 return reconf_clear_dst(cfg
, vty
);
263 fmtv
= log_5424_fmt(fmt
, ZLOG_FMT_5424
);
266 char *errp
= (char *)perms
;
268 perm_val
= strtoul(perms
, &errp
, 8);
269 if (*errp
|| errp
== perms
|| perm_val
== 0 ||
270 (perm_val
& ~0666)) {
271 vty_out(vty
, "%% Invalid permissions value \"%s\"\n",
277 dst
= (strcmp(type
, "fifo") == 0) ? ZLOG_5424_DST_FIFO
278 : ZLOG_5424_DST_FILE
;
280 if (cfg
->filename
&& !strcmp(path
, cfg
->filename
) &&
281 dst
== cfg
->cfg
.dst
&& cfg
->cfg
.active
&& cfg
->cfg
.fmt
== fmtv
)
284 /* keep for compare below */
285 prev_user
= cfg
->file_user
;
286 prev_group
= cfg
->file_group
;
287 cfg
->file_user
= NULL
;
288 cfg
->file_group
= NULL
;
292 cfg
->filename
= XSTRDUP(MTYPE_LOG_5424_DATA
, path
);
294 cfg
->cfg
.filename
= cfg
->filename
;
298 cfg
->cfg
.file_nocreate
= true;
301 struct passwd
*pwent
;
303 warn_perm
|= (prev_user
&& strcmp(user
, prev_user
));
304 cfg
->file_user
= XSTRDUP(MTYPE_LOG_5424_DATA
, user
);
307 pwent
= getpwnam(user
);
310 "%% Could not look up user \"%s\" (%s), file owner will be left untouched!\n",
312 errno
? safe_strerror(errno
)
313 : "No entry by this user name");
315 cfg
->cfg
.file_uid
= pwent
->pw_uid
;
320 warn_perm
|= (prev_group
&& strcmp(group
, prev_group
));
321 cfg
->file_group
= XSTRDUP(MTYPE_LOG_5424_DATA
, group
);
324 grent
= getgrnam(group
);
327 "%% Could not look up group \"%s\" (%s), file group will be left untouched!\n",
329 errno
? safe_strerror(errno
)
330 : "No entry by this group name");
332 cfg
->cfg
.file_gid
= grent
->gr_gid
;
335 XFREE(MTYPE_LOG_5424_DATA
, prev_user
);
336 XFREE(MTYPE_LOG_5424_DATA
, prev_group
);
338 if (cfg
->cfg
.file_uid
!= (uid_t
)-1 || cfg
->cfg
.file_gid
!= (gid_t
)-1) {
341 if (stat(cfg
->filename
, &st
) == 0) {
342 warn_perm
|= (st
.st_uid
!= cfg
->cfg
.file_uid
);
343 warn_perm
|= (st
.st_gid
!= cfg
->cfg
.file_gid
);
348 "%% Warning: ownership and permission bits are only applied when creating\n"
349 "%% log files. Use system tools to change existing files.\n"
350 "%% FRR may also be missing necessary privileges to set these.\n");
353 return reconf_dst(cfg
, vty
);
358 /* FIFOs are for legacy /dev/log implementations; using this is very much not
359 * recommended since it can unexpectedly block in logging calls. Also the fd
360 * would need to be reopened when the process at the other end restarts. None
361 * of this is handled - use at your own caution. It's _HIDDEN for a purpose.
363 ALIAS_HIDDEN(log_5424_destination_file
,
364 log_5424_destination_fifo_cmd
,
365 "[no] destination fifo$type PATH "
366 "[create$create [{owner WORD|group WORD|permissions PERMS}]"
367 "|no-create$nocreate] "
368 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
370 "Log destination setup\n"
371 "Log to filesystem FIFO\n"
372 "Path to destination\n"
373 "Create file if it does not exist\n"
379 "File permissions (octal)\n"
380 "Do not create file if it does not exist\n"
383 static int dst_unix(struct vty
*vty
, const char *no
, const char *path
,
384 enum zlog_5424_format fmt
, enum unix_special special
)
386 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
389 return reconf_clear_dst(cfg
, vty
);
391 cfg
->unix_special
= special
;
393 if (cfg
->cfg
.dst
== ZLOG_5424_DST_UNIX
&& cfg
->filename
&&
394 !strcmp(path
, cfg
->filename
) && cfg
->cfg
.active
&&
400 cfg
->filename
= XSTRDUP(MTYPE_LOG_5424_DATA
, path
);
401 cfg
->cfg
.dst
= ZLOG_5424_DST_UNIX
;
402 cfg
->cfg
.filename
= cfg
->filename
;
405 cfg
->cfg
.reconn_backoff
= 25;
406 cfg
->cfg
.reconn_backoff_cur
= 25;
407 cfg
->cfg
.reconn_backoff_max
= 10000;
408 return reconf_dst(cfg
, vty
);
411 DEFPY(log_5424_destination_unix
,
412 log_5424_destination_unix_cmd
,
413 "[no] destination unix PATH "
414 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
416 "Log destination setup\n"
417 "Log to unix socket\n"
421 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
422 enum zlog_5424_format fmtv
= log_5424_fmt(fmt
, ZLOG_FMT_5424
);
424 return dst_unix(vty
, no
, path
, fmtv
, SPECIAL_NONE
);
427 DEFPY(log_5424_destination_journald
,
428 log_5424_destination_journald_cmd
,
429 "[no] destination journald",
431 "Log destination setup\n"
432 "Log directly to systemd's journald\n")
434 return dst_unix(vty
, no
, "/run/systemd/journal/socket",
435 ZLOG_FMT_JOURNALD
, SPECIAL_JOURNALD
);
438 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 1200061)
439 #define ZLOG_FMT_DEV_LOG ZLOG_FMT_5424
440 #elif defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 500000000)
441 #define ZLOG_FMT_DEV_LOG ZLOG_FMT_5424
443 #define ZLOG_FMT_DEV_LOG ZLOG_FMT_LOCAL
446 DEFPY(log_5424_destination_syslog
,
447 log_5424_destination_syslog_cmd
,
448 "[no] destination syslog [supports-rfc5424]$supp5424",
450 "Log destination setup\n"
451 "Log directly to syslog\n"
452 "Use RFC5424 format (please refer to documentation)\n")
454 int format
= supp5424
? ZLOG_FMT_5424
: ZLOG_FMT_DEV_LOG
;
456 /* unfortunately, there is no way to detect 5424 support */
457 return dst_unix(vty
, no
, "/dev/log", format
, SPECIAL_SYSLOG
);
460 /* could add something like
461 * "destination <udp|tcp>$proto <A.B.C.D|X:X::X:X> (1-65535)$port"
462 * here, but there are 2 reasons not to do that:
464 * - each FRR daemon would open its own connection, there's no system level
465 * aggregation. That's the system's syslogd's job. It likely also
466 * supports directing & filtering log messages with configurable rules.
467 * - we're likely not going to support DTLS or TLS for more secure logging;
468 * adding this would require a considerable amount of additional config
469 * and an entire TLS library to begin with. A proper syslogd implements
470 * all of this, why reinvent the wheel?
473 DEFPY(log_5424_destination_fd
,
474 log_5424_destination_fd_cmd
,
475 "[no] destination <fd <(0-63)$fd|envvar WORD>|stdout$fd1|stderr$fd2>"
476 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
478 "Log destination setup\n"
479 "Log to pre-opened file descriptor\n"
480 "File descriptor number (must be open at startup)\n"
481 "Read file descriptor number from environment variable\n"
482 "Environment variable name\n"
483 "Log to standard output\n"
484 "Log to standard error output\n"
487 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
488 bool envvar_problem
= false;
489 enum zlog_5424_format fmtv
;
492 return reconf_clear_dst(cfg
, vty
);
494 fmtv
= log_5424_fmt(fmt
, ZLOG_FMT_5424
);
499 envval
= getenv(envvar
);
501 envvar_problem
= true;
505 fd
= strtoul(envval
, &errp
, 0);
506 if (errp
== envval
|| *errp
)
507 envvar_problem
= true;
517 if (cfg
->cfg
.dst
== ZLOG_5424_DST_FD
&& cfg
->cfg
.fd
== fd
&&
518 cfg
->cfg
.active
&& cfg
->cfg
.fmt
== fmtv
)
523 cfg
->cfg
.dst
= ZLOG_5424_DST_FD
;
527 cfg
->envvar
= XSTRDUP(MTYPE_LOG_5424_DATA
, envvar
);
531 "%% environment variable \"%s\" not present or invalid.\n",
533 if (!frr_is_startup_fd(fd
))
535 "%% file descriptor %d was not open when this process was started\n",
537 if (envvar_problem
|| !frr_is_startup_fd(fd
))
539 "%% configuration will be saved but has no effect currently\n");
541 return reconf_dst(cfg
, vty
);
544 DEFPY(log_5424_destination_none
,
545 log_5424_destination_none_cmd
,
546 "[no] destination [none]",
548 "Log destination setup\n"
549 "Deconfigure destination\n")
551 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
553 return reconf_clear_dst(cfg
, vty
);
556 /* end of destinations */
560 "[no] priority <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg",
562 "Set minimum message priority to include for this target\n"
565 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
566 int prio_min
= log_level_match(levelarg
);
568 if (prio_min
== cfg
->cfg
.prio_min
)
571 cfg
->cfg
.prio_min
= prio_min
;
572 return reconf_meta(cfg
, vty
);
575 DEFPY(log_5424_facility
,
576 log_5424_facility_cmd
,
577 "[no] facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>$facilityarg",
579 "Set syslog facility to use\n"
582 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
583 int facility
= facility_match(facilityarg
);
585 if (cfg
->cfg
.facility
== facility
)
588 cfg
->cfg
.facility
= facility
;
589 return reconf_meta(cfg
, vty
);
594 "[no] structured-data <code-location|version|unique-id|error-category|format-args>$option",
596 "Select structured data (key/value pairs) to include in each message\n"
597 "FRR source code location\n"
599 "Unique message identifier (XXXXX-XXXXX)\n"
600 "Error category (EC numeric)\n"
601 "Individual formatted log message arguments\n")
603 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
604 bool val
= !no
, *ptr
;
605 struct log_option
*opt
= log_opts
;
607 while (opt
->name
&& strcmp(opt
->name
, option
))
612 ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
617 return reconf_meta(cfg
, vty
);
620 DEFPY(log_5424_ts_prec
,
621 log_5424_ts_prec_cmd
,
622 "[no] timestamp precision (0-9)",
624 "Timestamp options\n"
625 "Number of sub-second digits to include\n"
626 "Number of sub-second digits to include\n")
628 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
629 uint32_t ts_flags
= cfg
->cfg
.ts_flags
;
631 ts_flags
&= ~ZLOG_TS_PREC
;
633 ts_flags
|= DFLT_TS_FLAGS
& ZLOG_TS_PREC
;
635 ts_flags
|= precision
;
637 if (ts_flags
== cfg
->cfg
.ts_flags
)
640 cfg
->cfg
.ts_flags
= ts_flags
;
641 return reconf_meta(cfg
, vty
);
644 DEFPY(log_5424_ts_local
,
645 log_5424_ts_local_cmd
,
646 "[no] timestamp local-time",
648 "Timestamp options\n"
649 "Use local system time zone rather than UTC\n")
651 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
652 uint32_t ts_flags
= cfg
->cfg
.ts_flags
;
654 ts_flags
&= ~ZLOG_TS_UTC
;
656 ts_flags
|= DFLT_TS_FLAGS
& ZLOG_TS_UTC
;
658 ts_flags
|= (~DFLT_TS_FLAGS
) & ZLOG_TS_UTC
;
660 if (ts_flags
== cfg
->cfg
.ts_flags
)
663 cfg
->cfg
.ts_flags
= ts_flags
;
664 return reconf_meta(cfg
, vty
);
667 static int log_5424_node_exit(struct vty
*vty
)
669 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
671 if ((cfg
->reconf_dst
|| cfg
->reconf_meta
) && vty
->type
!= VTY_FILE
)
672 vty_out(vty
, "%% applying changes.\n");
675 zlog_5424_apply_dst(&cfg
->cfg
);
676 else if (cfg
->reconf_meta
)
677 zlog_5424_apply_meta(&cfg
->cfg
);
679 cfg
->reconf_dst
= cfg
->reconf_meta
= false;
683 static int log_5424_config_write(struct vty
*vty
)
685 struct zlog_cfg_5424_user
*cfg
;
687 frr_each (targets
, &targets
, cfg
) {
688 const char *fmt_str
= "";
690 vty_out(vty
, "log extended %s\n", cfg
->name
);
692 switch (cfg
->cfg
.fmt
) {
694 fmt_str
= " format rfc5424";
697 fmt_str
= " format rfc3164";
700 fmt_str
= " format local-syslogd";
702 case ZLOG_FMT_JOURNALD
:
703 fmt_str
= " format journald";
707 switch (cfg
->cfg
.dst
) {
708 case ZLOG_5424_DST_NONE
:
709 vty_out(vty
, " ! no destination configured\n");
712 case ZLOG_5424_DST_FD
:
713 if (cfg
->cfg
.fmt
== ZLOG_FMT_5424
)
717 vty_out(vty
, " destination fd envvar %s%s\n",
718 cfg
->envvar
, fmt_str
);
719 else if (cfg
->cfg
.fd
== 1)
720 vty_out(vty
, " destination stdout%s\n",
722 else if (cfg
->cfg
.fd
== 2)
723 vty_out(vty
, " destination stderr%s\n",
726 vty_out(vty
, " destination fd %d%s\n",
727 cfg
->cfg
.fd
, fmt_str
);
730 case ZLOG_5424_DST_FILE
:
731 case ZLOG_5424_DST_FIFO
:
732 if (cfg
->cfg
.fmt
== ZLOG_FMT_5424
)
735 vty_out(vty
, " destination %s %s",
736 (cfg
->cfg
.dst
== ZLOG_5424_DST_FIFO
) ? "fifo"
740 if (cfg
->cfg
.file_nocreate
)
741 vty_out(vty
, " no-create");
742 else if (cfg
->file_user
|| cfg
->file_group
||
743 cfg
->cfg
.file_mode
!= (LOGFILE_MASK
& 0666)) {
744 vty_out(vty
, " create");
747 vty_out(vty
, " user %s",
750 vty_out(vty
, " group %s",
752 if (cfg
->cfg
.file_mode
!= (LOGFILE_MASK
& 0666))
753 vty_out(vty
, " mode %04o",
756 vty_out(vty
, "%s\n", fmt_str
);
759 case ZLOG_5424_DST_UNIX
:
760 switch (cfg
->unix_special
) {
762 vty_out(vty
, " destination unix %s%s\n",
763 cfg
->filename
, fmt_str
);
766 if (cfg
->cfg
.fmt
== ZLOG_FMT_DEV_LOG
)
767 vty_out(vty
, " destination syslog\n");
770 " destination syslog supports-rfc5424\n");
772 case SPECIAL_JOURNALD
:
773 vty_out(vty
, " destination journald\n");
779 if (cfg
->cfg
.prio_min
!= LOG_DEBUG
)
780 vty_out(vty
, " priority %s\n",
781 zlog_priority_str(cfg
->cfg
.prio_min
));
782 if (cfg
->cfg
.facility
!= DFLT_FACILITY
)
783 vty_out(vty
, " facility %s\n",
784 facility_name(cfg
->cfg
.facility
));
786 for (struct log_option
*opt
= log_opts
; opt
->name
; opt
++) {
787 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
789 if (*ptr
!= opt
->dflt
)
790 vty_out(vty
, " %sstructured-data %s\n",
791 *ptr
? "" : "no ", opt
->name
);
794 if ((cfg
->cfg
.ts_flags
^ DFLT_TS_FLAGS
) & ZLOG_TS_PREC
)
795 vty_out(vty
, " timestamp precision %u\n",
796 cfg
->cfg
.ts_flags
& ZLOG_TS_PREC
);
798 if ((cfg
->cfg
.ts_flags
^ DFLT_TS_FLAGS
) & ZLOG_TS_UTC
) {
799 if (cfg
->cfg
.ts_flags
& ZLOG_TS_UTC
)
800 vty_out(vty
, " no timestamp local-time\n");
802 vty_out(vty
, " timestamp local-time\n");
810 static int log_5424_show(struct vty
*vty
)
812 struct zlog_cfg_5424_user
*cfg
;
814 frr_each (targets
, &targets
, cfg
) {
815 vty_out(vty
, "\nExtended log target %pSQq\n", cfg
->name
);
817 switch (cfg
->cfg
.dst
) {
818 case ZLOG_5424_DST_NONE
:
820 " Inactive (no destination configured)\n");
823 case ZLOG_5424_DST_FD
:
826 " logging to fd %d from environment variable %pSE\n",
827 cfg
->cfg
.fd
, cfg
->envvar
);
828 else if (cfg
->cfg
.fd
== 1)
829 vty_out(vty
, " logging to stdout\n");
830 else if (cfg
->cfg
.fd
== 2)
831 vty_out(vty
, " logging to stderr\n");
833 vty_out(vty
, " logging to fd %d\n",
837 case ZLOG_5424_DST_FILE
:
838 case ZLOG_5424_DST_FIFO
:
839 case ZLOG_5424_DST_UNIX
:
840 vty_out(vty
, " logging to %s: %pSE\n",
841 (cfg
->cfg
.dst
== ZLOG_5424_DST_FIFO
) ? "fifo"
842 : (cfg
->cfg
.dst
== ZLOG_5424_DST_UNIX
)
849 vty_out(vty
, " log level: %s, facility: %s\n",
850 zlog_priority_str(cfg
->cfg
.prio_min
),
851 facility_name(cfg
->cfg
.facility
));
853 bool any_meta
= false, first
= true;
855 for (struct log_option
*opt
= log_opts
; opt
->name
; opt
++) {
856 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
864 switch (cfg
->cfg
.fmt
) {
866 case ZLOG_FMT_JOURNALD
:
867 vty_out(vty
, " structured data: ");
869 for (struct log_option
*opt
= log_opts
; opt
->name
;
871 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) +
875 vty_out(vty
, "%s%s", first
? "" : ", ",
884 " structured data is not supported by the selected format\n");
893 struct timeval err_ts
;
896 zlog_5424_state(&cfg
->cfg
, &lost_msgs
, &last_errno
,
897 &stale_errno
, &err_ts
);
898 vty_out(vty
, " number of lost messages: %zu\n", lost_msgs
);
903 since
= monotime_since(&err_ts
, NULL
);
905 " last error: %s (%lld.%06llds ago, currently %s)\n",
906 last_errno
? safe_strerror(last_errno
) : "none",
907 since
/ 1000000LL, since
% 1000000LL,
908 stale_errno
? "OK" : "erroring");
913 static struct cmd_node extlog_node
= {
916 .parent_node
= CONFIG_NODE
,
917 .prompt
= "%s(config-ext-log)# ",
919 .config_write
= log_5424_config_write
,
920 .node_exit
= log_5424_node_exit
,
923 static void log_5424_autocomplete(vector comps
, struct cmd_token
*token
)
925 struct zlog_cfg_5424_user
*cfg
;
927 frr_each (targets
, &targets
, cfg
)
928 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, cfg
->name
));
931 static const struct cmd_variable_handler log_5424_var_handlers
[] = {
932 {.tokenname
= "EXTLOGNAME", .completions
= log_5424_autocomplete
},
933 {.completions
= NULL
},
936 void log_5424_cmd_init(void)
938 hook_register(zlog_cli_show
, log_5424_show
);
940 cmd_variable_handler_register(log_5424_var_handlers
);
943 install_node(&extlog_node
);
944 install_default(EXTLOG_NODE
);
946 install_element(CONFIG_NODE
, &log_5424_target_cmd
);
947 install_element(CONFIG_NODE
, &no_log_5424_target_cmd
);
949 install_element(EXTLOG_NODE
, &log_5424_destination_file_cmd
);
950 install_element(EXTLOG_NODE
, &log_5424_destination_fifo_cmd
);
951 install_element(EXTLOG_NODE
, &log_5424_destination_unix_cmd
);
952 install_element(EXTLOG_NODE
, &log_5424_destination_journald_cmd
);
953 install_element(EXTLOG_NODE
, &log_5424_destination_syslog_cmd
);
954 install_element(EXTLOG_NODE
, &log_5424_destination_fd_cmd
);
956 install_element(EXTLOG_NODE
, &log_5424_meta_cmd
);
957 install_element(EXTLOG_NODE
, &log_5424_prio_cmd
);
958 install_element(EXTLOG_NODE
, &log_5424_facility_cmd
);
959 install_element(EXTLOG_NODE
, &log_5424_ts_prec_cmd
);
960 install_element(EXTLOG_NODE
, &log_5424_ts_local_cmd
);
965 static int log_5424_early_init(struct thread_master
*master
);
966 static int log_5424_rotate(void);
967 static int log_5424_fini(void);
969 __attribute__((_CONSTRUCTOR(475))) static void zlog_5424_startup_init(void)
971 hook_register(frr_early_init
, log_5424_early_init
);
972 hook_register(zlog_rotate
, log_5424_rotate
);
973 hook_register(frr_fini
, log_5424_fini
);
976 static int log_5424_early_init(struct thread_master
*master
)
978 log_5424_master
= master
;
983 static int log_5424_rotate(void)
985 struct zlog_cfg_5424_user
*cfg
;
987 frr_each (targets
, &targets
, cfg
)
988 if (!zlog_5424_rotate(&cfg
->cfg
))
990 "log rotation on extended log target %s failed",
996 static int log_5424_fini(void)
998 struct zlog_cfg_5424_user
*cfg
;
1000 while ((cfg
= targets_pop(&targets
)))
1001 log_5424_free(cfg
, true);
1003 log_5424_master
= NULL
;