summaryrefslogtreecommitdiffstats
path: root/lib/zlog.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/zlog.h')
-rw-r--r--lib/zlog.h286
1 files changed, 286 insertions, 0 deletions
diff --git a/lib/zlog.h b/lib/zlog.h
new file mode 100644
index 0000000..a207b29
--- /dev/null
+++ b/lib/zlog.h
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (c) 2015-19 David Lamparter, for NetDEF, Inc.
+ */
+
+#ifndef _FRR_ZLOG_H
+#define _FRR_ZLOG_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
+#include <assert.h>
+
+#include "atomlist.h"
+#include "frrcu.h"
+#include "memory.h"
+#include "hook.h"
+#include "printfrr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+DECLARE_MGROUP(LOG);
+
+extern char zlog_prefix[];
+extern size_t zlog_prefixsz;
+extern int zlog_tmpdirfd;
+extern int zlog_instance;
+extern const char *zlog_progname;
+
+struct xref_logmsg {
+ struct xref xref;
+
+ const char *fmtstring;
+ uint32_t priority;
+ uint32_t ec;
+ const char *args;
+};
+
+/* whether flag was added in config mode or enable mode */
+#define LOGMSG_FLAG_EPHEMERAL (1 << 0)
+#define LOGMSG_FLAG_PERSISTENT (1 << 1)
+
+struct xrefdata_logmsg {
+ struct xrefdata xrefdata;
+
+ uint8_t fl_print_bt;
+};
+
+/* These functions are set up to write to stdout/stderr without explicit
+ * initialization and/or before config load. There is no need to call e.g.
+ * fprintf(stderr, ...) just because it's "too early" at startup. Depending
+ * on context, it may still be the right thing to use fprintf though -- try to
+ * determine whether something is a log message or something else.
+ */
+
+extern void vzlogx(const struct xref_logmsg *xref, int prio, const char *fmt,
+ va_list ap) PRINTFRR(3, 0);
+#define vzlog(prio, ...) vzlogx(NULL, prio, __VA_ARGS__)
+
+PRINTFRR(2, 3)
+static inline void zlog(int prio, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vzlog(prio, fmt, ap);
+ va_end(ap);
+}
+
+PRINTFRR(2, 3)
+static inline void zlog_ref(const struct xref_logmsg *xref,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vzlogx(xref, xref->priority, fmt, ap);
+ va_end(ap);
+}
+
+#define _zlog_ecref(ec_, prio, msg, ...) \
+ do { \
+ static struct xrefdata_logmsg _xrefdata = { \
+ .xrefdata = \
+ { \
+ .xref = NULL, \
+ .uid = {}, \
+ .hashstr = (msg), \
+ .hashu32 = {(prio), (ec_)}, \
+ }, \
+ }; \
+ static const struct xref_logmsg _xref __attribute__( \
+ (used)) = { \
+ .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata.xrefdata, \
+ __func__), \
+ .fmtstring = (msg), \
+ .priority = (prio), \
+ .ec = (ec_), \
+ .args = (#__VA_ARGS__), \
+ }; \
+ XREF_LINK(_xref.xref); \
+ zlog_ref(&_xref, (msg), ##__VA_ARGS__); \
+ } while (0)
+
+#define zlog_err(...) _zlog_ecref(0, LOG_ERR, __VA_ARGS__)
+#define zlog_warn(...) _zlog_ecref(0, LOG_WARNING, __VA_ARGS__)
+#define zlog_info(...) _zlog_ecref(0, LOG_INFO, __VA_ARGS__)
+#define zlog_notice(...) _zlog_ecref(0, LOG_NOTICE, __VA_ARGS__)
+#define zlog_debug(...) _zlog_ecref(0, LOG_DEBUG, __VA_ARGS__)
+
+#define flog_err(ferr_id, format, ...) \
+ _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
+#define flog_warn(ferr_id, format, ...) \
+ _zlog_ecref(ferr_id, LOG_WARNING, format, ## __VA_ARGS__)
+
+#define flog_err_sys(ferr_id, format, ...) \
+ _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
+
+extern void zlog_sigsafe(const char *text, size_t len);
+
+/* extra priority value to disable a target without deleting it */
+#define ZLOG_DISABLED (LOG_EMERG-1)
+
+/* zlog_msg encapsulates a particular logging call from somewhere in the code.
+ * The same struct is passed around to all zlog_targets.
+ *
+ * This is used to defer formatting the log message until it is actually
+ * requested by one of the targets. If none of the targets needs the message
+ * formatted, the formatting call is avoided entirely.
+ *
+ * This struct is opaque / private to the core zlog code. Logging targets
+ * should use zlog_msg_* functions to get text / timestamps / ... for a
+ * message.
+ */
+
+struct zlog_msg;
+
+extern int zlog_msg_prio(struct zlog_msg *msg);
+extern const struct xref_logmsg *zlog_msg_xref(struct zlog_msg *msg);
+
+/* text is NOT \0 terminated; instead there is a \n after textlen since the
+ * logging targets would jump extra hoops otherwise for a single byte. (the
+ * \n is not included in textlen)
+ *
+ * calling this with NULL textlen is likely wrong.
+ * use "%.*s", (int)textlen, text when passing to printf-like functions
+ */
+extern const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen);
+
+extern void zlog_msg_args(struct zlog_msg *msg, size_t *hdrlen,
+ size_t *n_argpos, const struct fmt_outpos **argpos);
+
+/* timestamp formatting control flags */
+
+/* sub-second digit count */
+#define ZLOG_TS_PREC 0xfU
+
+/* 8601: 0000-00-00T00:00:00Z (if used with ZLOG_TS_UTC)
+ * 0000-00-00T00:00:00+00:00 (otherwise)
+ * Legacy: 0000/00/00 00:00:00 (no TZ indicated!)
+ */
+#define ZLOG_TS_ISO8601 (1 << 8)
+#define ZLOG_TS_LEGACY (1 << 9)
+
+/* default is local time zone */
+#define ZLOG_TS_UTC (1 << 10)
+
+struct timespec;
+
+extern size_t zlog_msg_ts(struct zlog_msg *msg, struct fbuf *out,
+ uint32_t flags);
+extern void zlog_msg_tsraw(struct zlog_msg *msg, struct timespec *ts);
+
+/* "mmm dd hh:mm:ss" for RFC3164 syslog. Only ZLOG_TS_UTC for flags. */
+extern size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out,
+ uint32_t flags);
+
+/* currently just returns the current PID/TID since we never write another
+ * thread's messages
+ */
+extern void zlog_msg_pid(struct zlog_msg *msg, intmax_t *pid, intmax_t *tid);
+
+/* This list & struct implements the actual logging targets. It is accessed
+ * lock-free from all threads, and thus MUST only be changed atomically, i.e.
+ * RCU.
+ *
+ * Since there's no atomic replace, the replacement action is an add followed
+ * by a delete. This means that during logging config changes, log messages
+ * may be duplicated in the log target that is being changed. The old entry
+ * being changed MUST also at the very least not crash or do other stupid
+ * things.
+ *
+ * This list and struct are NOT related to config. Logging config is kept
+ * separately, and results in creating appropriate zlog_target(s) to realize
+ * the config. Log targets may also be created from varying sources, e.g.
+ * command line options, or VTY commands ("log monitor").
+ *
+ * struct zlog_target is intended to be embedded into a larger structure that
+ * contains additional field for the specific logging target, e.g. an fd or
+ * additional options. It MUST be the first field in that larger struct.
+ */
+
+PREDECL_ATOMLIST(zlog_targets);
+struct zlog_target {
+ struct zlog_targets_item head;
+
+ int prio_min;
+
+ void (*logfn)(struct zlog_target *zt, struct zlog_msg *msg[],
+ size_t nmsgs);
+
+ /* for crash handlers, set to NULL if log target can't write crash logs
+ * without possibly deadlocking (AS-Safe)
+ *
+ * text is not \0 terminated & split up into lines (e.g. no \n)
+ */
+ void (*logfn_sigsafe)(struct zlog_target *zt, const char *text,
+ size_t len);
+
+ struct rcu_head rcu_head;
+};
+
+/* make a copy for RCUpdating. oldzt may be NULL to allocate a fresh one. */
+extern struct zlog_target *zlog_target_clone(struct memtype *mt,
+ struct zlog_target *oldzt,
+ size_t size);
+
+/* update the zlog_targets list; both oldzt and newzt may be NULL. You
+ * still need to zlog_target_free() the old target afterwards if it wasn't
+ * NULL.
+ *
+ * Returns oldzt so you can zlog_target_free(zlog_target_replace(old, new));
+ * (Some log targets may need extra cleanup inbetween, but remember the old
+ * target MUST remain functional until the end of the current RCU cycle.)
+ */
+extern struct zlog_target *zlog_target_replace(struct zlog_target *oldzt,
+ struct zlog_target *newzt);
+
+/* Mostly for symmetry for zlog_target_clone(), just rcu_free() internally. */
+#define zlog_target_free(mt, zt) \
+ rcu_free(mt, zt, rcu_head)
+
+extern void zlog_init(const char *progname, const char *protoname,
+ unsigned short instance, uid_t uid, gid_t gid);
+DECLARE_HOOK(zlog_init, (const char *progname, const char *protoname,
+ unsigned short instance, uid_t uid, gid_t gid),
+ (progname, protoname, instance, uid, gid));
+
+extern void zlog_fini(void);
+DECLARE_KOOH(zlog_fini, (), ());
+
+extern void zlog_set_prefix_ec(bool enable);
+extern bool zlog_get_prefix_ec(void);
+extern void zlog_set_prefix_xid(bool enable);
+extern bool zlog_get_prefix_xid(void);
+
+/* for tools & test programs, i.e. anything not a daemon.
+ * (no cleanup needed at exit)
+ */
+extern void zlog_aux_init(const char *prefix, int prio_min);
+DECLARE_HOOK(zlog_aux_init, (const char *prefix, int prio_min),
+ (prefix, prio_min));
+
+extern void zlog_startup_end(void);
+
+extern void zlog_tls_buffer_init(void);
+extern void zlog_tls_buffer_flush(void);
+extern void zlog_tls_buffer_fini(void);
+
+/* Enable or disable 'immediate' output - default is to buffer messages. */
+extern void zlog_set_immediate(bool set_p);
+
+extern const char *zlog_priority_str(int priority);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_ZLOG_H */