pjdlog.c revision 217964
144746Smarkm/*- 250476Speter * Copyright (c) 2009-2010 The FreeBSD Foundation 344746Smarkm * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org> 444746Smarkm * All rights reserved. 5156813Sru * 6156813Sru * This software was developed by Pawel Jakub Dawidek under sponsorship from 744746Smarkm * the FreeBSD Foundation. 8195767Skensmith * 996462Sru * Redistribution and use in source and binary forms, with or without 1074870Sru * modification, are permitted provided that the following conditions 1174870Sru * are met: 12166856Sn_hibma * 1. Redistributions of source code must retain the above copyright 13166856Sn_hibma * notice, this list of conditions and the following disclaimer. 14166856Sn_hibma * 2. Redistributions in binary form must reproduce the above copyright 15167074Sru * notice, this list of conditions and the following disclaimer in the 1644746Smarkm * documentation and/or other materials provided with the distribution. 1744746Smarkm * 1844746Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1944746Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20291819Sbdrewery * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2144746Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2244746Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23117980Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24156813Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25137675Sbz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26137675Sbz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27156813Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2859266Ssteve * SUCH DAMAGE. 2959266Ssteve */ 3044746Smarkm 31201381Sed#include <sys/cdefs.h> 32201381Sed__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 217964 2011-01-27 19:18:42Z pjd $"); 3344746Smarkm 3444746Smarkm#include <assert.h> 3544746Smarkm#include <errno.h> 3645255Sache#include <stdarg.h> 3744746Smarkm#include <stdio.h> 3844746Smarkm#include <stdlib.h> 39#include <string.h> 40#include <syslog.h> 41 42#include "pjdlog.h" 43 44static int pjdlog_mode = PJDLOG_MODE_STD; 45static int pjdlog_debug_level = 0; 46static char pjdlog_prefix[128]; 47 48/* 49 * Configure where the logs should go. 50 * By default they are send to stdout/stderr, but after going into background 51 * (eg. by calling daemon(3)) application is responsible for changing mode to 52 * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 53 */ 54void 55pjdlog_mode_set(int mode) 56{ 57 58 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 59 60 pjdlog_mode = mode; 61 62 if (mode == PJDLOG_MODE_SYSLOG) 63 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 64} 65 66/* 67 * Return current mode. 68 */ 69int 70pjdlog_mode_get(void) 71{ 72 73 return (pjdlog_mode); 74} 75 76/* 77 * Set debug level. All the logs above the level specified here will be 78 * ignored. 79 */ 80void 81pjdlog_debug_set(int level) 82{ 83 84 assert(level >= 0); 85 86 pjdlog_debug_level = level; 87} 88 89/* 90 * Return current debug level. 91 */ 92int 93pjdlog_debug_get(void) 94{ 95 96 return (pjdlog_debug_level); 97} 98 99/* 100 * Set prefix that will be used before each log. 101 * Setting prefix to NULL will remove it. 102 */ 103void 104pjdlog_prefix_set(const char *fmt, ...) 105{ 106 va_list ap; 107 108 va_start(ap, fmt); 109 pjdlogv_prefix_set(fmt, ap); 110 va_end(ap); 111} 112 113/* 114 * Set prefix that will be used before each log. 115 * Setting prefix to NULL will remove it. 116 */ 117void 118pjdlogv_prefix_set(const char *fmt, va_list ap) 119{ 120 121 assert(fmt != NULL); 122 123 vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 124} 125 126/* 127 * Convert log level into string. 128 */ 129static const char * 130pjdlog_level_string(int loglevel) 131{ 132 133 switch (loglevel) { 134 case LOG_EMERG: 135 return ("EMERG"); 136 case LOG_ALERT: 137 return ("ALERT"); 138 case LOG_CRIT: 139 return ("CRIT"); 140 case LOG_ERR: 141 return ("ERROR"); 142 case LOG_WARNING: 143 return ("WARNING"); 144 case LOG_NOTICE: 145 return ("NOTICE"); 146 case LOG_INFO: 147 return ("INFO"); 148 case LOG_DEBUG: 149 return ("DEBUG"); 150 } 151 assert(!"Invalid log level."); 152 abort(); /* XXX: gcc */ 153} 154 155/* 156 * Common log routine. 157 */ 158void 159pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 160{ 161 va_list ap; 162 163 va_start(ap, fmt); 164 pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 165 va_end(ap); 166} 167 168/* 169 * Common log routine, which can handle regular log level as well as debug 170 * level. We decide here where to send the logs (stdout/stderr or syslog). 171 */ 172void 173pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 174 va_list ap) 175{ 176 177 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 178 loglevel == LOG_CRIT || loglevel == LOG_ERR || 179 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 180 loglevel == LOG_INFO || loglevel == LOG_DEBUG); 181 assert(loglevel != LOG_DEBUG || debuglevel > 0); 182 assert(error >= -1); 183 184 /* Ignore debug above configured level. */ 185 if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 186 return; 187 188 switch (pjdlog_mode) { 189 case PJDLOG_MODE_STD: 190 { 191 FILE *out; 192 193 /* 194 * We send errors and warning to stderr and the rest to stdout. 195 */ 196 switch (loglevel) { 197 case LOG_EMERG: 198 case LOG_ALERT: 199 case LOG_CRIT: 200 case LOG_ERR: 201 case LOG_WARNING: 202 out = stderr; 203 break; 204 case LOG_NOTICE: 205 case LOG_INFO: 206 case LOG_DEBUG: 207 out = stdout; 208 break; 209 default: 210 assert(!"Invalid loglevel."); 211 abort(); /* XXX: gcc */ 212 } 213 214 fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 215 /* Attach debuglevel if this is debug log. */ 216 if (loglevel == LOG_DEBUG) 217 fprintf(out, "[%d]", debuglevel); 218 fprintf(out, " %s", pjdlog_prefix); 219 vfprintf(out, fmt, ap); 220 if (error != -1) 221 fprintf(out, ": %s.", strerror(error)); 222 fprintf(out, "\n"); 223 fflush(out); 224 break; 225 } 226 case PJDLOG_MODE_SYSLOG: 227 { 228 char log[1024]; 229 int len; 230 231 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 232 if ((size_t)len < sizeof(log)) 233 len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 234 if (error != -1 && (size_t)len < sizeof(log)) { 235 (void)snprintf(log + len, sizeof(log) - len, ": %s.", 236 strerror(error)); 237 } 238 syslog(loglevel, "%s", log); 239 break; 240 } 241 default: 242 assert(!"Invalid mode."); 243 } 244} 245 246/* 247 * Regular logs. 248 */ 249void 250pjdlogv(int loglevel, const char *fmt, va_list ap) 251{ 252 253 /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 254 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 255 loglevel == LOG_CRIT || loglevel == LOG_ERR || 256 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 257 loglevel == LOG_INFO); 258 259 pjdlogv_common(loglevel, 0, -1, fmt, ap); 260} 261 262/* 263 * Regular logs. 264 */ 265void 266pjdlog(int loglevel, const char *fmt, ...) 267{ 268 va_list ap; 269 270 va_start(ap, fmt); 271 pjdlogv(loglevel, fmt, ap); 272 va_end(ap); 273} 274 275/* 276 * Debug logs. 277 */ 278void 279pjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 280{ 281 282 pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 283} 284 285/* 286 * Debug logs. 287 */ 288void 289pjdlog_debug(int debuglevel, const char *fmt, ...) 290{ 291 va_list ap; 292 293 va_start(ap, fmt); 294 pjdlogv_debug(debuglevel, fmt, ap); 295 va_end(ap); 296} 297 298/* 299 * Error logs with errno logging. 300 */ 301void 302pjdlogv_errno(int loglevel, const char *fmt, va_list ap) 303{ 304 305 pjdlogv_common(loglevel, 0, errno, fmt, ap); 306} 307 308/* 309 * Error logs with errno logging. 310 */ 311void 312pjdlog_errno(int loglevel, const char *fmt, ...) 313{ 314 va_list ap; 315 316 va_start(ap, fmt); 317 pjdlogv_errno(loglevel, fmt, ap); 318 va_end(ap); 319} 320 321/* 322 * Log error, errno and exit. 323 */ 324void 325pjdlogv_exit(int exitcode, const char *fmt, va_list ap) 326{ 327 328 pjdlogv_errno(LOG_ERR, fmt, ap); 329 exit(exitcode); 330 /* NOTREACHED */ 331} 332 333/* 334 * Log error, errno and exit. 335 */ 336void 337pjdlog_exit(int exitcode, const char *fmt, ...) 338{ 339 va_list ap; 340 341 va_start(ap, fmt); 342 pjdlogv_exit(exitcode, fmt, ap); 343 /* NOTREACHED */ 344 va_end(ap); 345} 346 347/* 348 * Log error and exit. 349 */ 350void 351pjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 352{ 353 354 pjdlogv(LOG_ERR, fmt, ap); 355 exit(exitcode); 356 /* NOTREACHED */ 357} 358 359/* 360 * Log error and exit. 361 */ 362void 363pjdlog_exitx(int exitcode, const char *fmt, ...) 364{ 365 va_list ap; 366 367 va_start(ap, fmt); 368 pjdlogv_exitx(exitcode, fmt, ap); 369 /* NOTREACHED */ 370 va_end(ap); 371} 372 373/* 374 * Log assertion and exit. 375 */ 376void 377pjdlog_verify(const char *func, const char *file, int line, 378 const char *failedexpr) 379{ 380 381 if (func == NULL) { 382 pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 383 failedexpr, file, line); 384 } else { 385 pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 386 failedexpr, func, file, line); 387 } 388 abort(); 389} 390