pjdlog.c revision 210872
1204076Spjd/*-
2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation
3204076Spjd * All rights reserved.
4204076Spjd *
5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
6204076Spjd * the FreeBSD Foundation.
7204076Spjd *
8204076Spjd * Redistribution and use in source and binary forms, with or without
9204076Spjd * modification, are permitted provided that the following conditions
10204076Spjd * are met:
11204076Spjd * 1. Redistributions of source code must retain the above copyright
12204076Spjd *    notice, this list of conditions and the following disclaimer.
13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
14204076Spjd *    notice, this list of conditions and the following disclaimer in the
15204076Spjd *    documentation and/or other materials provided with the distribution.
16204076Spjd *
17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27204076Spjd * SUCH DAMAGE.
28204076Spjd *
29204076Spjd * $FreeBSD: head/sbin/hastd/pjdlog.c 210872 2010-08-05 18:21:45Z pjd $
30204076Spjd */
31204076Spjd
32204076Spjd#include <sys/cdefs.h>
33204076Spjd__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 210872 2010-08-05 18:21:45Z pjd $");
34204076Spjd
35204076Spjd#include <assert.h>
36204076Spjd#include <errno.h>
37204076Spjd#include <stdarg.h>
38204076Spjd#include <stdio.h>
39204076Spjd#include <stdlib.h>
40204076Spjd#include <string.h>
41204076Spjd#include <syslog.h>
42204076Spjd
43204076Spjd#include "pjdlog.h"
44204076Spjd
45204076Spjdstatic int pjdlog_mode = PJDLOG_MODE_STD;
46204076Spjdstatic int pjdlog_debug_level = 0;
47204076Spjdstatic char pjdlog_prefix[128];
48204076Spjd
49204076Spjd/*
50204076Spjd * Configure where the logs should go.
51204076Spjd * By default they are send to stdout/stderr, but after going into background
52204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to
53204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
54204076Spjd */
55204076Spjdvoid
56204076Spjdpjdlog_mode_set(int mode)
57204076Spjd{
58204076Spjd
59204076Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
60204076Spjd
61204076Spjd	pjdlog_mode = mode;
62204076Spjd}
63204076Spjd
64204076Spjd/*
65204076Spjd * Return current mode.
66204076Spjd */
67204076Spjdint
68204076Spjdpjdlog_mode_get(void)
69204076Spjd{
70204076Spjd
71204076Spjd	return (pjdlog_mode);
72204076Spjd}
73204076Spjd
74204076Spjd/*
75204076Spjd * Set debug level. All the logs above the level specified here will be
76204076Spjd * ignored.
77204076Spjd */
78204076Spjdvoid
79204076Spjdpjdlog_debug_set(int level)
80204076Spjd{
81204076Spjd
82204076Spjd	assert(level >= 0);
83204076Spjd
84204076Spjd	pjdlog_debug_level = level;
85204076Spjd}
86204076Spjd
87204076Spjd/*
88204076Spjd * Return current debug level.
89204076Spjd */
90204076Spjdint
91204076Spjdpjdlog_debug_get(void)
92204076Spjd{
93204076Spjd
94204076Spjd	return (pjdlog_debug_level);
95204076Spjd}
96204076Spjd
97204076Spjd/*
98204076Spjd * Set prefix that will be used before each log.
99204076Spjd * Setting prefix to NULL will remove it.
100204076Spjd */
101204076Spjdvoid
102204076Spjdpjdlog_prefix_set(const char *fmt, ...)
103204076Spjd{
104204076Spjd	va_list ap;
105204076Spjd
106204076Spjd	va_start(ap, fmt);
107204076Spjd	pjdlog_prefix_setv(fmt, ap);
108204076Spjd	va_end(ap);
109204076Spjd}
110204076Spjd
111204076Spjd/*
112204076Spjd * Set prefix that will be used before each log.
113204076Spjd * Setting prefix to NULL will remove it.
114204076Spjd */
115204076Spjdvoid
116204076Spjdpjdlog_prefix_setv(const char *fmt, va_list ap)
117204076Spjd{
118204076Spjd
119204076Spjd	assert(fmt != NULL);
120204076Spjd
121204076Spjd	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
122204076Spjd}
123204076Spjd
124204076Spjd/*
125204076Spjd * Convert log level into string.
126204076Spjd */
127204076Spjdstatic const char *
128204076Spjdpjdlog_level_string(int loglevel)
129204076Spjd{
130204076Spjd
131204076Spjd	switch (loglevel) {
132204076Spjd	case LOG_EMERG:
133204076Spjd		return ("EMERG");
134204076Spjd	case LOG_ALERT:
135204076Spjd		return ("ALERT");
136204076Spjd	case LOG_CRIT:
137204076Spjd		return ("CRIT");
138204076Spjd	case LOG_ERR:
139204076Spjd		return ("ERROR");
140204076Spjd	case LOG_WARNING:
141204076Spjd		return ("WARNING");
142204076Spjd	case LOG_NOTICE:
143204076Spjd		return ("NOTICE");
144204076Spjd	case LOG_INFO:
145204076Spjd		return ("INFO");
146204076Spjd	case LOG_DEBUG:
147204076Spjd		return ("DEBUG");
148204076Spjd	}
149204076Spjd	assert(!"Invalid log level.");
150204076Spjd	abort();	/* XXX: gcc */
151204076Spjd}
152204076Spjd
153204076Spjd/*
154204076Spjd * Common log routine.
155204076Spjd */
156204076Spjdvoid
157204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
158204076Spjd{
159204076Spjd	va_list ap;
160204076Spjd
161204076Spjd	va_start(ap, fmt);
162204076Spjd	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
163204076Spjd	va_end(ap);
164204076Spjd}
165204076Spjd
166204076Spjd/*
167204076Spjd * Common log routine, which can handle regular log level as well as debug
168204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog).
169204076Spjd */
170204076Spjdvoid
171204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
172204076Spjd    va_list ap)
173204076Spjd{
174204076Spjd
175204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
176204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
177204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
178204076Spjd	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
179204076Spjd	assert(loglevel != LOG_DEBUG || debuglevel > 0);
180204076Spjd	assert(error >= -1);
181204076Spjd
182204076Spjd	/* Ignore debug above configured level. */
183204076Spjd	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
184204076Spjd		return;
185204076Spjd
186204076Spjd	switch (pjdlog_mode) {
187204076Spjd	case PJDLOG_MODE_STD:
188204076Spjd	    {
189204076Spjd		FILE *out;
190204076Spjd
191204076Spjd		/*
192204076Spjd		 * We send errors and warning to stderr and the rest to stdout.
193204076Spjd		 */
194204076Spjd		switch (loglevel) {
195204076Spjd		case LOG_EMERG:
196204076Spjd		case LOG_ALERT:
197204076Spjd		case LOG_CRIT:
198204076Spjd		case LOG_ERR:
199204076Spjd		case LOG_WARNING:
200204076Spjd			out = stderr;
201204076Spjd			break;
202204076Spjd		case LOG_NOTICE:
203204076Spjd		case LOG_INFO:
204204076Spjd		case LOG_DEBUG:
205204076Spjd			out = stdout;
206204076Spjd			break;
207204076Spjd		default:
208204076Spjd			assert(!"Invalid loglevel.");
209204076Spjd			abort();	/* XXX: gcc */
210204076Spjd		}
211204076Spjd
212204076Spjd		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
213204076Spjd		/* Attach debuglevel if this is debug log. */
214204076Spjd		if (loglevel == LOG_DEBUG)
215204076Spjd			fprintf(out, "[%d]", debuglevel);
216204076Spjd		fprintf(out, " ");
217204076Spjd		fprintf(out, "%s", pjdlog_prefix);
218204076Spjd		vfprintf(out, fmt, ap);
219204076Spjd		if (error != -1)
220204076Spjd			fprintf(out, ": %s.", strerror(error));
221204076Spjd		fprintf(out, "\n");
222204076Spjd		break;
223204076Spjd	    }
224204076Spjd	case PJDLOG_MODE_SYSLOG:
225204076Spjd	    {
226204076Spjd		char log[1024];
227204076Spjd		int len;
228204076Spjd
229204076Spjd		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
230204076Spjd		if ((size_t)len < sizeof(log))
231206697Spjd			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
232204076Spjd		if (error != -1 && (size_t)len < sizeof(log)) {
233204076Spjd			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
234204076Spjd			    strerror(error));
235204076Spjd		}
236204076Spjd		syslog(loglevel, "%s", log);
237204076Spjd		break;
238204076Spjd	    }
239204076Spjd	default:
240204076Spjd		assert(!"Invalid mode.");
241204076Spjd	}
242204076Spjd}
243204076Spjd
244204076Spjd/*
245204076Spjd * Regular logs.
246204076Spjd */
247204076Spjdvoid
248204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap)
249204076Spjd{
250204076Spjd
251204076Spjd	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
252204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
253204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
254204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
255204076Spjd	    loglevel == LOG_INFO);
256204076Spjd
257204076Spjd	pjdlogv_common(loglevel, 0, -1, fmt, ap);
258204076Spjd}
259204076Spjd
260204076Spjd/*
261204076Spjd * Regular logs.
262204076Spjd */
263204076Spjdvoid
264204076Spjdpjdlog(int loglevel, const char *fmt, ...)
265204076Spjd{
266204076Spjd	va_list ap;
267204076Spjd
268204076Spjd	va_start(ap, fmt);
269204076Spjd	pjdlogv(loglevel, fmt, ap);
270204076Spjd	va_end(ap);
271204076Spjd}
272204076Spjd
273204076Spjd/*
274204076Spjd * Debug logs.
275204076Spjd */
276204076Spjdvoid
277204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
278204076Spjd{
279204076Spjd
280204076Spjd	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
281204076Spjd}
282204076Spjd
283204076Spjd/*
284204076Spjd * Debug logs.
285204076Spjd */
286204076Spjdvoid
287204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...)
288204076Spjd{
289204076Spjd	va_list ap;
290204076Spjd
291204076Spjd	va_start(ap, fmt);
292204076Spjd	pjdlogv_debug(debuglevel, fmt, ap);
293204076Spjd	va_end(ap);
294204076Spjd}
295204076Spjd
296204076Spjd/*
297204076Spjd * Error logs with errno logging.
298204076Spjd */
299204076Spjdvoid
300204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap)
301204076Spjd{
302204076Spjd
303204076Spjd	pjdlogv_common(loglevel, 0, errno, fmt, ap);
304204076Spjd}
305204076Spjd
306204076Spjd/*
307204076Spjd * Error logs with errno logging.
308204076Spjd */
309204076Spjdvoid
310204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...)
311204076Spjd{
312204076Spjd	va_list ap;
313204076Spjd
314204076Spjd	va_start(ap, fmt);
315204076Spjd	pjdlogv_errno(loglevel, fmt, ap);
316204076Spjd	va_end(ap);
317204076Spjd}
318204076Spjd
319204076Spjd/*
320204076Spjd * Log error, errno and exit.
321204076Spjd */
322204076Spjdvoid
323204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap)
324204076Spjd{
325204076Spjd
326204076Spjd	pjdlogv_errno(LOG_ERR, fmt, ap);
327204076Spjd	exit(exitcode);
328210872Spjd	/* NOTREACHED */
329204076Spjd}
330204076Spjd
331204076Spjd/*
332204076Spjd * Log error, errno and exit.
333204076Spjd */
334204076Spjdvoid
335204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...)
336204076Spjd{
337204076Spjd	va_list ap;
338204076Spjd
339204076Spjd	va_start(ap, fmt);
340204076Spjd	pjdlogv_exit(exitcode, fmt, ap);
341204076Spjd	/* NOTREACHED */
342204076Spjd	va_end(ap);
343204076Spjd}
344204076Spjd
345204076Spjd/*
346204076Spjd * Log error and exit.
347204076Spjd */
348204076Spjdvoid
349204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
350204076Spjd{
351204076Spjd
352204076Spjd	pjdlogv(LOG_ERR, fmt, ap);
353204076Spjd	exit(exitcode);
354210872Spjd	/* NOTREACHED */
355204076Spjd}
356204076Spjd
357204076Spjd/*
358204076Spjd * Log error and exit.
359204076Spjd */
360204076Spjdvoid
361204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...)
362204076Spjd{
363204076Spjd	va_list ap;
364204076Spjd
365204076Spjd	va_start(ap, fmt);
366204076Spjd	pjdlogv_exitx(exitcode, fmt, ap);
367204076Spjd	/* NOTREACHED */
368204076Spjd	va_end(ap);
369204076Spjd}
370