pjdlog.c revision 206697
1/*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Pawel Jakub Dawidek under sponsorship from 6 * the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: head/sbin/hastd/pjdlog.c 206697 2010-04-16 06:49:12Z pjd $ 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 206697 2010-04-16 06:49:12Z pjd $"); 34 35#include <assert.h> 36#include <errno.h> 37#include <stdarg.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <syslog.h> 42 43#include "pjdlog.h" 44 45static int pjdlog_mode = PJDLOG_MODE_STD; 46static int pjdlog_debug_level = 0; 47static char pjdlog_prefix[128]; 48 49/* 50 * Configure where the logs should go. 51 * By default they are send to stdout/stderr, but after going into background 52 * (eg. by calling daemon(3)) application is responsible for changing mode to 53 * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 54 */ 55void 56pjdlog_mode_set(int mode) 57{ 58 59 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 60 61 pjdlog_mode = mode; 62} 63 64/* 65 * Return current mode. 66 */ 67int 68pjdlog_mode_get(void) 69{ 70 71 return (pjdlog_mode); 72} 73 74/* 75 * Set debug level. All the logs above the level specified here will be 76 * ignored. 77 */ 78void 79pjdlog_debug_set(int level) 80{ 81 82 assert(level >= 0); 83 84 pjdlog_debug_level = level; 85} 86 87/* 88 * Return current debug level. 89 */ 90int 91pjdlog_debug_get(void) 92{ 93 94 return (pjdlog_debug_level); 95} 96 97/* 98 * Set prefix that will be used before each log. 99 * Setting prefix to NULL will remove it. 100 */ 101void 102pjdlog_prefix_set(const char *fmt, ...) 103{ 104 va_list ap; 105 106 va_start(ap, fmt); 107 pjdlog_prefix_setv(fmt, ap); 108 va_end(ap); 109} 110 111/* 112 * Set prefix that will be used before each log. 113 * Setting prefix to NULL will remove it. 114 */ 115void 116pjdlog_prefix_setv(const char *fmt, va_list ap) 117{ 118 119 assert(fmt != NULL); 120 121 vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 122} 123 124/* 125 * Convert log level into string. 126 */ 127static const char * 128pjdlog_level_string(int loglevel) 129{ 130 131 switch (loglevel) { 132 case LOG_EMERG: 133 return ("EMERG"); 134 case LOG_ALERT: 135 return ("ALERT"); 136 case LOG_CRIT: 137 return ("CRIT"); 138 case LOG_ERR: 139 return ("ERROR"); 140 case LOG_WARNING: 141 return ("WARNING"); 142 case LOG_NOTICE: 143 return ("NOTICE"); 144 case LOG_INFO: 145 return ("INFO"); 146 case LOG_DEBUG: 147 return ("DEBUG"); 148 } 149 assert(!"Invalid log level."); 150 abort(); /* XXX: gcc */ 151} 152 153/* 154 * Common log routine. 155 */ 156void 157pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 158{ 159 va_list ap; 160 161 va_start(ap, fmt); 162 pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 163 va_end(ap); 164} 165 166/* 167 * Common log routine, which can handle regular log level as well as debug 168 * level. We decide here where to send the logs (stdout/stderr or syslog). 169 */ 170void 171pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 172 va_list ap) 173{ 174 175 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 176 loglevel == LOG_CRIT || loglevel == LOG_ERR || 177 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 178 loglevel == LOG_INFO || loglevel == LOG_DEBUG); 179 assert(loglevel != LOG_DEBUG || debuglevel > 0); 180 assert(error >= -1); 181 182 /* Ignore debug above configured level. */ 183 if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 184 return; 185 186 switch (pjdlog_mode) { 187 case PJDLOG_MODE_STD: 188 { 189 FILE *out; 190 191 /* 192 * We send errors and warning to stderr and the rest to stdout. 193 */ 194 switch (loglevel) { 195 case LOG_EMERG: 196 case LOG_ALERT: 197 case LOG_CRIT: 198 case LOG_ERR: 199 case LOG_WARNING: 200 out = stderr; 201 break; 202 case LOG_NOTICE: 203 case LOG_INFO: 204 case LOG_DEBUG: 205 out = stdout; 206 break; 207 default: 208 assert(!"Invalid loglevel."); 209 abort(); /* XXX: gcc */ 210 } 211 212 fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 213 /* Attach debuglevel if this is debug log. */ 214 if (loglevel == LOG_DEBUG) 215 fprintf(out, "[%d]", debuglevel); 216 fprintf(out, " "); 217 fprintf(out, "%s", pjdlog_prefix); 218 vfprintf(out, fmt, ap); 219 if (error != -1) 220 fprintf(out, ": %s.", strerror(error)); 221 fprintf(out, "\n"); 222 break; 223 } 224 case PJDLOG_MODE_SYSLOG: 225 { 226 char log[1024]; 227 int len; 228 229 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 230 if ((size_t)len < sizeof(log)) 231 len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 232 if (error != -1 && (size_t)len < sizeof(log)) { 233 (void)snprintf(log + len, sizeof(log) - len, ": %s.", 234 strerror(error)); 235 } 236 syslog(loglevel, "%s", log); 237 break; 238 } 239 default: 240 assert(!"Invalid mode."); 241 } 242} 243 244/* 245 * Regular logs. 246 */ 247void 248pjdlogv(int loglevel, const char *fmt, va_list ap) 249{ 250 251 /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 252 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 253 loglevel == LOG_CRIT || loglevel == LOG_ERR || 254 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 255 loglevel == LOG_INFO); 256 257 pjdlogv_common(loglevel, 0, -1, fmt, ap); 258} 259 260/* 261 * Regular logs. 262 */ 263void 264pjdlog(int loglevel, const char *fmt, ...) 265{ 266 va_list ap; 267 268 va_start(ap, fmt); 269 pjdlogv(loglevel, fmt, ap); 270 va_end(ap); 271} 272 273/* 274 * Debug logs. 275 */ 276void 277pjdlogv_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