pjdlog.c revision 206697
1165023Sgrog/*-
2165023Sgrog * Copyright (c) 2009-2010 The FreeBSD Foundation
3165023Sgrog * All rights reserved.
4165023Sgrog *
5165023Sgrog * This software was developed by Pawel Jakub Dawidek under sponsorship from
6165023Sgrog * the FreeBSD Foundation.
7165023Sgrog *
8165023Sgrog * Redistribution and use in source and binary forms, with or without
9165023Sgrog * modification, are permitted provided that the following conditions
10165023Sgrog * are met:
11165023Sgrog * 1. Redistributions of source code must retain the above copyright
12165023Sgrog *    notice, this list of conditions and the following disclaimer.
13165023Sgrog * 2. Redistributions in binary form must reproduce the above copyright
14165025Sgrog *    notice, this list of conditions and the following disclaimer in the
15165025Sgrog *    documentation and/or other materials provided with the distribution.
16165025Sgrog *
17165025Sgrog * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18165025Sgrog * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19165025Sgrog * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20165025Sgrog * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21165025Sgrog * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22165025Sgrog * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23165025Sgrog * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24165025Sgrog * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25165023Sgrog * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26165023Sgrog * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27165023Sgrog * SUCH DAMAGE.
28165023Sgrog *
29165026Sgrog * $FreeBSD: head/sbin/hastd/pjdlog.c 206697 2010-04-16 06:49:12Z pjd $
30165023Sgrog */
31165023Sgrog
32165023Sgrog#include <sys/cdefs.h>
33165023Sgrog__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 206697 2010-04-16 06:49:12Z pjd $");
34165023Sgrog
35165023Sgrog#include <assert.h>
36165023Sgrog#include <errno.h>
37165023Sgrog#include <stdarg.h>
38165023Sgrog#include <stdio.h>
39165023Sgrog#include <stdlib.h>
40165023Sgrog#include <string.h>
41165023Sgrog#include <syslog.h>
42165023Sgrog
43165023Sgrog#include "pjdlog.h"
44165023Sgrog
45165023Sgrogstatic int pjdlog_mode = PJDLOG_MODE_STD;
46165023Sgrogstatic int pjdlog_debug_level = 0;
47165023Sgrogstatic char pjdlog_prefix[128];
48165023Sgrog
49165023Sgrog/*
50165023Sgrog * Configure where the logs should go.
51165023Sgrog * By default they are send to stdout/stderr, but after going into background
52165023Sgrog * (eg. by calling daemon(3)) application is responsible for changing mode to
53165026Sgrog * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
54165026Sgrog */
55165026Sgrogvoid
56165026Sgrogpjdlog_mode_set(int mode)
57166959Sgrog{
58166959Sgrog
59166959Sgrog	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
60166959Sgrog
61166959Sgrog	pjdlog_mode = mode;
62166959Sgrog}
63165026Sgrog
64165026Sgrog/*
65165026Sgrog * Return current mode.
66165026Sgrog */
67165026Sgrogint
68165026Sgrogpjdlog_mode_get(void)
69165026Sgrog{
70165026Sgrog
71165026Sgrog	return (pjdlog_mode);
72165026Sgrog}
73165026Sgrog
74166959Sgrog/*
75166959Sgrog * Set debug level. All the logs above the level specified here will be
76165026Sgrog * ignored.
77165026Sgrog */
78165026Sgrogvoid
79165023Sgrogpjdlog_debug_set(int level)
80165023Sgrog{
81165026Sgrog
82165026Sgrog	assert(level >= 0);
83165023Sgrog
84165026Sgrog	pjdlog_debug_level = level;
85165026Sgrog}
86165026Sgrog
87165026Sgrog/*
88165026Sgrog * Return current debug level.
89165026Sgrog */
90165026Sgrogint
91165026Sgrogpjdlog_debug_get(void)
92165026Sgrog{
93165026Sgrog
94165026Sgrog	return (pjdlog_debug_level);
95165026Sgrog}
96165026Sgrog
97165026Sgrog/*
98165026Sgrog * Set prefix that will be used before each log.
99165026Sgrog * Setting prefix to NULL will remove it.
100165023Sgrog */
101165026Sgrogvoid
102165026Sgrogpjdlog_prefix_set(const char *fmt, ...)
103165026Sgrog{
104165026Sgrog	va_list ap;
105165026Sgrog
106165026Sgrog	va_start(ap, fmt);
107165026Sgrog	pjdlog_prefix_setv(fmt, ap);
108165026Sgrog	va_end(ap);
109165026Sgrog}
110165023Sgrog
111166959Sgrog/*
112165026Sgrog * Set prefix that will be used before each log.
113165026Sgrog * Setting prefix to NULL will remove it.
114165026Sgrog */
115165026Sgrogvoid
116165026Sgrogpjdlog_prefix_setv(const char *fmt, va_list ap)
117165026Sgrog{
118165026Sgrog
119165026Sgrog	assert(fmt != NULL);
120165026Sgrog
121165026Sgrog	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
122165026Sgrog}
123165023Sgrog
124165026Sgrog/*
125165026Sgrog * Convert log level into string.
126165026Sgrog */
127165026Sgrogstatic const char *
128165023Sgrogpjdlog_level_string(int loglevel)
129165026Sgrog{
130165026Sgrog
131165026Sgrog	switch (loglevel) {
132165026Sgrog	case LOG_EMERG:
133165023Sgrog		return ("EMERG");
134165026Sgrog	case LOG_ALERT:
135165026Sgrog		return ("ALERT");
136165026Sgrog	case LOG_CRIT:
137165026Sgrog		return ("CRIT");
138165023Sgrog	case LOG_ERR:
139165026Sgrog		return ("ERROR");
140165026Sgrog	case LOG_WARNING:
141165026Sgrog		return ("WARNING");
142165026Sgrog	case LOG_NOTICE:
143165023Sgrog		return ("NOTICE");
144165026Sgrog	case LOG_INFO:
145165026Sgrog		return ("INFO");
146165026Sgrog	case LOG_DEBUG:
147165026Sgrog		return ("DEBUG");
148165026Sgrog	}
149165026Sgrog	assert(!"Invalid log level.");
150165026Sgrog	abort();	/* XXX: gcc */
151165023Sgrog}
152165026Sgrog
153165026Sgrog/*
154165026Sgrog * Common log routine.
155165026Sgrog */
156165026Sgrogvoid
157165026Sgrogpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
158165026Sgrog{
159165023Sgrog	va_list ap;
160165026Sgrog
161165026Sgrog	va_start(ap, fmt);
162165026Sgrog	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
163165026Sgrog	va_end(ap);
164165023Sgrog}
165165026Sgrog
166165023Sgrog/*
167165026Sgrog * Common log routine, which can handle regular log level as well as debug
168165026Sgrog * level. We decide here where to send the logs (stdout/stderr or syslog).
169165026Sgrog */
170165023Sgrogvoid
171165026Sgrogpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
172165026Sgrog    va_list ap)
173165026Sgrog{
174165026Sgrog
175165026Sgrog	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
176165026Sgrog	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
177165023Sgrog	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
178165026Sgrog	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
179165023Sgrog	assert(loglevel != LOG_DEBUG || debuglevel > 0);
180165026Sgrog	assert(error >= -1);
181165026Sgrog
182165026Sgrog	/* Ignore debug above configured level. */
183165026Sgrog	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
184165026Sgrog		return;
185165023Sgrog
186165026Sgrog	switch (pjdlog_mode) {
187165026Sgrog	case PJDLOG_MODE_STD:
188165026Sgrog	    {
189165026Sgrog		FILE *out;
190165023Sgrog
191165026Sgrog		/*
192165026Sgrog		 * We send errors and warning to stderr and the rest to stdout.
193165023Sgrog		 */
194165026Sgrog		switch (loglevel) {
195165026Sgrog		case LOG_EMERG:
196165026Sgrog		case LOG_ALERT:
197165026Sgrog		case LOG_CRIT:
198165023Sgrog		case LOG_ERR:
199165026Sgrog		case LOG_WARNING:
200165026Sgrog			out = stderr;
201165026Sgrog			break;
202165026Sgrog		case LOG_NOTICE:
203165026Sgrog		case LOG_INFO:
204165023Sgrog		case LOG_DEBUG:
205165026Sgrog			out = stdout;
206165026Sgrog			break;
207165026Sgrog		default:
208165026Sgrog			assert(!"Invalid loglevel.");
209165026Sgrog			abort();	/* XXX: gcc */
210165023Sgrog		}
211165026Sgrog
212165026Sgrog		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
213165026Sgrog		/* Attach debuglevel if this is debug log. */
214165026Sgrog		if (loglevel == LOG_DEBUG)
215165026Sgrog			fprintf(out, "[%d]", debuglevel);
216165023Sgrog		fprintf(out, " ");
217165026Sgrog		fprintf(out, "%s", pjdlog_prefix);
218165026Sgrog		vfprintf(out, fmt, ap);
219165026Sgrog		if (error != -1)
220165026Sgrog			fprintf(out, ": %s.", strerror(error));
221165026Sgrog		fprintf(out, "\n");
222165023Sgrog		break;
223165026Sgrog	    }
224165026Sgrog	case PJDLOG_MODE_SYSLOG:
225165026Sgrog	    {
226165026Sgrog		char log[1024];
227165026Sgrog		int len;
228165023Sgrog
229165026Sgrog		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
230165026Sgrog		if ((size_t)len < sizeof(log))
231165026Sgrog			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
232165026Sgrog		if (error != -1 && (size_t)len < sizeof(log)) {
233165023Sgrog			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
234165026Sgrog			    strerror(error));
235165026Sgrog		}
236165026Sgrog		syslog(loglevel, "%s", log);
237165026Sgrog		break;
238165026Sgrog	    }
239165026Sgrog	default:
240165026Sgrog		assert(!"Invalid mode.");
241165026Sgrog	}
242165026Sgrog}
243165023Sgrog
244165026Sgrog/*
245165026Sgrog * Regular logs.
246165026Sgrog */
247165026Sgrogvoid
248165026Sgrogpjdlogv(int loglevel, const char *fmt, va_list ap)
249165023Sgrog{
250165026Sgrog
251165026Sgrog	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
252165026Sgrog	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
253165026Sgrog	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
254165026Sgrog	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
255165026Sgrog	    loglevel == LOG_INFO);
256165026Sgrog
257165026Sgrog	pjdlogv_common(loglevel, 0, -1, fmt, ap);
258165026Sgrog}
259165023Sgrog
260165026Sgrog/*
261165026Sgrog * Regular logs.
262165026Sgrog */
263165026Sgrogvoid
264165026Sgrogpjdlog(int loglevel, const char *fmt, ...)
265165026Sgrog{
266165026Sgrog	va_list ap;
267165023Sgrog
268165026Sgrog	va_start(ap, fmt);
269165026Sgrog	pjdlogv(loglevel, fmt, ap);
270165026Sgrog	va_end(ap);
271165026Sgrog}
272165026Sgrog
273165026Sgrog/*
274165023Sgrog * Debug logs.
275165026Sgrog */
276165026Sgrogvoid
277165023Sgrogpjdlogv_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 */
286void
287pjdlog_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 */
299void
300pjdlogv_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 */
309void
310pjdlog_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 */
322void
323pjdlogv_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 */
333void
334pjdlog_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 */
347void
348pjdlogv_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 */
358void
359pjdlog_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