Line data Source code
1 : // SPDX-License-Identifier: ISC
2 : /*
3 : * Copyright (c) 2015-19 David Lamparter, for NetDEF, Inc.
4 : */
5 :
6 : #ifndef _FRR_ZLOG_H
7 : #define _FRR_ZLOG_H
8 :
9 : #include <stdarg.h>
10 : #include <stdbool.h>
11 : #include <stdint.h>
12 : #include <string.h>
13 : #include <syslog.h>
14 : #include <unistd.h>
15 : #include <sys/uio.h>
16 :
17 : #include <assert.h>
18 :
19 : #include "atomlist.h"
20 : #include "frrcu.h"
21 : #include "memory.h"
22 : #include "hook.h"
23 : #include "printfrr.h"
24 :
25 : #ifdef __cplusplus
26 : extern "C" {
27 : #endif
28 :
29 : DECLARE_MGROUP(LOG);
30 :
31 : extern char zlog_prefix[];
32 : extern size_t zlog_prefixsz;
33 : extern int zlog_tmpdirfd;
34 : extern int zlog_instance;
35 : extern const char *zlog_progname;
36 :
37 : struct xref_logmsg {
38 : struct xref xref;
39 :
40 : const char *fmtstring;
41 : uint32_t priority;
42 : uint32_t ec;
43 : const char *args;
44 : };
45 :
46 : /* whether flag was added in config mode or enable mode */
47 : #define LOGMSG_FLAG_EPHEMERAL (1 << 0)
48 : #define LOGMSG_FLAG_PERSISTENT (1 << 1)
49 :
50 : struct xrefdata_logmsg {
51 : struct xrefdata xrefdata;
52 :
53 : uint8_t fl_print_bt;
54 : };
55 :
56 : /* These functions are set up to write to stdout/stderr without explicit
57 : * initialization and/or before config load. There is no need to call e.g.
58 : * fprintf(stderr, ...) just because it's "too early" at startup. Depending
59 : * on context, it may still be the right thing to use fprintf though -- try to
60 : * determine whether something is a log message or something else.
61 : */
62 :
63 : extern void vzlogx(const struct xref_logmsg *xref, int prio, const char *fmt,
64 : va_list ap) PRINTFRR(3, 0);
65 : #define vzlog(prio, ...) vzlogx(NULL, prio, __VA_ARGS__)
66 :
67 : PRINTFRR(2, 3)
68 0 : static inline void zlog(int prio, const char *fmt, ...)
69 : {
70 0 : va_list ap;
71 :
72 0 : va_start(ap, fmt);
73 0 : vzlog(prio, fmt, ap);
74 0 : va_end(ap);
75 0 : }
76 :
77 : PRINTFRR(2, 3)
78 690 : static inline void zlog_ref(const struct xref_logmsg *xref,
79 : const char *fmt, ...)
80 : {
81 690 : va_list ap;
82 :
83 690 : va_start(ap, fmt);
84 690 : vzlogx(xref, xref->priority, fmt, ap);
85 690 : va_end(ap);
86 690 : }
87 :
88 : #define _zlog_ecref(ec_, prio, msg, ...) \
89 : do { \
90 : static struct xrefdata_logmsg _xrefdata = { \
91 : .xrefdata = \
92 : { \
93 : .xref = NULL, \
94 : .uid = {}, \
95 : .hashstr = (msg), \
96 : .hashu32 = {(prio), (ec_)}, \
97 : }, \
98 : }; \
99 : static const struct xref_logmsg _xref __attribute__( \
100 : (used)) = { \
101 : .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata.xrefdata, \
102 : __func__), \
103 : .fmtstring = (msg), \
104 : .priority = (prio), \
105 : .ec = (ec_), \
106 : .args = (#__VA_ARGS__), \
107 : }; \
108 : XREF_LINK(_xref.xref); \
109 : zlog_ref(&_xref, (msg), ##__VA_ARGS__); \
110 : } while (0)
111 :
112 : #define zlog_err(...) _zlog_ecref(0, LOG_ERR, __VA_ARGS__)
113 : #define zlog_warn(...) _zlog_ecref(0, LOG_WARNING, __VA_ARGS__)
114 : #define zlog_info(...) _zlog_ecref(0, LOG_INFO, __VA_ARGS__)
115 : #define zlog_notice(...) _zlog_ecref(0, LOG_NOTICE, __VA_ARGS__)
116 : #define zlog_debug(...) _zlog_ecref(0, LOG_DEBUG, __VA_ARGS__)
117 :
118 : #define flog_err(ferr_id, format, ...) \
119 : _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
120 : #define flog_warn(ferr_id, format, ...) \
121 : _zlog_ecref(ferr_id, LOG_WARNING, format, ## __VA_ARGS__)
122 :
123 : #define flog_err_sys(ferr_id, format, ...) \
124 : _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
125 :
126 : extern void zlog_sigsafe(const char *text, size_t len);
127 :
128 : /* extra priority value to disable a target without deleting it */
129 : #define ZLOG_DISABLED (LOG_EMERG-1)
130 :
131 : /* zlog_msg encapsulates a particular logging call from somewhere in the code.
132 : * The same struct is passed around to all zlog_targets.
133 : *
134 : * This is used to defer formatting the log message until it is actually
135 : * requested by one of the targets. If none of the targets needs the message
136 : * formatted, the formatting call is avoided entirely.
137 : *
138 : * This struct is opaque / private to the core zlog code. Logging targets
139 : * should use zlog_msg_* functions to get text / timestamps / ... for a
140 : * message.
141 : */
142 :
143 : struct zlog_msg;
144 :
145 : extern int zlog_msg_prio(struct zlog_msg *msg);
146 : extern const struct xref_logmsg *zlog_msg_xref(struct zlog_msg *msg);
147 :
148 : /* text is NOT \0 terminated; instead there is a \n after textlen since the
149 : * logging targets would jump extra hoops otherwise for a single byte. (the
150 : * \n is not included in textlen)
151 : *
152 : * calling this with NULL textlen is likely wrong.
153 : * use "%.*s", (int)textlen, text when passing to printf-like functions
154 : */
155 : extern const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen);
156 :
157 : extern void zlog_msg_args(struct zlog_msg *msg, size_t *hdrlen,
158 : size_t *n_argpos, const struct fmt_outpos **argpos);
159 :
160 : /* timestamp formatting control flags */
161 :
162 : /* sub-second digit count */
163 : #define ZLOG_TS_PREC 0xfU
164 :
165 : /* 8601: 0000-00-00T00:00:00Z (if used with ZLOG_TS_UTC)
166 : * 0000-00-00T00:00:00+00:00 (otherwise)
167 : * Legacy: 0000/00/00 00:00:00 (no TZ indicated!)
168 : */
169 : #define ZLOG_TS_ISO8601 (1 << 8)
170 : #define ZLOG_TS_LEGACY (1 << 9)
171 :
172 : /* default is local time zone */
173 : #define ZLOG_TS_UTC (1 << 10)
174 :
175 : struct timespec;
176 :
177 : extern size_t zlog_msg_ts(struct zlog_msg *msg, struct fbuf *out,
178 : uint32_t flags);
179 : extern void zlog_msg_tsraw(struct zlog_msg *msg, struct timespec *ts);
180 :
181 : /* "mmm dd hh:mm:ss" for RFC3164 syslog. Only ZLOG_TS_UTC for flags. */
182 : extern size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out,
183 : uint32_t flags);
184 :
185 : /* currently just returns the current PID/TID since we never write another
186 : * thread's messages
187 : */
188 : extern void zlog_msg_pid(struct zlog_msg *msg, intmax_t *pid, intmax_t *tid);
189 :
190 : /* This list & struct implements the actual logging targets. It is accessed
191 : * lock-free from all threads, and thus MUST only be changed atomically, i.e.
192 : * RCU.
193 : *
194 : * Since there's no atomic replace, the replacement action is an add followed
195 : * by a delete. This means that during logging config changes, log messages
196 : * may be duplicated in the log target that is being changed. The old entry
197 : * being changed MUST also at the very least not crash or do other stupid
198 : * things.
199 : *
200 : * This list and struct are NOT related to config. Logging config is kept
201 : * separately, and results in creating appropriate zlog_target(s) to realize
202 : * the config. Log targets may also be created from varying sources, e.g.
203 : * command line options, or VTY commands ("log monitor").
204 : *
205 : * struct zlog_target is intended to be embedded into a larger structure that
206 : * contains additional field for the specific logging target, e.g. an fd or
207 : * additional options. It MUST be the first field in that larger struct.
208 : */
209 :
210 : PREDECL_ATOMLIST(zlog_targets);
211 : struct zlog_target {
212 : struct zlog_targets_item head;
213 :
214 : int prio_min;
215 :
216 : void (*logfn)(struct zlog_target *zt, struct zlog_msg *msg[],
217 : size_t nmsgs);
218 :
219 : /* for crash handlers, set to NULL if log target can't write crash logs
220 : * without possibly deadlocking (AS-Safe)
221 : *
222 : * text is not \0 terminated & split up into lines (e.g. no \n)
223 : */
224 : void (*logfn_sigsafe)(struct zlog_target *zt, const char *text,
225 : size_t len);
226 :
227 : struct rcu_head rcu_head;
228 : };
229 :
230 : /* make a copy for RCUpdating. oldzt may be NULL to allocate a fresh one. */
231 : extern struct zlog_target *zlog_target_clone(struct memtype *mt,
232 : struct zlog_target *oldzt,
233 : size_t size);
234 :
235 : /* update the zlog_targets list; both oldzt and newzt may be NULL. You
236 : * still need to zlog_target_free() the old target afterwards if it wasn't
237 : * NULL.
238 : *
239 : * Returns oldzt so you can zlog_target_free(zlog_target_replace(old, new));
240 : * (Some log targets may need extra cleanup inbetween, but remember the old
241 : * target MUST remain functional until the end of the current RCU cycle.)
242 : */
243 : extern struct zlog_target *zlog_target_replace(struct zlog_target *oldzt,
244 : struct zlog_target *newzt);
245 :
246 : /* Mostly for symmetry for zlog_target_clone(), just rcu_free() internally. */
247 : #define zlog_target_free(mt, zt) \
248 : rcu_free(mt, zt, rcu_head)
249 :
250 : extern void zlog_init(const char *progname, const char *protoname,
251 : unsigned short instance, uid_t uid, gid_t gid);
252 : DECLARE_HOOK(zlog_init, (const char *progname, const char *protoname,
253 : unsigned short instance, uid_t uid, gid_t gid),
254 : (progname, protoname, instance, uid, gid));
255 :
256 : extern void zlog_fini(void);
257 : DECLARE_KOOH(zlog_fini, (), ());
258 :
259 : extern void zlog_set_prefix_ec(bool enable);
260 : extern bool zlog_get_prefix_ec(void);
261 : extern void zlog_set_prefix_xid(bool enable);
262 : extern bool zlog_get_prefix_xid(void);
263 :
264 : /* for tools & test programs, i.e. anything not a daemon.
265 : * (no cleanup needed at exit)
266 : */
267 : extern void zlog_aux_init(const char *prefix, int prio_min);
268 : DECLARE_HOOK(zlog_aux_init, (const char *prefix, int prio_min),
269 : (prefix, prio_min));
270 :
271 : extern void zlog_startup_end(void);
272 :
273 : extern void zlog_tls_buffer_init(void);
274 : extern void zlog_tls_buffer_flush(void);
275 : extern void zlog_tls_buffer_fini(void);
276 :
277 : /* Enable or disable 'immediate' output - default is to buffer messages. */
278 : extern void zlog_set_immediate(bool set_p);
279 :
280 : extern const char *zlog_priority_str(int priority);
281 :
282 : #ifdef __cplusplus
283 : }
284 : #endif
285 :
286 : #endif /* _FRR_ZLOG_H */
|