mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-22 15:17:09 +00:00
2e9785cfb5
git-svn-id: file:///svn/unbound/trunk@723 be551aaa-1e26-0410-a405-d3ace91eadb9
256 lines
6.2 KiB
C
256 lines
6.2 KiB
C
/*
|
|
* util/log.c - implementation of the log code
|
|
*
|
|
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
|
*
|
|
* This software is open source.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
|
* be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
/**
|
|
* \file
|
|
* Implementation of log.h.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "util/log.h"
|
|
#include "util/locks.h"
|
|
#ifdef HAVE_TIME_H
|
|
#include <time.h>
|
|
#endif
|
|
#ifdef HAVE_SYSLOG_H
|
|
# include <syslog.h>
|
|
#else
|
|
/**define LOG_ constants */
|
|
# define LOG_CRIT 2
|
|
# define LOG_ERR 3
|
|
# define LOG_WARNING 4
|
|
# define LOG_NOTICE 5
|
|
# define LOG_INFO 6
|
|
# define LOG_DEBUG 7
|
|
#endif
|
|
|
|
/* default verbosity */
|
|
enum verbosity_value verbosity = 0;
|
|
/** the file logged to. */
|
|
static FILE* logfile = 0;
|
|
/** if key has been created */
|
|
static int key_created = 0;
|
|
/** pthread key for thread ids in logfile */
|
|
static ub_thread_key_t logkey;
|
|
/** the identity of this executable/process */
|
|
static const char* ident="unbound";
|
|
#ifdef HAVE_SYSLOG_H
|
|
/** are we using syslog(3) to log to */
|
|
static int log_to_syslog = 0;
|
|
#endif /* HAVE_SYSLOG_H */
|
|
|
|
void
|
|
log_init(const char* filename, int use_syslog, const char* chrootdir)
|
|
{
|
|
FILE *f;
|
|
if(!key_created) {
|
|
key_created = 1;
|
|
ub_thread_key_create(&logkey, NULL);
|
|
}
|
|
if(logfile
|
|
#ifdef HAVE_SYSLOG_H
|
|
|| log_to_syslog
|
|
#endif
|
|
)
|
|
verbose(VERB_DETAIL, "switching log to %s",
|
|
use_syslog?"syslog":(filename&&filename[0]?filename:"stderr"));
|
|
if(logfile && logfile != stderr)
|
|
fclose(logfile);
|
|
#ifdef HAVE_SYSLOG_H
|
|
if(log_to_syslog) {
|
|
closelog();
|
|
log_to_syslog = 0;
|
|
}
|
|
if(use_syslog) {
|
|
openlog(ident, 0, LOG_DAEMON);
|
|
log_to_syslog = 1;
|
|
return;
|
|
}
|
|
#endif /* HAVE_SYSLOG_H */
|
|
if(!filename || !filename[0]) {
|
|
logfile = stderr;
|
|
return;
|
|
}
|
|
/* open the file for logging */
|
|
if(chrootdir && chrootdir[0] && strncmp(filename, chrootdir,
|
|
strlen(chrootdir)) == 0)
|
|
filename += strlen(chrootdir);
|
|
f = fopen(filename, "a");
|
|
if(!f) {
|
|
log_err("Could not open logfile %s: %s", filename,
|
|
strerror(errno));
|
|
return;
|
|
}
|
|
logfile = f;
|
|
}
|
|
|
|
void log_thread_set(int* num)
|
|
{
|
|
ub_thread_key_set(logkey, num);
|
|
}
|
|
|
|
void log_ident_set(const char* id)
|
|
{
|
|
ident = id;
|
|
}
|
|
|
|
void
|
|
log_vmsg(int pri, const char* type,
|
|
const char *format, va_list args)
|
|
{
|
|
char message[MAXSYSLOGMSGLEN];
|
|
unsigned int* tid = (unsigned int*)ub_thread_key_get(logkey);
|
|
(void)pri;
|
|
vsnprintf(message, sizeof(message), format, args);
|
|
#ifdef HAVE_SYSLOG_H
|
|
if(log_to_syslog) {
|
|
syslog(pri, "[%d:%x] %s: %s",
|
|
(int)getpid(), tid?*tid:0, type, message);
|
|
return;
|
|
}
|
|
#endif /* HAVE_SYSLOG_H */
|
|
fprintf(logfile, "[%d] %s[%d:%x] %s: %s\n", (int)time(NULL),
|
|
ident, (int)getpid(), tid?*tid:0, type, message);
|
|
fflush(logfile);
|
|
}
|
|
|
|
/**
|
|
* implementation of log_info
|
|
* @param format: format string printf-style.
|
|
*/
|
|
void
|
|
log_info(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, format);
|
|
log_vmsg(LOG_INFO, "info", format, args);
|
|
va_end(args);
|
|
}
|
|
|
|
/**
|
|
* implementation of log_err
|
|
* @param format: format string printf-style.
|
|
*/
|
|
void
|
|
log_err(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, format);
|
|
log_vmsg(LOG_ERR, "error", format, args);
|
|
va_end(args);
|
|
}
|
|
|
|
/**
|
|
* implementation of log_warn
|
|
* @param format: format string printf-style.
|
|
*/
|
|
void
|
|
log_warn(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, format);
|
|
log_vmsg(LOG_WARNING, "warning", format, args);
|
|
va_end(args);
|
|
}
|
|
|
|
/**
|
|
* implementation of fatal_exit
|
|
* @param format: format string printf-style.
|
|
*/
|
|
void
|
|
fatal_exit(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, format);
|
|
log_vmsg(LOG_CRIT, "fatal error", format, args);
|
|
va_end(args);
|
|
exit(1);
|
|
}
|
|
|
|
/**
|
|
* implementation of verbose
|
|
* @param level: verbose level for the message.
|
|
* @param format: format string printf-style.
|
|
*/
|
|
void
|
|
verbose(enum verbosity_value level, const char* format, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, format);
|
|
if(verbosity >= level) {
|
|
if(level == VERB_OPS)
|
|
log_vmsg(LOG_NOTICE, "notice", format, args);
|
|
else if(level == VERB_DETAIL)
|
|
log_vmsg(LOG_INFO, "info", format, args);
|
|
else log_vmsg(LOG_DEBUG, "debug", format, args);
|
|
}
|
|
va_end(args);
|
|
}
|
|
|
|
void
|
|
log_hex(const char* msg, void* data, size_t length)
|
|
{
|
|
size_t i, j;
|
|
uint8_t* data8 = (uint8_t*)data;
|
|
const char* hexchar = "0123456789ABCDEF";
|
|
char buf[1024+1]; /* alloc blocksize hex chars + \0 */
|
|
const size_t blocksize = 1024;
|
|
size_t len;
|
|
|
|
if(length == 0) {
|
|
log_info("%s[%u]", msg, (unsigned)length);
|
|
return;
|
|
}
|
|
|
|
for(i=0; i<length; i+=blocksize/2) {
|
|
len = blocksize/2;
|
|
if(length - i < blocksize/2)
|
|
len = length - i;
|
|
for(j=0; j<len; j++) {
|
|
buf[j*2] = hexchar[ data8[i+j] >> 4 ];
|
|
buf[j*2 + 1] = hexchar[ data8[i+j] & 0xF ];
|
|
}
|
|
buf[len*2] = 0;
|
|
log_info("%s[%u:%u] %.*s", msg, (unsigned)length,
|
|
(unsigned)i, (int)len*2, buf);
|
|
}
|
|
}
|
|
|
|
void log_buf(enum verbosity_value level, const char* msg, ldns_buffer* buf)
|
|
{
|
|
if(verbosity < level)
|
|
return;
|
|
log_hex(msg, ldns_buffer_begin(buf), ldns_buffer_limit(buf));
|
|
}
|