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