2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
8 * This software was developed by Pawel Jakub Dawidek under sponsorship from
9 * the FreeBSD Foundation.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
54 #define PJDLOG_NEVER_INITIALIZED 0
55 #define PJDLOG_NOT_INITIALIZED 1
56 #define PJDLOG_INITIALIZED 2
58 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
59 static int pjdlog_mode, pjdlog_debug_level;
60 static char pjdlog_prefix[128];
63 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
68 argt[0] = PA_INT | PA_FLAG_INTMAX;
73 pjdlog_printf_render_humanized_number(struct __printf_io *io,
74 const struct printf_info *pi, const void * const *arg)
80 num = *(const intmax_t *)arg[0];
81 humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
82 HN_NOSPACE | HN_DECIMAL);
83 ret = __printf_out(io, pi, buf, strlen(buf));
89 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
99 pjdlog_printf_render_sockaddr(struct __printf_io *io,
100 const struct printf_info *pi, const void * const *arg)
102 const struct sockaddr_storage *ss;
106 ss = *(const struct sockaddr_storage * const *)arg[0];
107 switch (ss->ss_family) {
110 char addr[INET_ADDRSTRLEN];
111 const struct sockaddr_in *sin;
114 sin = (const struct sockaddr_in *)ss;
115 port = ntohs(sin->sin_port);
116 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
117 sizeof(addr)) == NULL) {
118 PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
121 snprintf(buf, sizeof(buf), "%s:%u", addr, port);
126 char addr[INET6_ADDRSTRLEN];
127 const struct sockaddr_in6 *sin;
130 sin = (const struct sockaddr_in6 *)ss;
131 port = ntohs(sin->sin6_port);
132 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
133 sizeof(addr)) == NULL) {
134 PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
137 snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
141 snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
145 ret = __printf_out(io, pi, buf, strlen(buf));
151 pjdlog_init(int mode)
155 assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
156 pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
157 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
161 if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
163 register_printf_render_std("T");
164 register_printf_render('N',
165 pjdlog_printf_render_humanized_number,
166 pjdlog_printf_arginfo_humanized_number);
167 register_printf_render('S',
168 pjdlog_printf_render_sockaddr,
169 pjdlog_printf_arginfo_sockaddr);
172 if (mode == PJDLOG_MODE_SYSLOG)
173 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
175 pjdlog_debug_level = 0;
176 bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
178 pjdlog_initialized = PJDLOG_INITIALIZED;
188 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
192 if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
195 pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
201 * Configure where the logs should go.
202 * By default they are send to stdout/stderr, but after going into background
203 * (eg. by calling daemon(3)) application is responsible for changing mode to
204 * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
207 pjdlog_mode_set(int mode)
211 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
212 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
214 if (pjdlog_mode == mode)
219 if (mode == PJDLOG_MODE_SYSLOG)
220 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
221 else /* if (mode == PJDLOG_MODE_STD) */
230 * Return current mode.
233 pjdlog_mode_get(void)
236 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
238 return (pjdlog_mode);
242 * Set debug level. All the logs above the level specified here will be
246 pjdlog_debug_set(int level)
249 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
252 pjdlog_debug_level = level;
256 * Return current debug level.
259 pjdlog_debug_get(void)
262 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
264 return (pjdlog_debug_level);
268 * Set prefix that will be used before each log.
269 * Setting prefix to NULL will remove it.
272 pjdlog_prefix_set(const char *fmt, ...)
276 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
279 pjdlogv_prefix_set(fmt, ap);
284 * Set prefix that will be used before each log.
285 * Setting prefix to NULL will remove it.
288 pjdlogv_prefix_set(const char *fmt, va_list ap)
292 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
297 vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
303 * Convert log level into string.
306 pjdlog_level_string(int loglevel)
327 assert(!"Invalid log level.");
328 abort(); /* XXX: gcc */
332 * Common log routine.
335 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
339 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
342 pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
347 * Common log routine, which can handle regular log level as well as debug
348 * level. We decide here where to send the logs (stdout/stderr or syslog).
351 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
356 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
357 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
358 loglevel == LOG_CRIT || loglevel == LOG_ERR ||
359 loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
360 loglevel == LOG_INFO || loglevel == LOG_DEBUG);
361 assert(loglevel != LOG_DEBUG || debuglevel > 0);
364 /* Ignore debug above configured level. */
365 if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
370 switch (pjdlog_mode) {
371 case PJDLOG_MODE_STD:
376 * We send errors and warning to stderr and the rest to stdout.
392 assert(!"Invalid loglevel.");
393 abort(); /* XXX: gcc */
396 fprintf(out, "[%s]", pjdlog_level_string(loglevel));
397 /* Attach debuglevel if this is debug log. */
398 if (loglevel == LOG_DEBUG)
399 fprintf(out, "[%d]", debuglevel);
400 fprintf(out, " %s", pjdlog_prefix);
401 vfprintf(out, fmt, ap);
403 fprintf(out, ": %s.", strerror(error));
408 case PJDLOG_MODE_SYSLOG:
413 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
414 if ((size_t)len < sizeof(log))
415 len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
416 if (error != -1 && (size_t)len < sizeof(log)) {
417 (void)snprintf(log + len, sizeof(log) - len, ": %s.",
420 syslog(loglevel, "%s", log);
424 assert(!"Invalid mode.");
434 pjdlogv(int loglevel, const char *fmt, va_list ap)
437 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
439 /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
440 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
441 loglevel == LOG_CRIT || loglevel == LOG_ERR ||
442 loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
443 loglevel == LOG_INFO);
445 pjdlogv_common(loglevel, 0, -1, fmt, ap);
452 pjdlog(int loglevel, const char *fmt, ...)
456 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
459 pjdlogv(loglevel, fmt, ap);
467 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
470 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
472 pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
479 pjdlog_debug(int debuglevel, const char *fmt, ...)
483 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
486 pjdlogv_debug(debuglevel, fmt, ap);
491 * Error logs with errno logging.
494 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
497 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
499 pjdlogv_common(loglevel, 0, errno, fmt, ap);
503 * Error logs with errno logging.
506 pjdlog_errno(int loglevel, const char *fmt, ...)
510 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
513 pjdlogv_errno(loglevel, fmt, ap);
518 * Log error, errno and exit.
521 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
524 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
526 pjdlogv_errno(LOG_ERR, fmt, ap);
532 * Log error, errno and exit.
535 pjdlog_exit(int exitcode, const char *fmt, ...)
539 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
542 pjdlogv_exit(exitcode, fmt, ap);
548 * Log error and exit.
551 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
554 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
556 pjdlogv(LOG_ERR, fmt, ap);
562 * Log error and exit.
565 pjdlog_exitx(int exitcode, const char *fmt, ...)
569 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
572 pjdlogv_exitx(exitcode, fmt, ap);
578 * Log failure message and exit.
581 pjdlog_abort(const char *func, const char *file, int line,
582 const char *failedexpr, const char *fmt, ...)
586 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
589 * When there is no message we pass __func__ as 'fmt'.
590 * It would be cleaner to pass NULL or "", but gcc generates a warning
595 pjdlogv_critical(fmt, ap);
598 if (failedexpr == NULL) {
600 pjdlog_critical("Aborted at file %s, line %d.", file,
603 pjdlog_critical("Aborted at function %s, file %s, line %d.",
608 pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
609 failedexpr, file, line);
611 pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
612 failedexpr, func, file, line);