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