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 #include "lib/zlog_5424_cli_clippy.c"
163 DEFPY_NOSH(log_5424_target
,
165 "log extended-syslog EXTLOGNAME",
167 "Extended RFC5424 syslog (including file targets)\n"
168 "Name identifying this syslog target\n")
170 struct zlog_cfg_5424_user
*cfg
, ref
;
172 ref
.name
= (char *)extlogname
;
173 cfg
= targets_find(&targets
, &ref
);
176 cfg
= log_5424_alloc(extlogname
);
178 VTY_PUSH_CONTEXT(EXTLOG_NODE
, cfg
);
182 DEFPY(no_log_5424_target
,
183 no_log_5424_target_cmd
,
184 "no log extended-syslog EXTLOGNAME",
187 "Extended RFC5424 syslog (including file targets)\n"
188 "Name identifying this syslog target\n")
190 struct zlog_cfg_5424_user
*cfg
, ref
;
192 ref
.name
= (char *)extlogname
;
193 cfg
= targets_find(&targets
, &ref
);
196 vty_out(vty
, "%% No extended syslog target named \"%s\"\n",
201 log_5424_free(cfg
, false);
205 /* "format <rfc3164|rfc5424|local-syslogd|journald>$fmt" */
206 #define FORMAT_HELP \
207 "Select log message formatting\n" \
208 "RFC3164 (legacy) syslog\n" \
209 "RFC5424 (modern) syslog, supports structured data (default)\n" \
210 "modified RFC3164 without hostname for local syslogd (/dev/log)\n" \
211 "journald (systemd log) native format\n" \
214 static enum zlog_5424_format
log_5424_fmt(const char *fmt
,
215 enum zlog_5424_format dflt
)
219 else if (!strcmp(fmt
, "rfc5424"))
220 return ZLOG_FMT_5424
;
221 else if (!strcmp(fmt
, "rfc3164"))
222 return ZLOG_FMT_3164
;
223 else if (!strcmp(fmt
, "local-syslogd"))
224 return ZLOG_FMT_LOCAL
;
225 else if (!strcmp(fmt
, "journald"))
226 return ZLOG_FMT_JOURNALD
;
231 DEFPY(log_5424_destination_file
,
232 log_5424_destination_file_cmd
,
233 "[no] destination file$type PATH "
234 "[create$create [{user WORD|group WORD|mode PERMS}]"
235 "|no-create$nocreate] "
236 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
238 "Log destination setup\n"
240 "Path to destination\n"
241 "Create file if it does not exist\n"
247 "File permissions (octal)\n"
248 "Do not create file if it does not exist\n"
251 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
252 enum zlog_5424_dst dst
;
253 bool reconf
= true, warn_perm
= false;
254 char *prev_user
, *prev_group
;
255 mode_t perm_val
= LOGFILE_MASK
& 0666;
256 enum zlog_5424_format fmtv
;
259 return reconf_clear_dst(cfg
, vty
);
261 fmtv
= log_5424_fmt(fmt
, ZLOG_FMT_5424
);
264 char *errp
= (char *)perms
;
266 perm_val
= strtoul(perms
, &errp
, 8);
267 if (*errp
|| errp
== perms
|| perm_val
== 0 ||
268 (perm_val
& ~0666)) {
269 vty_out(vty
, "%% Invalid permissions value \"%s\"\n",
275 dst
= (strcmp(type
, "fifo") == 0) ? ZLOG_5424_DST_FIFO
276 : ZLOG_5424_DST_FILE
;
278 if (cfg
->filename
&& !strcmp(path
, cfg
->filename
) &&
279 dst
== cfg
->cfg
.dst
&& cfg
->cfg
.active
&& cfg
->cfg
.fmt
== fmtv
)
282 /* keep for compare below */
283 prev_user
= cfg
->file_user
;
284 prev_group
= cfg
->file_group
;
285 cfg
->file_user
= NULL
;
286 cfg
->file_group
= NULL
;
290 cfg
->filename
= XSTRDUP(MTYPE_LOG_5424_DATA
, path
);
292 cfg
->cfg
.filename
= cfg
->filename
;
296 cfg
->cfg
.file_nocreate
= true;
299 struct passwd
*pwent
;
301 warn_perm
|= (prev_user
&& strcmp(user
, prev_user
));
302 cfg
->file_user
= XSTRDUP(MTYPE_LOG_5424_DATA
, user
);
305 pwent
= getpwnam(user
);
308 "%% Could not look up user \"%s\" (%s), file owner will be left untouched!\n",
310 errno
? safe_strerror(errno
)
311 : "No entry by this user name");
313 cfg
->cfg
.file_uid
= pwent
->pw_uid
;
318 warn_perm
|= (prev_group
&& strcmp(group
, prev_group
));
319 cfg
->file_group
= XSTRDUP(MTYPE_LOG_5424_DATA
, group
);
322 grent
= getgrnam(group
);
325 "%% Could not look up group \"%s\" (%s), file group will be left untouched!\n",
327 errno
? safe_strerror(errno
)
328 : "No entry by this group name");
330 cfg
->cfg
.file_gid
= grent
->gr_gid
;
333 XFREE(MTYPE_LOG_5424_DATA
, prev_user
);
334 XFREE(MTYPE_LOG_5424_DATA
, prev_group
);
336 if (cfg
->cfg
.file_uid
!= (uid_t
)-1 || cfg
->cfg
.file_gid
!= (gid_t
)-1) {
339 if (stat(cfg
->filename
, &st
) == 0) {
340 warn_perm
|= (st
.st_uid
!= cfg
->cfg
.file_uid
);
341 warn_perm
|= (st
.st_gid
!= cfg
->cfg
.file_gid
);
346 "%% Warning: ownership and permission bits are only applied when creating\n"
347 "%% log files. Use system tools to change existing files.\n"
348 "%% FRR may also be missing necessary privileges to set these.\n");
351 return reconf_dst(cfg
, vty
);
356 /* FIFOs are for legacy /dev/log implementations; using this is very much not
357 * recommended since it can unexpectedly block in logging calls. Also the fd
358 * would need to be reopened when the process at the other end restarts. None
359 * of this is handled - use at your own caution. It's _HIDDEN for a purpose.
361 ALIAS_HIDDEN(log_5424_destination_file
,
362 log_5424_destination_fifo_cmd
,
363 "[no] destination fifo$type PATH "
364 "[create$create [{owner WORD|group WORD|permissions PERMS}]"
365 "|no-create$nocreate] "
366 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
368 "Log destination setup\n"
369 "Log to filesystem FIFO\n"
370 "Path to destination\n"
371 "Create file if it does not exist\n"
377 "File permissions (octal)\n"
378 "Do not create file if it does not exist\n"
381 static int dst_unix(struct vty
*vty
, const char *no
, const char *path
,
382 enum zlog_5424_format fmt
, enum unix_special special
)
384 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
387 return reconf_clear_dst(cfg
, vty
);
389 cfg
->unix_special
= special
;
391 if (cfg
->cfg
.dst
== ZLOG_5424_DST_UNIX
&& cfg
->filename
&&
392 !strcmp(path
, cfg
->filename
) && cfg
->cfg
.active
&&
398 cfg
->filename
= XSTRDUP(MTYPE_LOG_5424_DATA
, path
);
399 cfg
->cfg
.dst
= ZLOG_5424_DST_UNIX
;
400 cfg
->cfg
.filename
= cfg
->filename
;
403 cfg
->cfg
.reconn_backoff
= 25;
404 cfg
->cfg
.reconn_backoff_cur
= 25;
405 cfg
->cfg
.reconn_backoff_max
= 10000;
406 return reconf_dst(cfg
, vty
);
409 DEFPY(log_5424_destination_unix
,
410 log_5424_destination_unix_cmd
,
411 "[no] destination unix PATH "
412 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
414 "Log destination setup\n"
415 "Log to unix socket\n"
419 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
420 enum zlog_5424_format fmtv
= log_5424_fmt(fmt
, ZLOG_FMT_5424
);
422 return dst_unix(vty
, no
, path
, fmtv
, SPECIAL_NONE
);
425 DEFPY(log_5424_destination_journald
,
426 log_5424_destination_journald_cmd
,
427 "[no] destination journald",
429 "Log destination setup\n"
430 "Log directly to systemd's journald\n")
432 return dst_unix(vty
, no
, "/run/systemd/journal/socket",
433 ZLOG_FMT_JOURNALD
, SPECIAL_JOURNALD
);
436 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 1200061)
437 #define ZLOG_FMT_DEV_LOG ZLOG_FMT_5424
438 #elif defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 500000000)
439 #define ZLOG_FMT_DEV_LOG ZLOG_FMT_5424
441 #define ZLOG_FMT_DEV_LOG ZLOG_FMT_LOCAL
444 DEFPY(log_5424_destination_syslog
,
445 log_5424_destination_syslog_cmd
,
446 "[no] destination syslog [supports-rfc5424]$supp5424",
448 "Log destination setup\n"
449 "Log directly to syslog\n"
450 "Use RFC5424 format (please refer to documentation)\n")
452 int format
= supp5424
? ZLOG_FMT_5424
: ZLOG_FMT_DEV_LOG
;
454 /* unfortunately, there is no way to detect 5424 support */
455 return dst_unix(vty
, no
, "/dev/log", format
, SPECIAL_SYSLOG
);
458 /* could add something like
459 * "destination <udp|tcp>$proto <A.B.C.D|X:X::X:X> (1-65535)$port"
460 * here, but there are 2 reasons not to do that:
462 * - each FRR daemon would open its own connection, there's no system level
463 * aggregation. That's the system's syslogd's job. It likely also
464 * supports directing & filtering log messages with configurable rules.
465 * - we're likely not going to support DTLS or TLS for more secure logging;
466 * adding this would require a considerable amount of additional config
467 * and an entire TLS library to begin with. A proper syslogd implements
468 * all of this, why reinvent the wheel?
471 DEFPY(log_5424_destination_fd
,
472 log_5424_destination_fd_cmd
,
473 "[no] destination <fd <(0-63)$fd|envvar WORD>|stdout$fd1|stderr$fd2>"
474 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
476 "Log destination setup\n"
477 "Log to pre-opened file descriptor\n"
478 "File descriptor number (must be open at startup)\n"
479 "Read file descriptor number from environment variable\n"
480 "Environment variable name\n"
481 "Log to standard output\n"
482 "Log to standard error output\n"
485 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
486 bool envvar_problem
= false;
487 enum zlog_5424_format fmtv
;
490 return reconf_clear_dst(cfg
, vty
);
492 fmtv
= log_5424_fmt(fmt
, ZLOG_FMT_5424
);
497 envval
= getenv(envvar
);
499 envvar_problem
= true;
503 fd
= strtoul(envval
, &errp
, 0);
504 if (errp
== envval
|| *errp
)
505 envvar_problem
= true;
515 if (cfg
->cfg
.dst
== ZLOG_5424_DST_FD
&& cfg
->cfg
.fd
== fd
&&
516 cfg
->cfg
.active
&& cfg
->cfg
.fmt
== fmtv
)
521 cfg
->cfg
.dst
= ZLOG_5424_DST_FD
;
525 cfg
->envvar
= XSTRDUP(MTYPE_LOG_5424_DATA
, envvar
);
529 "%% environment variable \"%s\" not present or invalid.\n",
531 if (!frr_is_startup_fd(fd
))
533 "%% file descriptor %d was not open when this process was started\n",
535 if (envvar_problem
|| !frr_is_startup_fd(fd
))
537 "%% configuration will be saved but has no effect currently\n");
539 return reconf_dst(cfg
, vty
);
542 DEFPY(log_5424_destination_none
,
543 log_5424_destination_none_cmd
,
544 "[no] destination [none]",
546 "Log destination setup\n"
547 "Deconfigure destination\n")
549 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
551 return reconf_clear_dst(cfg
, vty
);
554 /* end of destinations */
558 "[no] priority <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg",
560 "Set minimum message priority to include for this target\n"
563 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
564 int prio_min
= log_level_match(levelarg
);
566 if (prio_min
== cfg
->cfg
.prio_min
)
569 cfg
->cfg
.prio_min
= prio_min
;
570 return reconf_meta(cfg
, vty
);
573 DEFPY(log_5424_facility
,
574 log_5424_facility_cmd
,
575 "[no] facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>$facilityarg",
577 "Set syslog facility to use\n"
580 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
581 int facility
= facility_match(facilityarg
);
583 if (cfg
->cfg
.facility
== facility
)
586 cfg
->cfg
.facility
= facility
;
587 return reconf_meta(cfg
, vty
);
592 "[no] structured-data <code-location|version|unique-id|error-category|format-args>$option",
594 "Select structured data (key/value pairs) to include in each message\n"
595 "FRR source code location\n"
597 "Unique message identifier (XXXXX-XXXXX)\n"
598 "Error category (EC numeric)\n"
599 "Individual formatted log message arguments\n")
601 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
602 bool val
= !no
, *ptr
;
603 struct log_option
*opt
= log_opts
;
605 while (opt
->name
&& strcmp(opt
->name
, option
))
610 ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
615 return reconf_meta(cfg
, vty
);
618 DEFPY(log_5424_ts_prec
,
619 log_5424_ts_prec_cmd
,
620 "[no] timestamp precision (0-9)",
622 "Timestamp options\n"
623 "Number of sub-second digits to include\n"
624 "Number of sub-second digits to include\n")
626 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
627 uint32_t ts_flags
= cfg
->cfg
.ts_flags
;
629 ts_flags
&= ~ZLOG_TS_PREC
;
631 ts_flags
|= DFLT_TS_FLAGS
& ZLOG_TS_PREC
;
633 ts_flags
|= precision
;
635 if (ts_flags
== cfg
->cfg
.ts_flags
)
638 cfg
->cfg
.ts_flags
= ts_flags
;
639 return reconf_meta(cfg
, vty
);
642 DEFPY(log_5424_ts_local
,
643 log_5424_ts_local_cmd
,
644 "[no] timestamp local-time",
646 "Timestamp options\n"
647 "Use local system time zone rather than UTC\n")
649 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
650 uint32_t ts_flags
= cfg
->cfg
.ts_flags
;
652 ts_flags
&= ~ZLOG_TS_UTC
;
654 ts_flags
|= DFLT_TS_FLAGS
& ZLOG_TS_UTC
;
656 ts_flags
|= (~DFLT_TS_FLAGS
) & ZLOG_TS_UTC
;
658 if (ts_flags
== cfg
->cfg
.ts_flags
)
661 cfg
->cfg
.ts_flags
= ts_flags
;
662 return reconf_meta(cfg
, vty
);
665 static int log_5424_node_exit(struct vty
*vty
)
667 VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user
, cfg
);
669 if ((cfg
->reconf_dst
|| cfg
->reconf_meta
) && vty
->type
!= VTY_FILE
)
670 vty_out(vty
, "%% applying changes.\n");
673 zlog_5424_apply_dst(&cfg
->cfg
);
674 else if (cfg
->reconf_meta
)
675 zlog_5424_apply_meta(&cfg
->cfg
);
677 cfg
->reconf_dst
= cfg
->reconf_meta
= false;
681 static int log_5424_config_write(struct vty
*vty
)
683 struct zlog_cfg_5424_user
*cfg
;
685 frr_each (targets
, &targets
, cfg
) {
686 const char *fmt_str
= "";
688 vty_out(vty
, "log extended %s\n", cfg
->name
);
690 switch (cfg
->cfg
.fmt
) {
692 fmt_str
= " format rfc5424";
695 fmt_str
= " format rfc3164";
698 fmt_str
= " format local-syslogd";
700 case ZLOG_FMT_JOURNALD
:
701 fmt_str
= " format journald";
705 switch (cfg
->cfg
.dst
) {
706 case ZLOG_5424_DST_NONE
:
707 vty_out(vty
, " ! no destination configured\n");
710 case ZLOG_5424_DST_FD
:
711 if (cfg
->cfg
.fmt
== ZLOG_FMT_5424
)
715 vty_out(vty
, " destination fd envvar %s%s\n",
716 cfg
->envvar
, fmt_str
);
717 else if (cfg
->cfg
.fd
== 1)
718 vty_out(vty
, " destination stdout%s\n",
720 else if (cfg
->cfg
.fd
== 2)
721 vty_out(vty
, " destination stderr%s\n",
724 vty_out(vty
, " destination fd %d%s\n",
725 cfg
->cfg
.fd
, fmt_str
);
728 case ZLOG_5424_DST_FILE
:
729 case ZLOG_5424_DST_FIFO
:
730 if (cfg
->cfg
.fmt
== ZLOG_FMT_5424
)
733 vty_out(vty
, " destination %s %s",
734 (cfg
->cfg
.dst
== ZLOG_5424_DST_FIFO
) ? "fifo"
738 if (cfg
->cfg
.file_nocreate
)
739 vty_out(vty
, " no-create");
740 else if (cfg
->file_user
|| cfg
->file_group
||
741 cfg
->cfg
.file_mode
!= (LOGFILE_MASK
& 0666)) {
742 vty_out(vty
, " create");
745 vty_out(vty
, " user %s",
748 vty_out(vty
, " group %s",
750 if (cfg
->cfg
.file_mode
!= (LOGFILE_MASK
& 0666))
751 vty_out(vty
, " mode %04o",
754 vty_out(vty
, "%s\n", fmt_str
);
757 case ZLOG_5424_DST_UNIX
:
758 switch (cfg
->unix_special
) {
760 vty_out(vty
, " destination unix %s%s\n",
761 cfg
->filename
, fmt_str
);
764 if (cfg
->cfg
.fmt
== ZLOG_FMT_DEV_LOG
)
765 vty_out(vty
, " destination syslog\n");
768 " destination syslog supports-rfc5424\n");
770 case SPECIAL_JOURNALD
:
771 vty_out(vty
, " destination journald\n");
777 if (cfg
->cfg
.prio_min
!= LOG_DEBUG
)
778 vty_out(vty
, " priority %s\n",
779 zlog_priority_str(cfg
->cfg
.prio_min
));
780 if (cfg
->cfg
.facility
!= DFLT_FACILITY
)
781 vty_out(vty
, " facility %s\n",
782 facility_name(cfg
->cfg
.facility
));
784 for (struct log_option
*opt
= log_opts
; opt
->name
; opt
++) {
785 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
787 if (*ptr
!= opt
->dflt
)
788 vty_out(vty
, " %sstructured-data %s\n",
789 *ptr
? "" : "no ", opt
->name
);
792 if ((cfg
->cfg
.ts_flags
^ DFLT_TS_FLAGS
) & ZLOG_TS_PREC
)
793 vty_out(vty
, " timestamp precision %u\n",
794 cfg
->cfg
.ts_flags
& ZLOG_TS_PREC
);
796 if ((cfg
->cfg
.ts_flags
^ DFLT_TS_FLAGS
) & ZLOG_TS_UTC
) {
797 if (cfg
->cfg
.ts_flags
& ZLOG_TS_UTC
)
798 vty_out(vty
, " no timestamp local-time\n");
800 vty_out(vty
, " timestamp local-time\n");
808 static int log_5424_show(struct vty
*vty
)
810 struct zlog_cfg_5424_user
*cfg
;
812 frr_each (targets
, &targets
, cfg
) {
813 vty_out(vty
, "\nExtended log target %pSQq\n", cfg
->name
);
815 switch (cfg
->cfg
.dst
) {
816 case ZLOG_5424_DST_NONE
:
818 " Inactive (no destination configured)\n");
821 case ZLOG_5424_DST_FD
:
824 " logging to fd %d from environment variable %pSE\n",
825 cfg
->cfg
.fd
, cfg
->envvar
);
826 else if (cfg
->cfg
.fd
== 1)
827 vty_out(vty
, " logging to stdout\n");
828 else if (cfg
->cfg
.fd
== 2)
829 vty_out(vty
, " logging to stderr\n");
831 vty_out(vty
, " logging to fd %d\n",
835 case ZLOG_5424_DST_FILE
:
836 case ZLOG_5424_DST_FIFO
:
837 case ZLOG_5424_DST_UNIX
:
838 vty_out(vty
, " logging to %s: %pSE\n",
839 (cfg
->cfg
.dst
== ZLOG_5424_DST_FIFO
) ? "fifo"
840 : (cfg
->cfg
.dst
== ZLOG_5424_DST_UNIX
)
847 vty_out(vty
, " log level: %s, facility: %s\n",
848 zlog_priority_str(cfg
->cfg
.prio_min
),
849 facility_name(cfg
->cfg
.facility
));
851 bool any_meta
= false, first
= true;
853 for (struct log_option
*opt
= log_opts
; opt
->name
; opt
++) {
854 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) + opt
->offs
);
862 switch (cfg
->cfg
.fmt
) {
864 case ZLOG_FMT_JOURNALD
:
865 vty_out(vty
, " structured data: ");
867 for (struct log_option
*opt
= log_opts
; opt
->name
;
869 bool *ptr
= (bool *)(((char *)&cfg
->cfg
) +
873 vty_out(vty
, "%s%s", first
? "" : ", ",
883 " structured data is not supported by the selected format\n");
892 struct timeval err_ts
;
895 zlog_5424_state(&cfg
->cfg
, &lost_msgs
, &last_errno
,
896 &stale_errno
, &err_ts
);
897 vty_out(vty
, " number of lost messages: %zu\n", lost_msgs
);
902 since
= monotime_since(&err_ts
, NULL
);
904 " last error: %s (%lld.%06llds ago, currently %s)\n",
905 last_errno
? safe_strerror(last_errno
) : "none",
906 since
/ 1000000LL, since
% 1000000LL,
907 stale_errno
? "OK" : "erroring");
912 static struct cmd_node extlog_node
= {
915 .parent_node
= CONFIG_NODE
,
916 .prompt
= "%s(config-ext-log)# ",
918 .config_write
= log_5424_config_write
,
919 .node_exit
= log_5424_node_exit
,
922 static void log_5424_autocomplete(vector comps
, struct cmd_token
*token
)
924 struct zlog_cfg_5424_user
*cfg
;
926 frr_each (targets
, &targets
, cfg
)
927 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, cfg
->name
));
930 static const struct cmd_variable_handler log_5424_var_handlers
[] = {
931 {.tokenname
= "EXTLOGNAME", .completions
= log_5424_autocomplete
},
932 {.completions
= NULL
},
935 void log_5424_cmd_init(void)
937 hook_register(zlog_cli_show
, log_5424_show
);
939 cmd_variable_handler_register(log_5424_var_handlers
);
942 install_node(&extlog_node
);
943 install_default(EXTLOG_NODE
);
945 install_element(CONFIG_NODE
, &log_5424_target_cmd
);
946 install_element(CONFIG_NODE
, &no_log_5424_target_cmd
);
948 install_element(EXTLOG_NODE
, &log_5424_destination_file_cmd
);
949 install_element(EXTLOG_NODE
, &log_5424_destination_fifo_cmd
);
950 install_element(EXTLOG_NODE
, &log_5424_destination_unix_cmd
);
951 install_element(EXTLOG_NODE
, &log_5424_destination_journald_cmd
);
952 install_element(EXTLOG_NODE
, &log_5424_destination_syslog_cmd
);
953 install_element(EXTLOG_NODE
, &log_5424_destination_fd_cmd
);
955 install_element(EXTLOG_NODE
, &log_5424_meta_cmd
);
956 install_element(EXTLOG_NODE
, &log_5424_prio_cmd
);
957 install_element(EXTLOG_NODE
, &log_5424_facility_cmd
);
958 install_element(EXTLOG_NODE
, &log_5424_ts_prec_cmd
);
959 install_element(EXTLOG_NODE
, &log_5424_ts_local_cmd
);
964 static int log_5424_early_init(struct thread_master
*master
);
965 static int log_5424_rotate(void);
966 static int log_5424_fini(void);
968 __attribute__((_CONSTRUCTOR(475))) static void zlog_5424_startup_init(void)
970 hook_register(frr_early_init
, log_5424_early_init
);
971 hook_register(zlog_rotate
, log_5424_rotate
);
972 hook_register(frr_fini
, log_5424_fini
);
975 static int log_5424_early_init(struct thread_master
*master
)
977 log_5424_master
= master
;
982 static int log_5424_rotate(void)
984 struct zlog_cfg_5424_user
*cfg
;
986 frr_each (targets
, &targets
, cfg
)
987 if (!zlog_5424_rotate(&cfg
->cfg
))
989 "log rotation on extended log target %s failed",
995 static int log_5424_fini(void)
997 struct zlog_cfg_5424_user
*cfg
;
999 while ((cfg
= targets_pop(&targets
)))
1000 log_5424_free(cfg
, true);
1002 log_5424_master
= NULL
;