unbound/util/log.c
Wouter Wijngaards 4260a18fb1 assertions, zero termination for gethostname, log_hex without malloc.
git-svn-id: file:///svn/unbound/trunk@679 be551aaa-1e26-0410-a405-d3ace91eadb9
2007-10-16 12:26:09 +00:00

253 lines
6.1 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)
{
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 */
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));
}