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