pjdlog.c revision 217961
155714Skris/*-
255714Skris * Copyright (c) 2009-2011 The FreeBSD Foundation
355714Skris * All rights reserved.
455714Skris *
555714Skris * This software was developed by Pawel Jakub Dawidek under sponsorship from
655714Skris * the FreeBSD Foundation.
755714Skris *
855714Skris * Redistribution and use in source and binary forms, with or without
955714Skris * modification, are permitted provided that the following conditions
1055714Skris * are met:
1155714Skris * 1. Redistributions of source code must retain the above copyright
1255714Skris *    notice, this list of conditions and the following disclaimer.
1355714Skris * 2. Redistributions in binary form must reproduce the above copyright
1455714Skris *    notice, this list of conditions and the following disclaimer in the
1555714Skris *    documentation and/or other materials provided with the distribution.
1655714Skris *
1755714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1855714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1955714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2055714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2155714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2255714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2355714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2455714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2555714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2655714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2755714Skris * SUCH DAMAGE.
2855714Skris */
2955714Skris
3055714Skris#include <sys/cdefs.h>
3155714Skris__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 217961 2011-01-27 19:12:44Z pjd $");
3255714Skris
3355714Skris#include <assert.h>
3455714Skris#include <errno.h>
3555714Skris#include <stdarg.h>
3655714Skris#include <stdio.h>
3755714Skris#include <stdlib.h>
3855714Skris#include <string.h>
3955714Skris#include <syslog.h>
4055714Skris
4155714Skris#include "pjdlog.h"
4255714Skris
4355714Skrisstatic int pjdlog_mode = PJDLOG_MODE_STD;
4455714Skrisstatic int pjdlog_debug_level = 0;
4555714Skrisstatic char pjdlog_prefix[128];
4655714Skris
4755714Skris/*
4855714Skris * Configure where the logs should go.
4955714Skris * By default they are send to stdout/stderr, but after going into background
5055714Skris * (eg. by calling daemon(3)) application is responsible for changing mode to
5155714Skris * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
5255714Skris */
5355714Skrisvoid
5455714Skrispjdlog_mode_set(int mode)
5555714Skris{
5655714Skris
5755714Skris	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
5855714Skris
5955714Skris	pjdlog_mode = mode;
6055714Skris
6155714Skris	if (mode == PJDLOG_MODE_SYSLOG)
6255714Skris		openlog(NULL, LOG_PID, LOG_DAEMON);
6355714Skris}
6455714Skris
6555714Skris/*
6655714Skris * Return current mode.
6755714Skris */
6855714Skrisint
6955714Skrispjdlog_mode_get(void)
7055714Skris{
7155714Skris
7255714Skris	return (pjdlog_mode);
7355714Skris}
7455714Skris
7555714Skris/*
7655714Skris * Set debug level. All the logs above the level specified here will be
7755714Skris * ignored.
7855714Skris */
7955714Skrisvoid
8055714Skrispjdlog_debug_set(int level)
8155714Skris{
8255714Skris
8355714Skris	assert(level >= 0);
8455714Skris
8555714Skris	pjdlog_debug_level = level;
8655714Skris}
8755714Skris
8855714Skris/*
8955714Skris * Return current debug level.
9055714Skris */
9155714Skrisint
9255714Skrispjdlog_debug_get(void)
9355714Skris{
9455714Skris
9555714Skris	return (pjdlog_debug_level);
9655714Skris}
9755714Skris
9855714Skris/*
9955714Skris * Set prefix that will be used before each log.
10055714Skris * Setting prefix to NULL will remove it.
10155714Skris */
10255714Skrisvoid
10355714Skrispjdlog_prefix_set(const char *fmt, ...)
10455714Skris{
10555714Skris	va_list ap;
10655714Skris
10755714Skris	va_start(ap, fmt);
10855714Skris	pjdlogv_prefix_set(fmt, ap);
10955714Skris	va_end(ap);
11055714Skris}
11155714Skris
11255714Skris/*
11355714Skris * Set prefix that will be used before each log.
11455714Skris * Setting prefix to NULL will remove it.
11555714Skris */
11655714Skrisvoid
11755714Skrispjdlogv_prefix_set(const char *fmt, va_list ap)
11855714Skris{
11955714Skris
12055714Skris	assert(fmt != NULL);
12155714Skris
12255714Skris	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
12355714Skris}
12455714Skris
12555714Skris/*
12655714Skris * Convert log level into string.
12755714Skris */
12855714Skrisstatic const char *
12955714Skrispjdlog_level_string(int loglevel)
13055714Skris{
13155714Skris
13255714Skris	switch (loglevel) {
13355714Skris	case LOG_EMERG:
13455714Skris		return ("EMERG");
13555714Skris	case LOG_ALERT:
13655714Skris		return ("ALERT");
13755714Skris	case LOG_CRIT:
13855714Skris		return ("CRIT");
13955714Skris	case LOG_ERR:
14055714Skris		return ("ERROR");
14155714Skris	case LOG_WARNING:
14255714Skris		return ("WARNING");
14355714Skris	case LOG_NOTICE:
14455714Skris		return ("NOTICE");
14555714Skris	case LOG_INFO:
14655714Skris		return ("INFO");
14755714Skris	case LOG_DEBUG:
14855714Skris		return ("DEBUG");
14955714Skris	}
15055714Skris	assert(!"Invalid log level.");
15155714Skris	abort();	/* XXX: gcc */
15255714Skris}
15355714Skris
15455714Skris/*
15555714Skris * Common log routine.
15655714Skris */
15755714Skrisvoid
15855714Skrispjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
15955714Skris{
16055714Skris	va_list ap;
16155714Skris
16255714Skris	va_start(ap, fmt);
16355714Skris	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
16455714Skris	va_end(ap);
16555714Skris}
16655714Skris
16755714Skris/*
16855714Skris * Common log routine, which can handle regular log level as well as debug
16955714Skris * level. We decide here where to send the logs (stdout/stderr or syslog).
17055714Skris */
17155714Skrisvoid
17255714Skrispjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
17355714Skris    va_list ap)
17455714Skris{
17555714Skris
17655714Skris	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
17755714Skris	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
17855714Skris	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
17955714Skris	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
18055714Skris	assert(loglevel != LOG_DEBUG || debuglevel > 0);
18155714Skris	assert(error >= -1);
18255714Skris
18355714Skris	/* Ignore debug above configured level. */
18455714Skris	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
18555714Skris		return;
18655714Skris
18755714Skris	switch (pjdlog_mode) {
18855714Skris	case PJDLOG_MODE_STD:
18955714Skris	    {
19055714Skris		FILE *out;
19155714Skris
19255714Skris		/*
19355714Skris		 * We send errors and warning to stderr and the rest to stdout.
19455714Skris		 */
19555714Skris		switch (loglevel) {
19655714Skris		case LOG_EMERG:
19755714Skris		case LOG_ALERT:
19855714Skris		case LOG_CRIT:
19955714Skris		case LOG_ERR:
20055714Skris		case LOG_WARNING:
20155714Skris			out = stderr;
20255714Skris			break;
20355714Skris		case LOG_NOTICE:
20455714Skris		case LOG_INFO:
20555714Skris		case LOG_DEBUG:
20655714Skris			out = stdout;
20755714Skris			break;
20855714Skris		default:
20955714Skris			assert(!"Invalid loglevel.");
21055714Skris			abort();	/* XXX: gcc */
21155714Skris		}
21255714Skris
21355714Skris		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
21455714Skris		/* Attach debuglevel if this is debug log. */
21555714Skris		if (loglevel == LOG_DEBUG)
21655714Skris			fprintf(out, "[%d]", debuglevel);
21755714Skris		fprintf(out, " %s", pjdlog_prefix);
21855714Skris		vfprintf(out, fmt, ap);
21955714Skris		if (error != -1)
22055714Skris			fprintf(out, ": %s.", strerror(error));
22155714Skris		fprintf(out, "\n");
22255714Skris		fflush(out);
22355714Skris		break;
22455714Skris	    }
22555714Skris	case PJDLOG_MODE_SYSLOG:
22655714Skris	    {
22755714Skris		char log[1024];
22855714Skris		int len;
22955714Skris
23055714Skris		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
23155714Skris		if ((size_t)len < sizeof(log))
23255714Skris			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
23355714Skris		if (error != -1 && (size_t)len < sizeof(log)) {
23455714Skris			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
23555714Skris			    strerror(error));
23655714Skris		}
23755714Skris		syslog(loglevel, "%s", log);
23855714Skris		break;
23955714Skris	    }
24055714Skris	default:
24155714Skris		assert(!"Invalid mode.");
24255714Skris	}
24355714Skris}
24455714Skris
24555714Skris/*
24655714Skris * Regular logs.
24755714Skris */
24855714Skrisvoid
24955714Skrispjdlogv(int loglevel, const char *fmt, va_list ap)
25055714Skris{
25155714Skris
25255714Skris	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
25355714Skris	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
25455714Skris	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
25555714Skris	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
25655714Skris	    loglevel == LOG_INFO);
25755714Skris
25855714Skris	pjdlogv_common(loglevel, 0, -1, fmt, ap);
25955714Skris}
26055714Skris
26155714Skris/*
26255714Skris * Regular logs.
26355714Skris */
26455714Skrisvoid
26555714Skrispjdlog(int loglevel, const char *fmt, ...)
26655714Skris{
26755714Skris	va_list ap;
26855714Skris
26955714Skris	va_start(ap, fmt);
27055714Skris	pjdlogv(loglevel, fmt, ap);
27155714Skris	va_end(ap);
27255714Skris}
27355714Skris
27455714Skris/*
27555714Skris * Debug logs.
27655714Skris */
27755714Skrisvoid
27855714Skrispjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
27955714Skris{
28055714Skris
28155714Skris	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
28255714Skris}
28355714Skris
28455714Skris/*
28555714Skris * Debug logs.
28655714Skris */
28755714Skrisvoid
28855714Skrispjdlog_debug(int debuglevel, const char *fmt, ...)
28955714Skris{
29055714Skris	va_list ap;
29155714Skris
29255714Skris	va_start(ap, fmt);
29355714Skris	pjdlogv_debug(debuglevel, fmt, ap);
29455714Skris	va_end(ap);
29555714Skris}
29655714Skris
29755714Skris/*
29855714Skris * Error logs with errno logging.
29955714Skris */
30055714Skrisvoid
30155714Skrispjdlogv_errno(int loglevel, const char *fmt, va_list ap)
30255714Skris{
30355714Skris
30455714Skris	pjdlogv_common(loglevel, 0, errno, fmt, ap);
30555714Skris}
30655714Skris
30755714Skris/*
30855714Skris * Error logs with errno logging.
30955714Skris */
31055714Skrisvoid
311pjdlog_errno(int loglevel, const char *fmt, ...)
312{
313	va_list ap;
314
315	va_start(ap, fmt);
316	pjdlogv_errno(loglevel, fmt, ap);
317	va_end(ap);
318}
319
320/*
321 * Log error, errno and exit.
322 */
323void
324pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
325{
326
327	pjdlogv_errno(LOG_ERR, fmt, ap);
328	exit(exitcode);
329	/* NOTREACHED */
330}
331
332/*
333 * Log error, errno and exit.
334 */
335void
336pjdlog_exit(int exitcode, const char *fmt, ...)
337{
338	va_list ap;
339
340	va_start(ap, fmt);
341	pjdlogv_exit(exitcode, fmt, ap);
342	/* NOTREACHED */
343	va_end(ap);
344}
345
346/*
347 * Log error and exit.
348 */
349void
350pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
351{
352
353	pjdlogv(LOG_ERR, fmt, ap);
354	exit(exitcode);
355	/* NOTREACHED */
356}
357
358/*
359 * Log error and exit.
360 */
361void
362pjdlog_exitx(int exitcode, const char *fmt, ...)
363{
364	va_list ap;
365
366	va_start(ap, fmt);
367	pjdlogv_exitx(exitcode, fmt, ap);
368	/* NOTREACHED */
369	va_end(ap);
370}
371
372/*
373 * Log assertion and exit.
374 */
375void
376pjdlog_verify(const char *func, const char *file, int line,
377    const char *failedexpr)
378{
379
380	if (func == NULL) {
381		pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
382		    failedexpr, file, line);
383	} else {
384		pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
385		    failedexpr, func, file, line);
386	}
387	abort();
388}
389