xref: /freebsd/sbin/hastd/pjdlog.c (revision 70ed590b393173d4ea697be2a27054ed171f0c1a)
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <assert.h>
36 #include <errno.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <syslog.h>
42 
43 #include "pjdlog.h"
44 
45 static int pjdlog_mode = PJDLOG_MODE_STD;
46 static int pjdlog_debug_level = 0;
47 static char pjdlog_prefix[128];
48 
49 /*
50  * Configure where the logs should go.
51  * By default they are send to stdout/stderr, but after going into background
52  * (eg. by calling daemon(3)) application is responsible for changing mode to
53  * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
54  */
55 void
56 pjdlog_mode_set(int mode)
57 {
58 
59 	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
60 
61 	pjdlog_mode = mode;
62 }
63 
64 /*
65  * Return current mode.
66  */
67 int
68 pjdlog_mode_get(void)
69 {
70 
71 	return (pjdlog_mode);
72 }
73 
74 /*
75  * Set debug level. All the logs above the level specified here will be
76  * ignored.
77  */
78 void
79 pjdlog_debug_set(int level)
80 {
81 
82 	assert(level >= 0);
83 
84 	pjdlog_debug_level = level;
85 }
86 
87 /*
88  * Return current debug level.
89  */
90 int
91 pjdlog_debug_get(void)
92 {
93 
94 	return (pjdlog_debug_level);
95 }
96 
97 /*
98  * Set prefix that will be used before each log.
99  * Setting prefix to NULL will remove it.
100  */
101 void
102 pjdlog_prefix_set(const char *fmt, ...)
103 {
104 	va_list ap;
105 
106 	va_start(ap, fmt);
107 	pjdlog_prefix_setv(fmt, ap);
108 	va_end(ap);
109 }
110 
111 /*
112  * Set prefix that will be used before each log.
113  * Setting prefix to NULL will remove it.
114  */
115 void
116 pjdlog_prefix_setv(const char *fmt, va_list ap)
117 {
118 
119 	assert(fmt != NULL);
120 
121 	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
122 }
123 
124 /*
125  * Convert log level into string.
126  */
127 static const char *
128 pjdlog_level_string(int loglevel)
129 {
130 
131 	switch (loglevel) {
132 	case LOG_EMERG:
133 		return ("EMERG");
134 	case LOG_ALERT:
135 		return ("ALERT");
136 	case LOG_CRIT:
137 		return ("CRIT");
138 	case LOG_ERR:
139 		return ("ERROR");
140 	case LOG_WARNING:
141 		return ("WARNING");
142 	case LOG_NOTICE:
143 		return ("NOTICE");
144 	case LOG_INFO:
145 		return ("INFO");
146 	case LOG_DEBUG:
147 		return ("DEBUG");
148 	}
149 	assert(!"Invalid log level.");
150 	abort();	/* XXX: gcc */
151 }
152 
153 /*
154  * Common log routine.
155  */
156 void
157 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
158 {
159 	va_list ap;
160 
161 	va_start(ap, fmt);
162 	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
163 	va_end(ap);
164 }
165 
166 /*
167  * Common log routine, which can handle regular log level as well as debug
168  * level. We decide here where to send the logs (stdout/stderr or syslog).
169  */
170 void
171 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
172     va_list ap)
173 {
174 
175 	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
176 	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
177 	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
178 	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
179 	assert(loglevel != LOG_DEBUG || debuglevel > 0);
180 	assert(error >= -1);
181 
182 	/* Ignore debug above configured level. */
183 	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
184 		return;
185 
186 	switch (pjdlog_mode) {
187 	case PJDLOG_MODE_STD:
188 	    {
189 		FILE *out;
190 
191 		/*
192 		 * We send errors and warning to stderr and the rest to stdout.
193 		 */
194 		switch (loglevel) {
195 		case LOG_EMERG:
196 		case LOG_ALERT:
197 		case LOG_CRIT:
198 		case LOG_ERR:
199 		case LOG_WARNING:
200 			out = stderr;
201 			break;
202 		case LOG_NOTICE:
203 		case LOG_INFO:
204 		case LOG_DEBUG:
205 			out = stdout;
206 			break;
207 		default:
208 			assert(!"Invalid loglevel.");
209 			abort();	/* XXX: gcc */
210 		}
211 
212 		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
213 		/* Attach debuglevel if this is debug log. */
214 		if (loglevel == LOG_DEBUG)
215 			fprintf(out, "[%d]", debuglevel);
216 		fprintf(out, " ");
217 		fprintf(out, "%s", pjdlog_prefix);
218 		vfprintf(out, fmt, ap);
219 		if (error != -1)
220 			fprintf(out, ": %s.", strerror(error));
221 		fprintf(out, "\n");
222 		break;
223 	    }
224 	case PJDLOG_MODE_SYSLOG:
225 	    {
226 		char log[1024];
227 		int len;
228 
229 		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
230 		if ((size_t)len < sizeof(log))
231 			len = vsnprintf(log + len, sizeof(log) - len, fmt, ap);
232 		if (error != -1 && (size_t)len < sizeof(log)) {
233 			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
234 			    strerror(error));
235 		}
236 		syslog(loglevel, "%s", log);
237 		break;
238 	    }
239 	default:
240 		assert(!"Invalid mode.");
241 	}
242 }
243 
244 /*
245  * Regular logs.
246  */
247 void
248 pjdlogv(int loglevel, const char *fmt, va_list ap)
249 {
250 
251 	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
252 	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
253 	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
254 	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
255 	    loglevel == LOG_INFO);
256 
257 	pjdlogv_common(loglevel, 0, -1, fmt, ap);
258 }
259 
260 /*
261  * Regular logs.
262  */
263 void
264 pjdlog(int loglevel, const char *fmt, ...)
265 {
266 	va_list ap;
267 
268 	va_start(ap, fmt);
269 	pjdlogv(loglevel, fmt, ap);
270 	va_end(ap);
271 }
272 
273 /*
274  * Debug logs.
275  */
276 void
277 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
278 {
279 
280 	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
281 }
282 
283 /*
284  * Debug logs.
285  */
286 void
287 pjdlog_debug(int debuglevel, const char *fmt, ...)
288 {
289 	va_list ap;
290 
291 	va_start(ap, fmt);
292 	pjdlogv_debug(debuglevel, fmt, ap);
293 	va_end(ap);
294 }
295 
296 /*
297  * Error logs with errno logging.
298  */
299 void
300 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
301 {
302 
303 	pjdlogv_common(loglevel, 0, errno, fmt, ap);
304 }
305 
306 /*
307  * Error logs with errno logging.
308  */
309 void
310 pjdlog_errno(int loglevel, const char *fmt, ...)
311 {
312 	va_list ap;
313 
314 	va_start(ap, fmt);
315 	pjdlogv_errno(loglevel, fmt, ap);
316 	va_end(ap);
317 }
318 
319 /*
320  * Log error, errno and exit.
321  */
322 void
323 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
324 {
325 
326 	pjdlogv_errno(LOG_ERR, fmt, ap);
327 	exit(exitcode);
328 }
329 
330 /*
331  * Log error, errno and exit.
332  */
333 void
334 pjdlog_exit(int exitcode, const char *fmt, ...)
335 {
336 	va_list ap;
337 
338 	va_start(ap, fmt);
339 	pjdlogv_exit(exitcode, fmt, ap);
340 	/* NOTREACHED */
341 	va_end(ap);
342 }
343 
344 /*
345  * Log error and exit.
346  */
347 void
348 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
349 {
350 
351 	pjdlogv(LOG_ERR, fmt, ap);
352 	exit(exitcode);
353 }
354 
355 /*
356  * Log error and exit.
357  */
358 void
359 pjdlog_exitx(int exitcode, const char *fmt, ...)
360 {
361 	va_list ap;
362 
363 	va_start(ap, fmt);
364 	pjdlogv_exitx(exitcode, fmt, ap);
365 	/* NOTREACHED */
366 	va_end(ap);
367 }
368