pjdlog.c revision 210875
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 30204076Spjd#include <sys/cdefs.h> 31204076Spjd__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 210875 2010-08-05 18:26:38Z pjd $"); 32204076Spjd 33204076Spjd#include <assert.h> 34204076Spjd#include <errno.h> 35204076Spjd#include <stdarg.h> 36204076Spjd#include <stdio.h> 37204076Spjd#include <stdlib.h> 38204076Spjd#include <string.h> 39204076Spjd#include <syslog.h> 40204076Spjd 41204076Spjd#include "pjdlog.h" 42204076Spjd 43204076Spjdstatic int pjdlog_mode = PJDLOG_MODE_STD; 44204076Spjdstatic int pjdlog_debug_level = 0; 45204076Spjdstatic char pjdlog_prefix[128]; 46204076Spjd 47204076Spjd/* 48204076Spjd * Configure where the logs should go. 49204076Spjd * By default they are send to stdout/stderr, but after going into background 50204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to 51204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 52204076Spjd */ 53204076Spjdvoid 54204076Spjdpjdlog_mode_set(int mode) 55204076Spjd{ 56204076Spjd 57204076Spjd assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 58204076Spjd 59204076Spjd pjdlog_mode = mode; 60204076Spjd} 61204076Spjd 62204076Spjd/* 63204076Spjd * Return current mode. 64204076Spjd */ 65204076Spjdint 66204076Spjdpjdlog_mode_get(void) 67204076Spjd{ 68204076Spjd 69204076Spjd return (pjdlog_mode); 70204076Spjd} 71204076Spjd 72204076Spjd/* 73204076Spjd * Set debug level. All the logs above the level specified here will be 74204076Spjd * ignored. 75204076Spjd */ 76204076Spjdvoid 77204076Spjdpjdlog_debug_set(int level) 78204076Spjd{ 79204076Spjd 80204076Spjd assert(level >= 0); 81204076Spjd 82204076Spjd pjdlog_debug_level = level; 83204076Spjd} 84204076Spjd 85204076Spjd/* 86204076Spjd * Return current debug level. 87204076Spjd */ 88204076Spjdint 89204076Spjdpjdlog_debug_get(void) 90204076Spjd{ 91204076Spjd 92204076Spjd return (pjdlog_debug_level); 93204076Spjd} 94204076Spjd 95204076Spjd/* 96204076Spjd * Set prefix that will be used before each log. 97204076Spjd * Setting prefix to NULL will remove it. 98204076Spjd */ 99204076Spjdvoid 100204076Spjdpjdlog_prefix_set(const char *fmt, ...) 101204076Spjd{ 102204076Spjd va_list ap; 103204076Spjd 104204076Spjd va_start(ap, fmt); 105204076Spjd pjdlog_prefix_setv(fmt, ap); 106204076Spjd va_end(ap); 107204076Spjd} 108204076Spjd 109204076Spjd/* 110204076Spjd * Set prefix that will be used before each log. 111204076Spjd * Setting prefix to NULL will remove it. 112204076Spjd */ 113204076Spjdvoid 114204076Spjdpjdlog_prefix_setv(const char *fmt, va_list ap) 115204076Spjd{ 116204076Spjd 117204076Spjd assert(fmt != NULL); 118204076Spjd 119204076Spjd vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 120204076Spjd} 121204076Spjd 122204076Spjd/* 123204076Spjd * Convert log level into string. 124204076Spjd */ 125204076Spjdstatic const char * 126204076Spjdpjdlog_level_string(int loglevel) 127204076Spjd{ 128204076Spjd 129204076Spjd switch (loglevel) { 130204076Spjd case LOG_EMERG: 131204076Spjd return ("EMERG"); 132204076Spjd case LOG_ALERT: 133204076Spjd return ("ALERT"); 134204076Spjd case LOG_CRIT: 135204076Spjd return ("CRIT"); 136204076Spjd case LOG_ERR: 137204076Spjd return ("ERROR"); 138204076Spjd case LOG_WARNING: 139204076Spjd return ("WARNING"); 140204076Spjd case LOG_NOTICE: 141204076Spjd return ("NOTICE"); 142204076Spjd case LOG_INFO: 143204076Spjd return ("INFO"); 144204076Spjd case LOG_DEBUG: 145204076Spjd return ("DEBUG"); 146204076Spjd } 147204076Spjd assert(!"Invalid log level."); 148204076Spjd abort(); /* XXX: gcc */ 149204076Spjd} 150204076Spjd 151204076Spjd/* 152204076Spjd * Common log routine. 153204076Spjd */ 154204076Spjdvoid 155204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 156204076Spjd{ 157204076Spjd va_list ap; 158204076Spjd 159204076Spjd va_start(ap, fmt); 160204076Spjd pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 161204076Spjd va_end(ap); 162204076Spjd} 163204076Spjd 164204076Spjd/* 165204076Spjd * Common log routine, which can handle regular log level as well as debug 166204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog). 167204076Spjd */ 168204076Spjdvoid 169204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 170204076Spjd va_list ap) 171204076Spjd{ 172204076Spjd 173204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 174204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 175204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 176204076Spjd loglevel == LOG_INFO || loglevel == LOG_DEBUG); 177204076Spjd assert(loglevel != LOG_DEBUG || debuglevel > 0); 178204076Spjd assert(error >= -1); 179204076Spjd 180204076Spjd /* Ignore debug above configured level. */ 181204076Spjd if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 182204076Spjd return; 183204076Spjd 184204076Spjd switch (pjdlog_mode) { 185204076Spjd case PJDLOG_MODE_STD: 186204076Spjd { 187204076Spjd FILE *out; 188204076Spjd 189204076Spjd /* 190204076Spjd * We send errors and warning to stderr and the rest to stdout. 191204076Spjd */ 192204076Spjd switch (loglevel) { 193204076Spjd case LOG_EMERG: 194204076Spjd case LOG_ALERT: 195204076Spjd case LOG_CRIT: 196204076Spjd case LOG_ERR: 197204076Spjd case LOG_WARNING: 198204076Spjd out = stderr; 199204076Spjd break; 200204076Spjd case LOG_NOTICE: 201204076Spjd case LOG_INFO: 202204076Spjd case LOG_DEBUG: 203204076Spjd out = stdout; 204204076Spjd break; 205204076Spjd default: 206204076Spjd assert(!"Invalid loglevel."); 207204076Spjd abort(); /* XXX: gcc */ 208204076Spjd } 209204076Spjd 210204076Spjd fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 211204076Spjd /* Attach debuglevel if this is debug log. */ 212204076Spjd if (loglevel == LOG_DEBUG) 213204076Spjd fprintf(out, "[%d]", debuglevel); 214204076Spjd fprintf(out, " "); 215204076Spjd fprintf(out, "%s", pjdlog_prefix); 216204076Spjd vfprintf(out, fmt, ap); 217204076Spjd if (error != -1) 218204076Spjd fprintf(out, ": %s.", strerror(error)); 219204076Spjd fprintf(out, "\n"); 220204076Spjd break; 221204076Spjd } 222204076Spjd case PJDLOG_MODE_SYSLOG: 223204076Spjd { 224204076Spjd char log[1024]; 225204076Spjd int len; 226204076Spjd 227204076Spjd len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 228204076Spjd if ((size_t)len < sizeof(log)) 229206697Spjd len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 230204076Spjd if (error != -1 && (size_t)len < sizeof(log)) { 231204076Spjd (void)snprintf(log + len, sizeof(log) - len, ": %s.", 232204076Spjd strerror(error)); 233204076Spjd } 234204076Spjd syslog(loglevel, "%s", log); 235204076Spjd break; 236204076Spjd } 237204076Spjd default: 238204076Spjd assert(!"Invalid mode."); 239204076Spjd } 240204076Spjd} 241204076Spjd 242204076Spjd/* 243204076Spjd * Regular logs. 244204076Spjd */ 245204076Spjdvoid 246204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap) 247204076Spjd{ 248204076Spjd 249204076Spjd /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 250204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 251204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 252204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 253204076Spjd loglevel == LOG_INFO); 254204076Spjd 255204076Spjd pjdlogv_common(loglevel, 0, -1, fmt, ap); 256204076Spjd} 257204076Spjd 258204076Spjd/* 259204076Spjd * Regular logs. 260204076Spjd */ 261204076Spjdvoid 262204076Spjdpjdlog(int loglevel, const char *fmt, ...) 263204076Spjd{ 264204076Spjd va_list ap; 265204076Spjd 266204076Spjd va_start(ap, fmt); 267204076Spjd pjdlogv(loglevel, fmt, ap); 268204076Spjd va_end(ap); 269204076Spjd} 270204076Spjd 271204076Spjd/* 272204076Spjd * Debug logs. 273204076Spjd */ 274204076Spjdvoid 275204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 276204076Spjd{ 277204076Spjd 278204076Spjd pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 279204076Spjd} 280204076Spjd 281204076Spjd/* 282204076Spjd * Debug logs. 283204076Spjd */ 284204076Spjdvoid 285204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...) 286204076Spjd{ 287204076Spjd va_list ap; 288204076Spjd 289204076Spjd va_start(ap, fmt); 290204076Spjd pjdlogv_debug(debuglevel, fmt, ap); 291204076Spjd va_end(ap); 292204076Spjd} 293204076Spjd 294204076Spjd/* 295204076Spjd * Error logs with errno logging. 296204076Spjd */ 297204076Spjdvoid 298204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap) 299204076Spjd{ 300204076Spjd 301204076Spjd pjdlogv_common(loglevel, 0, errno, fmt, ap); 302204076Spjd} 303204076Spjd 304204076Spjd/* 305204076Spjd * Error logs with errno logging. 306204076Spjd */ 307204076Spjdvoid 308204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...) 309204076Spjd{ 310204076Spjd va_list ap; 311204076Spjd 312204076Spjd va_start(ap, fmt); 313204076Spjd pjdlogv_errno(loglevel, fmt, ap); 314204076Spjd va_end(ap); 315204076Spjd} 316204076Spjd 317204076Spjd/* 318204076Spjd * Log error, errno and exit. 319204076Spjd */ 320204076Spjdvoid 321204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap) 322204076Spjd{ 323204076Spjd 324204076Spjd pjdlogv_errno(LOG_ERR, fmt, ap); 325204076Spjd exit(exitcode); 326210872Spjd /* NOTREACHED */ 327204076Spjd} 328204076Spjd 329204076Spjd/* 330204076Spjd * Log error, errno and exit. 331204076Spjd */ 332204076Spjdvoid 333204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...) 334204076Spjd{ 335204076Spjd va_list ap; 336204076Spjd 337204076Spjd va_start(ap, fmt); 338204076Spjd pjdlogv_exit(exitcode, fmt, ap); 339204076Spjd /* NOTREACHED */ 340204076Spjd va_end(ap); 341204076Spjd} 342204076Spjd 343204076Spjd/* 344204076Spjd * Log error and exit. 345204076Spjd */ 346204076Spjdvoid 347204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 348204076Spjd{ 349204076Spjd 350204076Spjd pjdlogv(LOG_ERR, fmt, ap); 351204076Spjd exit(exitcode); 352210872Spjd /* NOTREACHED */ 353204076Spjd} 354204076Spjd 355204076Spjd/* 356204076Spjd * Log error and exit. 357204076Spjd */ 358204076Spjdvoid 359204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...) 360204076Spjd{ 361204076Spjd va_list ap; 362204076Spjd 363204076Spjd va_start(ap, fmt); 364204076Spjd pjdlogv_exitx(exitcode, fmt, ap); 365204076Spjd /* NOTREACHED */ 366204076Spjd va_end(ap); 367204076Spjd} 368210875Spjd 369210875Spjd/* 370210875Spjd * Log assertion and exit. 371210875Spjd */ 372210875Spjdvoid 373210875Spjdpjdlog_verify(const char *func, const char *file, int line, 374210875Spjd const char *failedexpr) 375210875Spjd{ 376210875Spjd 377210875Spjd if (func == NULL) { 378210875Spjd pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 379210875Spjd failedexpr, file, line); 380210875Spjd } else { 381210875Spjd pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 382210875Spjd failedexpr, func, file, line); 383210875Spjd } 384210875Spjd abort(); 385210875Spjd /* NOTREACHED */ 386210875Spjd} 387210875Spjd 388