diff --git a/pdns/logger.cc b/pdns/logger.cc index 1766d35ae9a7..994ef4251471 100644 --- a/pdns/logger.cc +++ b/pdns/logger.cc @@ -31,19 +31,34 @@ extern StatBag S; #include "lock.hh" #include "namespaces.hh" -pthread_once_t Logger::s_once; -pthread_key_t Logger::g_loggerKey; - Logger g_log("", LOG_DAEMON); +thread_local Logger::PerThread Logger::t_perThread; + +static Logger::Config& getLoggerConfig() +{ + /* Since the Logger can be called very early, we need to make sure + that the relevant parts are initialized no matter what, which is tricky + because we can't easily control the initialization order, especially with + built-in backends. + t_perThread is thread_local, so it will be initialized when first accessed, + but we need to make sure that the rest of the config is too, and making + it a function-level static variable achieves that, because it will be + initialized the first time we enter this function at the very last. + */ + static Logger::Config config; + return config; +} void Logger::log(const string &msg, Urgency u) { #ifndef RECURSOR bool mustAccount(false); #endif - if(u<=consoleUrgency) { + const auto& config = getLoggerConfig(); + + if(u <= config.consoleUrgency) { char buffer[50] = ""; - if (d_timestamps) { + if (config.d_timestamps) { struct tm tm; time_t t; time(&t); @@ -52,7 +67,7 @@ void Logger::log(const string &msg, Urgency u) } string prefix; - if (d_prefixed) { + if (config.d_prefixed) { switch(u) { case All: prefix = "[all] "; @@ -91,7 +106,7 @@ void Logger::log(const string &msg, Urgency u) mustAccount=true; #endif } - if( u <= d_loglevel && !d_disableSyslog ) { + if( u <= config.d_loglevel && !config.d_disableSyslog ) { syslog(u,"%s",msg.c_str()); #ifndef RECURSOR mustAccount=true; @@ -106,75 +121,101 @@ void Logger::log(const string &msg, Urgency u) void Logger::setLoglevel( Urgency u ) { - d_loglevel = u; + auto& config = getLoggerConfig(); + config.d_loglevel = u; } +void Logger::setFacility(int f) +{ + auto& config = getLoggerConfig(); -void Logger::toConsole(Urgency u) + config.d_facility = f; + open(); +} + +void Logger::setFlag(int f) { - consoleUrgency=u; + auto& config = getLoggerConfig(); + config. flags |= f; + open(); } -void Logger::open() +void Logger::disableSyslog(bool d) { - if(opened) - closelog(); - openlog(name.c_str(),flags,d_facility); - opened=true; + auto& config = getLoggerConfig(); + + config.d_disableSyslog = d; } -void Logger::setName(const string &_name) +void Logger::setTimestamps(bool t) { - name=_name; - open(); + auto& config = getLoggerConfig(); + config.d_timestamps = t; } -void Logger::initKey() +void Logger::setPrefixed(bool p) { - if(pthread_key_create(&g_loggerKey, perThreadDestructor)) - unixDie("Creating thread key for logger"); + auto& config = getLoggerConfig(); + config.d_prefixed = p; } -Logger::Logger(const string &n, int facility) : - name(n), flags(LOG_PID|LOG_NDELAY), d_facility(facility), d_loglevel(Logger::None), - consoleUrgency(Error), opened(false), d_disableSyslog(false) +void Logger::resetFlags() { - if(pthread_once(&s_once, initKey)) - unixDie("Creating thread key for logger"); + auto& config = getLoggerConfig(); + config.flags = 0; open(); +} + +void Logger::toConsole(Urgency u) +{ + auto& config = getLoggerConfig(); + config.consoleUrgency = u; +} + +void Logger::open() +{ + auto& config = getLoggerConfig(); + if(config.opened) { + closelog(); + } + openlog(config.name.c_str(), config.flags, config.d_facility); + config.opened = true; } -Logger& Logger::operator<<(Urgency u) +void Logger::setName(const string &_name) { - getPerThread()->d_urgency=u; - return *this; + auto& config = getLoggerConfig(); + config.name = _name; + open(); } -void Logger::perThreadDestructor(void* buf) +Logger::Logger(const string &n, int facility) { - PerThread* pt = (PerThread*) buf; - delete pt; + auto& config = getLoggerConfig(); + config.name = n; + config.flags = LOG_PID|LOG_NDELAY; + config.d_facility = facility; + + open(); } -Logger::PerThread* Logger::getPerThread() +Logger& Logger::operator<<(Urgency u) { - void *buf=pthread_getspecific(g_loggerKey); - PerThread* ret; - if(buf) - ret = (PerThread*) buf; - else { - ret = new PerThread(); - pthread_setspecific(g_loggerKey, (void*)ret); - } - return ret; + getPerThread().d_urgency = u; + return *this; +} + +Logger::PerThread& Logger::getPerThread() +{ + return t_perThread; } Logger& Logger::operator<<(const string &s) { - PerThread* pt =getPerThread(); - pt->d_output.append(s); + PerThread& pt = getPerThread(); + pt.d_output.append(s); return *this; } @@ -244,11 +285,11 @@ Logger& Logger::operator<<(long i) Logger& Logger::operator<<(ostream & (&)(ostream &)) { - PerThread* pt =getPerThread(); + PerThread& pt = getPerThread(); - log(pt->d_output, pt->d_urgency); - pt->d_output.clear(); - pt->d_urgency=Info; + log(pt.d_output, pt.d_urgency); + pt.d_output.clear(); + pt.d_urgency=Info; return *this; } diff --git a/pdns/logger.hh b/pdns/logger.hh index 3fb97ee0fcf9..2a787d2afaaf 100644 --- a/pdns/logger.hh +++ b/pdns/logger.hh @@ -26,7 +26,6 @@ #include #include #include -#include #include "namespaces.hh" #include "dnsname.hh" @@ -42,36 +41,44 @@ public: enum Urgency {All=32767,Alert=LOG_ALERT, Critical=LOG_CRIT, Error=LOG_ERR, Warning=LOG_WARNING, Notice=LOG_NOTICE,Info=LOG_INFO, Debug=LOG_DEBUG, None=-1}; + struct Config + { + string name; + int flags; + int d_facility; + Urgency d_loglevel{None}; + Urgency consoleUrgency{Error}; + bool opened{false}; + bool d_disableSyslog{false}; + bool d_timestamps{true}; + bool d_prefixed{false}; + }; + /** Log a message. \param msg Message you wish to log \param u Urgency of the message you wish to log */ void log(const string &msg, Urgency u=Notice); - void setFacility(int f){d_facility=f;open();} //!< Choose logging facility - void setFlag(int f){flags|=f;open();} //!< set a syslog flag + void setFacility(int f); //!< Choose logging facility + void setFlag(int f); //!< set a syslog flag void setName(const string &); //! set lower limit of urgency needed for console display. Messages of this urgency, and higher, will be displayed void toConsole(Urgency); void setLoglevel( Urgency ); - void disableSyslog(bool d) { - d_disableSyslog = d; - } + void disableSyslog(bool d); - void setTimestamps(bool t) { - d_timestamps = t; - } + void setTimestamps(bool t); - void setPrefixed(bool p) { - d_prefixed = p; - } + void setPrefixed(bool p); //! Log to a file. void toFile( const string & filename ); - void resetFlags(){flags=0;open();} //!< zero the flags + void resetFlags(); //!< zero the flags + /** Use this to stream to your log, like this: \code g_log<<"This is an informational message"<