Browse Source

[trac558] Stage 1 of backing out log4cxx support

The introduction of logging caused problems when building BIND10
on a number of systems because up to date log4cxx support was not
available. (It appears that v0.9.8 is the minimum required, and a
number of distributions only have v0.9.7.)  For this reason, the
logging is being altered (for the moment) to withdraw log4cxx and
to write directly to the console.

The best solution seemed to be to split the basic API and the
implementation and to provide implementations for different logging
systems. (This was entered as ticket 529, but is being done now.)
The current commit leaves the logging system still using log4cxx,
but with the implementation split from the API.
Stephen Morris 14 years ago
parent
commit
f7f035851d

+ 1 - 0
src/lib/log/Makefile.am

@@ -13,6 +13,7 @@ liblog_la_SOURCES += dbglevels.h
 liblog_la_SOURCES += dummylog.h dummylog.cc
 liblog_la_SOURCES += filename.h filename.cc
 liblog_la_SOURCES += logger.cc logger.h
+liblog_la_SOURCES += logger_impl.cc logger_impl.h
 liblog_la_SOURCES += logger_support.cc logger_support.h
 liblog_la_SOURCES += messagedef.cc messagedef.h
 liblog_la_SOURCES += message_dictionary.cc message_dictionary.h

+ 71 - 190
src/lib/log/logger.cc

@@ -19,229 +19,100 @@
 #include <stdarg.h>
 #include <stdio.h>
 
-#include <log4cxx/appender.h>
-#include <log4cxx/basicconfigurator.h>
-#include <log4cxx/patternlayout.h>
-#include <log4cxx/consoleappender.h>
-
-#include <log/root_logger_name.h>
 #include <log/logger.h>
+#include <log/logger_impl.h>
 #include <log/message_dictionary.h>
 #include <log/message_types.h>
+#include <log/root_logger_name.h>
 #include <log/strutil.h>
-#include <log/xdebuglevel.h>
 
 using namespace std;
 
 namespace isc {
 namespace log {
 
-// Static initializations
+// Constructor
 
-bool Logger::init_ = false;
+Logger::Logger(const std::string& name, bool infunc) :
+    loggerptr_(new LoggerImpl(name, infunc))
+{}
 
-// Destructor.  Delete log4cxx stuff if "don't delete" is clear.
+// Destructor.
 
 Logger::~Logger() {
-    if (exit_delete_) {
-        delete loggerptr_;
-    }
+    delete loggerptr_;
 }
 
-// Initialize logger - create a logger as a child of the root logger.  With
-// log4cxx this is assured by naming the logger <parent>.<child>.
+// Get Name of Logger
 
-void
-Logger::initLogger() {
-
-    // Initialize basic logging if not already done.  This is a one-off for
-    // all loggers.
-    if (!init_) {
-
-        // TEMPORARY
-        // Add a suitable console logger to the log4cxx root logger.  (This
-        // is the logger at the root of the log4cxx tree, not the BIND-10 root
-        // logger, which is one level down.)  The chosen format is:
-        //
-        // YYYY-MM-DD hh:mm:ss.sss [logger] SEVERITY: text
-        //
-        // As noted, this is a temporary hack: it is done here to ensure that
-        // a suitable output and output pattern is set.  Future versions of the
-        // software will set this based on configuration data.
-
-        log4cxx::LayoutPtr layout(
-            new log4cxx::PatternLayout(
-                "%d{yyyy-MM-DD HH:mm:ss.SSS} %-5p [%c] %m\n"));
-        log4cxx::AppenderPtr console(
-            new log4cxx::ConsoleAppender(layout));
-        log4cxx::LoggerPtr sys_root_logger = log4cxx::Logger::getRootLogger();
-        sys_root_logger->addAppender(console);
-        
-        // Set the default logging to INFO
-        sys_root_logger->setLevel(log4cxx::Level::getInfo());
-
-        // All static stuff initialized
-        init_ = true;
-    }
-
-    // Initialize this logger.  Name this as to whether the BIND-10 root logger
-    // name has been set.  (If not, this mucks up the hierarchy :-( ).
-    string root_name = RootLoggerName::getName();
-    if (root_name.empty() || (name_ == root_name)) {
-        loggerptr_ = new log4cxx::LoggerPtr(log4cxx::Logger::getLogger(name_));
-    }
-    else {
-        loggerptr_ = new log4cxx::LoggerPtr(
-            log4cxx::Logger::getLogger(root_name + "." + name_)
-        );
-    }
+std::string
+Logger::getName() {
+    return (loggerptr_->getName());
 }
 
-
-// Set the severity for logging.  There is a 1:1 mapping between the logging
-// severity and the log4cxx logging levels, apart from DEBUG.
-//
-// In log4cxx, each of the logging levels (DEBUG, INFO, WARN etc.) has a numeric
-// value.  The level is set to one of these and any numeric level equal to or
-// above it that is reported.  For example INFO has a value of 20000 and ERROR
-// a value of 40000. So if a message of WARN severity (= 30000) is logged, it is
-// not logged when the logger's severity level is ERROR (as 30000 !>= 40000).
-// It is reported if the logger's severity level is set to WARN (as 30000 >=
-/// 30000) or INFO (30000 >= 20000).
-//
-// This gives a simple system for handling different debug levels.  The debug
-// level is a number between 0 and 99, with 0 being least verbose and 99 the
-// most.  To implement this seamlessly, when DEBUG is set, the numeric value
-// of the logging level is actually set to (DEBUG - debug-level).  Similarly
-// messages of level "n" are logged at a logging level of (DEBUG - n).  Thus if
-// the logging level is set to DEBUG and the debug level set to 25, the actual
-// level set is 10000 - 25 = 99975.
-//
-// Attempting to log a debug message of level 26 is an attempt to log a message
-// of level 10000 - 26 = 9974.  As 9974 !>= 9975, it is not logged.  A
-// message of level 25 is, because 9975 >= 9975.
-//
-// The extended set of logging levels is implemented by the XDebugLevel class.
+// Set the severity for logging.
 
 void
-Logger::setSeverity(Severity severity, int dbglevel) {
-    switch (severity) {
-        case NONE:
-            getLogger()->setLevel(log4cxx::Level::getOff());
-            break;
-
-        case FATAL:
-            getLogger()->setLevel(log4cxx::Level::getFatal());
-            break;
-
-        case ERROR:
-            getLogger()->setLevel(log4cxx::Level::getError());
-            break;
-
-        case WARN:
-            getLogger()->setLevel(log4cxx::Level::getWarn());
-            break;
-
-        case INFO:
-            getLogger()->setLevel(log4cxx::Level::getInfo());
-            break;
-
-        case DEBUG:
-            getLogger()->setLevel(
-                log4cxx::XDebugLevel::getExtendedDebug(dbglevel));
-            break;
-
-        // Will get here for DEFAULT or any other value.  This disables the
-        // logger's own severity and it defaults to the severity of the parent
-        // logger.
-        default:
-            getLogger()->setLevel(0);
-    }
+Logger::setSeverity(isc::log::Severity severity, int dbglevel) {
+    loggerptr_->setSeverity(severity, dbglevel);
 }
 
-// Convert between numeric log4cxx logging level and BIND-10 logging severity.
-
-Logger::Severity
-Logger::convertLevel(int value) const {
-
-    // The order is optimised.  This is only likely to be called when testing
-    // for writing debug messages, so the check for DEBUG_INT is first.
-    if (value <= log4cxx::Level::DEBUG_INT) {
-        return (DEBUG);
-    } else if (value <= log4cxx::Level::INFO_INT) {
-        return (INFO);
-    } else if (value <= log4cxx::Level::WARN_INT) {
-        return (WARN);
-    } else if (value <= log4cxx::Level::ERROR_INT) {
-        return (ERROR);
-    } else if (value <= log4cxx::Level::FATAL_INT) {
-        return (FATAL);
-    } else {
-        return (NONE);
-    }
-}
+// Return the severity of the logger.
 
+isc::log::Severity
+Logger::getSeverity() {
+    return (loggerptr_->getSeverity());
+}
 
-// Return the logging severity associated with this logger.
+// Get Effective Severity Level for Logger
 
-Logger::Severity
-Logger::getSeverityCommon(const log4cxx::LoggerPtr& ptrlogger,
-    bool check_parent) const {
+isc::log::Severity
+Logger::getEffectiveSeverity() {
+    return (loggerptr_->getEffectiveSeverity());
+}
 
-    log4cxx::LevelPtr level = ptrlogger->getLevel();
-    if (level == log4cxx::LevelPtr()) {
+// Debug level (only relevant if messages of severity DEBUG are being logged).
 
-        // Null level returned, logging should be that of the parent.
+int
+Logger::getDebugLevel() {
+    return (loggerptr_->getDebugLevel());
+}
 
-        if (check_parent) {
-            log4cxx::LoggerPtr parent = ptrlogger->getParent();
-            if (parent == log4cxx::LoggerPtr()) {
+// Check on the current severity settings
 
-                // No parent, so reached the end of the chain.  Return INFO
-                // severity.
-                return (INFO);
-            }
-            else {
-                return getSeverityCommon(parent, check_parent);
-            }
-        }
-        else {
-            return (DEFAULT);
-        }
-    } else {
-        return convertLevel(level->toInt());
-    }
+bool
+Logger::isDebugEnabled(int dbglevel) {
+    return (loggerptr_->isDebugEnabled(dbglevel));
 }
 
+bool
+Logger::isInfoEnabled() {
+    return (loggerptr_->isInfoEnabled());
+}
 
-// Get the debug level.  This returns 0 unless the severity is DEBUG.
+bool
+Logger::isWarnEnabled() {
+    return (loggerptr_->isWarnEnabled());
+}
 
-int
-Logger::getDebugLevel() {
+bool
+Logger::isErrorEnabled() {
+    return (loggerptr_->isErrorEnabled());
+}
 
-    log4cxx::LevelPtr level = getLogger()->getLevel();
-    if (level == log4cxx::LevelPtr()) {
-
-        // Null pointer returned, logging should be that of the parent.
-        return (0);
-        
-    } else {
-        int severity = level->toInt();
-        if (severity <= log4cxx::Level::DEBUG_INT) {
-            return (log4cxx::Level::DEBUG_INT - severity);
-        }
-        else {
-            return (0);
-        }
-    }
+bool
+Logger::isFatalEnabled() {
+    return (loggerptr_->isFatalEnabled());
 }
 
-// Log an error message:
-// Common code.  Owing to the use of variable arguments, this must be inline
-// (hence the definition of the macro).  Also note that it expects that the
-// message buffer "message" is declared in the compilation unit.
+// Format a message: looks up the message text in the dictionary and formats
+// it, replacing tokens with arguments.
+//
+// Owing to the use of variable arguments, this must be inline (hence the
+// definition of the macro).  Also note that it expects that the message buffer
+// "message" is declared in the compilation unit.
 
-#define MESSAGE_SIZE (256)
+#define MESSAGE_SIZE (512)
 
 #define FORMAT_MESSAGE(message) \
     { \
@@ -262,7 +133,7 @@ Logger::debug(int dbglevel, isc::log::MessageID ident, ...) {
     if (isDebugEnabled(dbglevel)) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        LOG4CXX_DEBUG(getLogger(), ident << ", " << message);
+        loggerptr_->debug(ident, message);
     }
 }
 
@@ -271,7 +142,7 @@ Logger::info(isc::log::MessageID ident, ...) {
     if (isInfoEnabled()) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        LOG4CXX_INFO(getLogger(), ident << ", " << message);
+        loggerptr_->info(ident, message);
     }
 }
 
@@ -280,7 +151,7 @@ Logger::warn(isc::log::MessageID ident, ...) {
     if (isWarnEnabled()) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        LOG4CXX_WARN(getLogger(), ident << ", " << message);
+        loggerptr_->warn(ident, message);
     }
 }
 
@@ -289,7 +160,7 @@ Logger::error(isc::log::MessageID ident, ...) {
     if (isErrorEnabled()) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        LOG4CXX_ERROR(getLogger(), ident << ", " << message);
+        loggerptr_->error(ident, message);
     }
 }
 
@@ -298,10 +169,20 @@ Logger::fatal(isc::log::MessageID ident, ...) {
     if (isFatalEnabled()) {
         char message[MESSAGE_SIZE];
         FORMAT_MESSAGE(message);
-        LOG4CXX_FATAL(getLogger(), ident << ", " << message);
+        loggerptr_->fatal(ident, message);
     }
 }
 
+// Protected methods (used for testing)
+
+bool Logger::operator==(const Logger& other) {
+    return (*loggerptr_ == *other.loggerptr_);
+}
+
+bool Logger::isInitialized() {
+    return loggerptr_->isInitialized();
+}
+
 
 } // namespace log
 } // namespace isc

+ 54 - 163
src/lib/log/logger.h

@@ -19,29 +19,37 @@
 
 #include <cstdlib>
 #include <string>
-#include <boost/lexical_cast.hpp>
-#include <log4cxx/logger.h>
 
 #include <log/dbglevels.h>
+#include <log/logger_levels.h>
 #include <log/message_types.h>
 
 namespace isc {
 namespace log {
 
+/// \brief Logging API
+///
+/// This module forms the interface into the logging subsystem. Features of the
+/// system and its implementation are:
+///
+/// # Multiple logging objects can be created, each given a name; those with the
+///   same name share characteristics (like destination, level being logged
+///   etc.)
+/// # Messages can be logged at severity levels of FATAL, ERROR, WARN, INFO or
+///   DEBUG.  The DEBUG level has further sub-levels numbered 0 (least
+///   informative) to 99 (most informative).
+/// # Each logger has a severity level set associated with it.  When a message
+///   is logged, it is output only if it is logged at a level equal to the
+///   logger severity level or greater, e.g. if the logger's severity is WARN,
+///   only messages logged at WARN, ERROR or FATAL will be output.
+/// # Messages are identified by message identifiers, which are keys into a
+///   message dictionary.
+
+class LoggerImpl;   // Forward declaration of the implementation class
+
 class Logger {
 public:
 
-    /// \brief Severity Levels
-    typedef enum {
-        DEFAULT,    // Default to logging level of parent
-        DEBUG,
-        INFO,
-        WARN,
-        ERROR,
-        FATAL,
-        NONE        // Disable logging
-    } Severity;
-
     /// \brief Constructor
     ///
     /// Creates/attaches to a logger of a specific name.
@@ -50,64 +58,40 @@ public:
     /// this creates an instance of the root logger; otherwise it creates a
     /// child of the root logger.
     ///
-    /// \param exit_delete This argument is present to get round a bug in
-    /// log4cxx.  If a log4cxx logger is declared outside an execution unit, it
-    /// is not deleted until the program runs down.  At that point all such
-    /// objects - including internal log4cxx objects - are deleted.  However,
-    /// there seems to be a bug in log4cxx where the way that such objects are
-    /// destroyed causes a MutexException to be thrown (this is described in
+    /// \param infunc This argument is present to get round a bug in some
+    /// implementations of the logging system.  If the logger is declared in
+    /// a function (such that it will be deleted when the function exits,
+    /// before the program ends), set this true.  If declared outside a
+    /// function (such that it gets deleted during program rundown), set false
+    /// (the default).\n
+    /// \n
+    /// The problems encountered was that during program rundown, one logging
+    /// implementation (log4cxx) threw a MutexException (this is described in
     /// https://issues.apache.org/jira/browse/LOGCXX-322).  As this only occurs
     /// during program rundown, the issue is not serious - it just looks bad to
     /// have the program crash instead of shut down cleanly.\n
     /// \n
-    /// The original implementation of the isc::log::Logger had as a member a
-    /// log4cxx logger (actually a LoggerPtr).  If the isc:: Logger was declared
-    /// statically, when it was destroyed at the end of the program the internal
-    /// LoggerPtr was destroyed, which triggered the problem.  The problem did
-    /// not occur if the isc::log::Logger was created on the stack.  To get
-    /// round this, the internal LoggerPtr is now created dynamically.  The
-    /// exit_delete argument controls its destruction: if true, it is destroyed
-    /// in the ISC Logger destructor.  If false, it is not.\n
+    /// If log4cxx is chosen as the implementation, this flag controls the
+    /// deletion of the underlying log4cxx data structures when the logger is
+    /// deleted.  Setting it false for externally-declared loggers inhibits
+    /// their deletion; so at program exit the memory is not reclaimed during
+    /// program rundown, only when the process is delected.  Setting it true
+    /// for loggers that will be deleted in the normal running of the program
+    /// enables their deletion - which causes no issues as the problem only
+    /// manifests itself during program rundown.
     /// \n
-    /// When creating an isc::log::Logger on the stack, the argument should be
-    /// false (the default); when the Logger is destroyed, all the internal
-    /// log4cxx objects are destroyed.  As only the logger (and not the internal
-    /// log4cxx data structures are being destroyed), all is well.  However,
-    /// when creating the logger statically, the argument should be false.  This
-    /// means that the log4cxx objects are not destroyed at program rundown;
-    /// instead memory is reclaimed and files are closed when the process is
-    /// destroyed, something that does not trigger the bug.
-    Logger(const std::string& name, bool exit_delete = false) :
-        loggerptr_(), name_(name), exit_delete_(exit_delete)
-    {}
+    /// The falg has no effect on non-log4cxx implementations.
+    Logger(const std::string& name, bool infunc = false);
 
 
     /// \brief Destructor
     virtual ~Logger();
 
 
-    /// \brief Configure Options
-    ///
-    /// TEMPORARY: Pass in the command-line options to set the logging severity
-    /// for the root logger.  Future versions of the logger will get this
-    /// information from the configuration database.
-    ///
-    /// \param severity Severity level to log
-    /// \param dbglevel If the severity is DEBUG, this is the debug level.
-    /// This can be in the range 1 to 100 and controls the verbosity.  A value
-    /// outside these limits is silently coerced to the nearest boundary.
-    /// \param local_file If provided, the name of a message file to read in and
-    /// supersede one or more of the current messages.
-    static void runTimeInit(Severity severity = INFO, int dbglevel = 1,
-        const char* local_file = NULL);
-
-
     /// \brief Get Name of Logger
     ///
     /// \return The full name of the logger (including the root name)
-    virtual std::string getName() {
-        return getLogger()->getName();
-    }
+    virtual std::string getName();
 
 
     /// \brief Set Severity Level for Logger
@@ -119,25 +103,22 @@ public:
     /// \param dbglevel If the severity is DEBUG, this is the debug level.
     /// This can be in the range 1 to 100 and controls the verbosity.  A value
     /// outside these limits is silently coerced to the nearest boundary.
-    virtual void setSeverity(Severity severity, int dbglevel = 1);
+    virtual void setSeverity(isc::log::Severity severity, int dbglevel = 1);
 
 
     /// \brief Get Severity Level for Logger
     ///
     /// \return The current logging level of this logger.  In most cases though,
     /// the effective logging level is what is required.
-    virtual Severity getSeverity() {
-        return getSeverityCommon(getLogger(), false);
-    }
+    virtual isc::log::Severity getSeverity();
+
 
     /// \brief Get Effective Severity Level for Logger
     ///
     /// \return The effective severity level of the logger.  This is the same
     /// as getSeverity() if the logger has a severity level set, but otherwise
     /// is the severity of the parent.
-    virtual Severity getEffectiveSeverity() {
-        return getSeverityCommon(getLogger(), true);
-    }
+    virtual isc::log::Severity getEffectiveSeverity();
 
 
     /// \brief Return DEBUG Level
@@ -152,35 +133,23 @@ public:
     /// \param dbglevel Level for which debugging is checked.  Debugging is
     /// enabled only if the logger has DEBUG enabled and if the dbglevel
     /// checked is less than or equal to the debug level set for the logger.
-    virtual bool
-    isDebugEnabled(int dbglevel = MIN_DEBUG_LEVEL) {
-        return (getLogger()->getEffectiveLevel()->toInt() <=
-            (log4cxx::Level::DEBUG_INT - dbglevel));
-    }
+    virtual bool isDebugEnabled(int dbglevel = MIN_DEBUG_LEVEL);
 
 
     /// \brief Is INFO Enabled?
-    virtual bool isInfoEnabled() {
-        return (getLogger()->isInfoEnabled());
-    }
+    virtual bool isInfoEnabled();
 
 
     /// \brief Is WARNING Enabled?
-    virtual bool isWarnEnabled() {
-        return (getLogger()->isWarnEnabled());
-    }
+    virtual bool isWarnEnabled();
 
 
     /// \brief Is ERROR Enabled?
-    virtual bool isErrorEnabled() {
-        return (getLogger()->isErrorEnabled());
-    }
+    virtual bool isErrorEnabled();
 
 
     /// \brief Is FATAL Enabled?
-    virtual bool isFatalEnabled() {
-        return (getLogger()->isFatalEnabled());
-    }
+    virtual bool isFatalEnabled();
 
 
     /// \brief Output Debug Message
@@ -219,7 +188,6 @@ public:
     /// \param ... Optional arguments for the message.
     void fatal(MessageID ident, ...);
 
-
 protected:
 
     /// \brief Equality
@@ -228,96 +196,19 @@ protected:
     /// (This method is principally for testing.)
     ///
     /// \return true if the logger objects are instances of the same logger.
-    bool operator==(const Logger& other) const {
-        return (*loggerptr_ == *other.loggerptr_);
-    }
-
+    bool operator==(const Logger& other);
 
+    
     /// \brief Logger Initialized
     ///
     /// Check that the logger has been properly initialized.  (This method
     /// is principally for testing.)
     ///
     /// \return true if this logger object has been initialized.
-    bool isInitialized() const {
-        return (loggerptr_ != NULL);
-    }
-
-
-    /// \brief Get Severity Level for Logger
-    ///
-    /// This is common code for getSeverity() and getEffectiveSeverity() -
-    /// it returns the severity of the logger; if not set (and the check_parent)
-    /// flag is set, it searches up the parent-child tree until a severity
-    /// level is found and uses that.
-    ///
-    /// \param ptrlogger Pointer to the log4cxx logger to check.
-    /// \param check_parent true to search up the tree, false to return the
-    /// current level.
-    ///
-    /// \return The effective severity level of the logger.  This is the same
-    /// as getSeverity() if the logger has a severity level set, but otherwise
-    /// is the severity of the parent.
-    Logger::Severity getSeverityCommon(const log4cxx::LoggerPtr& ptrlogger,
-        bool check_parent) const;
-
-
-    /// \brief Convert Between BIND-10 and log4cxx Logging Levels
-    ///
-    /// Converts between the numeric value of the log4cxx logging level
-    /// and the BIND-10 severity level.
-    ///
-    /// \param value log4cxx numeric logging level
-    ///
-    /// \return BIND-10 logging severity
-    Severity convertLevel(int value) const;
-
-
-    /// \brief Initialize log4cxx Logger
-    ///
-    /// Creates the log4cxx logger used internally.  A function is provided for
-    /// this so that the creation does not take place when this Logger object
-    /// is created but when it is used.  As the latter occurs in executable
-    /// code but the former can occur during initialization, this order
-    /// guarantees that anything that is statically initialized has completed
-    /// its initialization by the time the logger is used.
-    void initLogger();
-
-
-    /// \brief Return log4cxx Logger
-    ///
-    /// Returns the log4cxx logger, initializing it if not already initialized.
-    ///
-    /// \return Loggerptr object
-    log4cxx::LoggerPtr& getLogger() {
-        if (loggerptr_ == NULL) {
-            initLogger();
-        }
-        return *loggerptr_;
-    }
-
-
-    /// \brief Read Local Message File
-    ///
-    /// Reads a local message file into the global dictionary, replacing any
-    /// definitions there.  Any messages found in the local file that do not
-    /// replace ones in the global dictionary are listed.
-    ///
-    /// \param file Local message file to be read.
-    static void readLocalMessageFile(const char* file);
+    bool isInitialized();
 
 private:
-    // Note that loggerptr_ is a pointer to a LoggerPtr, which is itself a
-    // pointer to the underlying log4cxx logger.  This is due to the problems
-    // with memory deletion on program exit, explained in the comments for
-    // the "exit_delete" parameter in this class's constructor.
-
-    log4cxx::LoggerPtr*  loggerptr_;    ///< Pointer to the underlying logger
-    std::string          name_;         ///< Name of this logger]
-    bool                 exit_delete_;  ///< Delete loggerptr_ on exit?
-
-    // NOTE - THIS IS A PLACE HOLDER
-    static bool         init_;      ///< Set true when initialized
+    LoggerImpl*     loggerptr_;     /// Pointer to the underlying logger
 };
 
 } // namespace log

+ 243 - 0
src/lib/log/logger_impl.cc

@@ -0,0 +1,243 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE
+
+// $Id$
+
+#include <iostream>
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <log4cxx/appender.h>
+#include <log4cxx/basicconfigurator.h>
+#include <log4cxx/patternlayout.h>
+#include <log4cxx/consoleappender.h>
+
+#include <log/root_logger_name.h>
+#include <log/logger.h>
+#include <log/logger_impl.h>
+#include <log/message_dictionary.h>
+#include <log/message_types.h>
+#include <log/strutil.h>
+#include <log/xdebuglevel.h>
+
+using namespace std;
+
+namespace isc {
+namespace log {
+
+// Static initializations
+
+bool LoggerImpl::init_ = false;
+
+// Destructor.  Delete log4cxx stuff if "don't delete" is clear.
+
+LoggerImpl::~LoggerImpl() {
+    if (exit_delete_) {
+        delete loggerptr_;
+    }
+}
+
+// Initialize logger - create a logger as a child of the root logger.  With
+// log4cxx this is assured by naming the logger <parent>.<child>.
+
+void
+LoggerImpl::initLogger() {
+
+    // Initialize basic logging if not already done.  This is a one-off for
+    // all loggers.
+    if (!init_) {
+
+        // TEMPORARY
+        // Add a suitable console logger to the log4cxx root logger.  (This
+        // is the logger at the root of the log4cxx tree, not the BIND-10 root
+        // logger, which is one level down.)  The chosen format is:
+        //
+        // YYYY-MM-DD hh:mm:ss.sss [logger] SEVERITY: text
+        //
+        // As noted, this is a temporary hack: it is done here to ensure that
+        // a suitable output and output pattern is set.  Future versions of the
+        // software will set this based on configuration data.
+
+        log4cxx::LayoutPtr layout(
+            new log4cxx::PatternLayout(
+                "%d{yyyy-MM-DD HH:mm:ss.SSS} %-5p [%c] %m\n"));
+        log4cxx::AppenderPtr console(
+            new log4cxx::ConsoleAppender(layout));
+        log4cxx::LoggerPtr sys_root_logger = log4cxx::Logger::getRootLogger();
+        sys_root_logger->addAppender(console);
+        
+        // Set the default logging to INFO
+        sys_root_logger->setLevel(log4cxx::Level::getInfo());
+
+        // All static stuff initialized
+        init_ = true;
+    }
+
+    // Initialize this logger.  Name this as to whether the BIND-10 root logger
+    // name has been set.  (If not, this mucks up the hierarchy :-( ).
+    string root_name = RootLoggerName::getName();
+    if (root_name.empty() || (name_ == root_name)) {
+        loggerptr_ = new log4cxx::LoggerPtr(log4cxx::Logger::getLogger(name_));
+    }
+    else {
+        loggerptr_ = new log4cxx::LoggerPtr(
+            log4cxx::Logger::getLogger(root_name + "." + name_)
+        );
+    }
+}
+
+
+// Set the severity for logging.  There is a 1:1 mapping between the logging
+// severity and the log4cxx logging levels, apart from DEBUG.
+//
+// In log4cxx, each of the logging levels (DEBUG, INFO, WARN etc.) has a numeric
+// value.  The level is set to one of these and any numeric level equal to or
+// above it that is reported.  For example INFO has a value of 20000 and ERROR
+// a value of 40000. So if a message of WARN severity (= 30000) is logged, it is
+// not logged when the logger's severity level is ERROR (as 30000 !>= 40000).
+// It is reported if the logger's severity level is set to WARN (as 30000 >=
+/// 30000) or INFO (30000 >= 20000).
+//
+// This gives a simple system for handling different debug levels.  The debug
+// level is a number between 0 and 99, with 0 being least verbose and 99 the
+// most.  To implement this seamlessly, when DEBUG is set, the numeric value
+// of the logging level is actually set to (DEBUG - debug-level).  Similarly
+// messages of level "n" are logged at a logging level of (DEBUG - n).  Thus if
+// the logging level is set to DEBUG and the debug level set to 25, the actual
+// level set is 10000 - 25 = 99975.
+//
+// Attempting to log a debug message of level 26 is an attempt to log a message
+// of level 10000 - 26 = 9974.  As 9974 !>= 9975, it is not logged.  A
+// message of level 25 is, because 9975 >= 9975.
+//
+// The extended set of logging levels is implemented by the XDebugLevel class.
+
+void
+LoggerImpl::setSeverity(isc::log::Severity severity, int dbglevel) {
+    switch (severity) {
+        case NONE:
+            getLogger()->setLevel(log4cxx::Level::getOff());
+            break;
+
+        case FATAL:
+            getLogger()->setLevel(log4cxx::Level::getFatal());
+            break;
+
+        case ERROR:
+            getLogger()->setLevel(log4cxx::Level::getError());
+            break;
+
+        case WARN:
+            getLogger()->setLevel(log4cxx::Level::getWarn());
+            break;
+
+        case INFO:
+            getLogger()->setLevel(log4cxx::Level::getInfo());
+            break;
+
+        case DEBUG:
+            getLogger()->setLevel(
+                log4cxx::XDebugLevel::getExtendedDebug(dbglevel));
+            break;
+
+        // Will get here for DEFAULT or any other value.  This disables the
+        // logger's own severity and it defaults to the severity of the parent
+        // logger.
+        default:
+            getLogger()->setLevel(0);
+    }
+}
+
+// Convert between numeric log4cxx logging level and BIND-10 logging severity.
+
+isc::log::Severity
+LoggerImpl::convertLevel(int value) {
+
+    // The order is optimised.  This is only likely to be called when testing
+    // for writing debug messages, so the check for DEBUG_INT is first.
+    if (value <= log4cxx::Level::DEBUG_INT) {
+        return (DEBUG);
+    } else if (value <= log4cxx::Level::INFO_INT) {
+        return (INFO);
+    } else if (value <= log4cxx::Level::WARN_INT) {
+        return (WARN);
+    } else if (value <= log4cxx::Level::ERROR_INT) {
+        return (ERROR);
+    } else if (value <= log4cxx::Level::FATAL_INT) {
+        return (FATAL);
+    } else {
+        return (NONE);
+    }
+}
+
+
+// Return the logging severity associated with this logger.
+
+isc::log::Severity
+LoggerImpl::getSeverityCommon(const log4cxx::LoggerPtr& ptrlogger,
+    bool check_parent) {
+
+    log4cxx::LevelPtr level = ptrlogger->getLevel();
+    if (level == log4cxx::LevelPtr()) {
+
+        // Null level returned, logging should be that of the parent.
+
+        if (check_parent) {
+            log4cxx::LoggerPtr parent = ptrlogger->getParent();
+            if (parent == log4cxx::LoggerPtr()) {
+
+                // No parent, so reached the end of the chain.  Return INFO
+                // severity.
+                return (INFO);
+            }
+            else {
+                return getSeverityCommon(parent, check_parent);
+            }
+        }
+        else {
+            return (DEFAULT);
+        }
+    } else {
+        return convertLevel(level->toInt());
+    }
+}
+
+
+// Get the debug level.  This returns 0 unless the severity is DEBUG.
+
+int
+LoggerImpl::getDebugLevel() {
+
+    log4cxx::LevelPtr level = getLogger()->getLevel();
+    if (level == log4cxx::LevelPtr()) {
+
+        // Null pointer returned, logging should be that of the parent.
+        return (0);
+        
+    } else {
+        int severity = level->toInt();
+        if (severity <= log4cxx::Level::DEBUG_INT) {
+            return (log4cxx::Level::DEBUG_INT - severity);
+        }
+        else {
+            return (0);
+        }
+    }
+}
+
+
+
+} // namespace log
+} // namespace isc

+ 310 - 0
src/lib/log/logger_impl.h

@@ -0,0 +1,310 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __LOGGER_IMPL_H
+#define __LOGGER_IMPL_H
+
+#include <cstdlib>
+#include <string>
+#include <boost/lexical_cast.hpp>
+#include <log4cxx/logger.h>
+#include <log4cxx/logger.h>
+
+#include <log/dbglevels.h>
+#include <log/logger.h>
+#include <log/message_types.h>
+
+namespace isc {
+namespace log {
+
+/// \brief Log4cxx Logger Implementation
+///
+/// The logger uses a "pimpl" idiom for implementation, where the base logger
+/// class contains little more than a pointer to the implementation class, and
+/// all actions are carried out by the latter.  This class is an implementation
+/// class interfacing to the log4cxx logging system.
+
+class LoggerImpl {
+public:
+
+    /// \brief Constructor
+    ///
+    /// Creates/attaches to a logger of a specific name.
+    ///
+    /// \param name Name of the logger.  If the name is that of the root name,
+    /// this creates an instance of the root logger; otherwise it creates a
+    /// child of the root logger.
+    ///
+    /// \param exit_delete This argument is present to get round a bug in
+    /// log4cxx.  If a log4cxx logger is declared outside an execution unit, it
+    /// is not deleted until the program runs down.  At that point all such
+    /// objects - including internal log4cxx objects - are deleted.  However,
+    /// there seems to be a bug in log4cxx where the way that such objects are
+    /// destroyed causes a MutexException to be thrown (this is described in
+    /// https://issues.apache.org/jira/browse/LOGCXX-322).  As this only occurs
+    /// during program rundown, the issue is not serious - it just looks bad to
+    /// have the program crash instead of shut down cleanly.\n
+    /// \n
+    /// The original implementation of the isc::log::Logger had as a member a
+    /// log4cxx logger (actually a LoggerPtr).  If the isc:: Logger was declared
+    /// statically, when it was destroyed at the end of the program the internal
+    /// LoggerPtr was destroyed, which triggered the problem.  The problem did
+    /// not occur if the isc::log::Logger was created on the stack.  To get
+    /// round this, the internal LoggerPtr is now created dynamically.  The
+    /// exit_delete argument controls its destruction: if true, it is destroyed
+    /// in the ISC Logger destructor.  If false, it is not.\n
+    /// \n
+    /// When creating an isc::log::Logger on the stack, the argument should be
+    /// false (the default); when the Logger is destroyed, all the internal
+    /// log4cxx objects are destroyed.  As only the logger (and not the internal
+    /// log4cxx data structures are being destroyed), all is well.  However,
+    /// when creating the logger statically, the argument should be false.  This
+    /// means that the log4cxx objects are not destroyed at program rundown;
+    /// instead memory is reclaimed and files are closed when the process is
+    /// destroyed, something that does not trigger the bug.
+    LoggerImpl(const std::string& name, bool exit_delete = false) :
+        loggerptr_(NULL), name_(name), exit_delete_(exit_delete)
+    {}
+
+
+    /// \brief Destructor
+    virtual ~LoggerImpl();
+
+
+    /// \brief Get the full name of the logger (including the root name)
+    virtual std::string getName() {
+        return (getLogger()->getName());
+    }
+
+
+    /// \brief Set Severity Level for Logger
+    ///
+    /// Sets the level at which this logger will log messages.  If none is set,
+    /// the level is inherited from the parent.
+    ///
+    /// \param severity Severity level to log
+    /// \param dbglevel If the severity is DEBUG, this is the debug level.
+    /// This can be in the range 1 to 100 and controls the verbosity.  A value
+    /// outside these limits is silently coerced to the nearest boundary.
+    virtual void setSeverity(isc::log::Severity severity, int dbglevel = 1);
+
+
+    /// \brief Get Severity Level for Logger
+    ///
+    /// \return The current logging level of this logger.  In most cases though,
+    /// the effective logging level is what is required.
+    virtual isc::log::Severity getSeverity() {
+        return getSeverityCommon(getLogger(), false);
+    }
+
+
+    /// \brief Get Effective Severity Level for Logger
+    ///
+    /// \return The effective severity level of the logger.  This is the same
+    /// as getSeverity() if the logger has a severity level set, but otherwise
+    /// is the severity of the parent.
+    virtual isc::log::Severity getEffectiveSeverity() {
+        return getSeverityCommon(getLogger(), true);
+    }
+
+
+    /// \brief Return DEBUG Level
+    ///
+    /// \return Current setting of debug level.  This is returned regardless of
+    /// whether the
+    virtual int getDebugLevel();
+
+
+    /// \brief Returns if Debug Message Should Be Output
+    ///
+    /// \param dbglevel Level for which debugging is checked.  Debugging is
+    /// enabled only if the logger has DEBUG enabled and if the dbglevel
+    /// checked is less than or equal to the debug level set for the logger.
+    virtual bool
+    isDebugEnabled(int dbglevel = MIN_DEBUG_LEVEL) {
+        return (getLogger()->getEffectiveLevel()->toInt() <=
+            (log4cxx::Level::DEBUG_INT - dbglevel));
+    }
+
+
+    /// \brief Is INFO Enabled?
+    virtual bool isInfoEnabled() {
+        return (getLogger()->isInfoEnabled());
+    }
+
+
+    /// \brief Is WARNING Enabled?
+    virtual bool isWarnEnabled() {
+        return (getLogger()->isWarnEnabled());
+    }
+
+
+    /// \brief Is ERROR Enabled?
+    virtual bool isErrorEnabled() {
+        return (getLogger()->isErrorEnabled());
+    }
+
+
+    /// \brief Is FATAL Enabled?
+    virtual bool isFatalEnabled() {
+        return (getLogger()->isFatalEnabled());
+    }
+
+
+    /// \brief Output Debug Message
+    ///
+    /// \param ident Message identification.
+    /// \param text Text to log
+    void debug(MessageID ident, const char* text) {
+        LOG4CXX_DEBUG(getLogger(), ident << ", " << text);
+    }
+
+
+    /// \brief Output Informational Message
+    ///
+    /// \param ident Message identification.
+    /// \param text Text to log
+    void info(MessageID ident, const char* text) {
+        LOG4CXX_INFO(getLogger(), ident << ", " << text);
+    }
+
+
+    /// \brief Output Warning Message
+    ///
+    /// \param ident Message identification.
+    /// \param text Text to log
+    void warn(MessageID ident, const char* text) {
+        LOG4CXX_WARN(getLogger(), ident << ", " << text);
+    }
+
+
+    /// \brief Output Error Message
+    ///
+    /// \param ident Message identification.
+    /// \param text Text to log
+    void error(MessageID ident, const char* text) {
+        LOG4CXX_ERROR(getLogger(), ident << ", " << text);
+    }
+
+
+    /// \brief Output Fatal Message
+    ///
+    /// \param ident Message identification.
+    /// \param text Text to log
+    void fatal(MessageID ident, const char* text) {
+        LOG4CXX_FATAL(getLogger(), ident << ", " << text);
+    }
+
+    //@{
+    /// \brief Testing Methods
+    ///
+    /// The next set of methods are used in testing.  As they are accessed from
+    /// the main logger class, they must be public.
+
+    /// \brief Equality
+    ///
+    /// Check if two instances of this logger refer to the same stream.
+    /// (This method is principally for testing.)
+    ///
+    /// \return true if the logger objects are instances of the same logger.
+    bool operator==(const LoggerImpl& other) {
+        return (*loggerptr_ == *other.loggerptr_);
+    }
+
+
+    /// \brief Logger Initialized
+    ///
+    /// Check that the logger has been properly initialized.  (This method
+    /// is principally for testing.)
+    ///
+    /// \return true if this logger object has been initialized.
+    bool isInitialized() {
+        return (loggerptr_ != NULL);
+    }
+
+    //@}
+
+protected:
+
+    /// \brief Convert Between BIND-10 and log4cxx Logging Levels
+    ///
+    /// This method is marked protected to allow for unit testing.
+    ///
+    /// \param value log4cxx numeric logging level
+    ///
+    /// \return BIND-10 logging severity
+    isc::log::Severity convertLevel(int value);
+
+private:
+
+    /// \brief Get Severity Level for Logger
+    ///
+    /// This is common code for getSeverity() and getEffectiveSeverity() -
+    /// it returns the severity of the logger; if not set (and the check_parent)
+    /// flag is set, it searches up the parent-child tree until a severity
+    /// level is found and uses that.
+    ///
+    /// \param ptrlogger Pointer to the log4cxx logger to check.
+    /// \param check_parent true to search up the tree, false to return the
+    /// current level.
+    ///
+    /// \return The effective severity level of the logger.  This is the same
+    /// as getSeverity() if the logger has a severity level set, but otherwise
+    /// is the severity of the parent.
+    isc::log::Severity getSeverityCommon(const log4cxx::LoggerPtr& ptrlogger,
+        bool check_parent);
+
+
+
+    /// \brief Initialize log4cxx Logger
+    ///
+    /// Creates the log4cxx logger used internally.  A function is provided for
+    /// this so that the creation does not take place when this Logger object
+    /// is created but when it is used.  As the latter occurs in executable
+    /// code but the former can occur during initialization, this order
+    /// guarantees that anything that is statically initialized has completed
+    /// its initialization by the time the logger is used.
+    void initLogger();
+
+
+    /// \brief Return underlying log4cxx logger, initializing it if necessary
+    ///
+    /// \return Loggerptr object
+    log4cxx::LoggerPtr& getLogger() {
+        if (loggerptr_ == NULL) {
+            initLogger();
+        }
+        return *loggerptr_;
+    }
+
+    // Members.  Note that loggerptr_ is a pointer to a LoggerPtr, which is
+    // itself a pointer to the underlying log4cxx logger.  This is due to the
+    // problems with memory deletion on program exit, explained in the comments
+    // for the "exit_delete" parameter in this class's constructor.
+
+    mutable log4cxx::LoggerPtr*  loggerptr_; ///< Pointer to the underlying logger
+    std::string          name_;         ///< Name of this logger]
+    bool                 exit_delete_;  ///< Delete loggerptr_ on exit?
+
+    // NOTE - THIS IS A PLACE HOLDER
+    static bool         init_;      ///< Set true when initialized
+};
+
+} // namespace log
+} // namespace isc
+
+
+#endif // __LOGGER_IMPL_H

+ 41 - 0
src/lib/log/logger_levels.h

@@ -0,0 +1,41 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __LOGGER_LEVELS_H
+#define __LOGGER_LEVELS_H
+
+namespace isc {
+namespace log {
+
+/// \brief Severity Levels
+///
+/// Defines the severity levels for logging.  This is shared between the logger
+/// and the implementations classes.
+
+typedef enum {
+    DEFAULT = 0,    // Default to logging level of the parent
+    DEBUG = 1,
+    INFO = 2,
+    WARN = 3,
+    ERROR = 4,
+    FATAL = 5,
+    NONE = 6    // Disable logging
+} Severity;
+
+}   // namespace log
+}   // namespace isc
+
+#endif // __LOGGER_LEVELS_H

+ 1 - 1
src/lib/log/logger_support.cc

@@ -91,7 +91,7 @@ readLocalMessageFile(const char* file) {
 /// Logger Run-Time Initialization
 
 void
-runTimeInit(Logger::Severity severity, int dbglevel, const char* file) {
+runTimeInit(isc::log::Severity severity, int dbglevel, const char* file) {
 
     // Create the application root logger.  This is the logger that has the
     // name of the application (and is one level down from the log4cxx root

+ 1 - 1
src/lib/log/logger_support.h

@@ -34,7 +34,7 @@ namespace log {
 /// \param severity Severity at which to log
 /// \param dbglevel Debug severiy (ignored if "severity" is not "DEBUG")
 /// \param file Name of the local message file.
-void runTimeInit(Logger::Severity severity, int dbglevel, const char* file);
+void runTimeInit(isc::log::Severity severity, int dbglevel, const char* file);
 
 } // namespace log
 } // namespace isc

+ 1 - 0
src/lib/log/tests/Makefile.am

@@ -17,6 +17,7 @@ TESTS += run_unittests
 run_unittests_SOURCES  = root_logger_name_unittest.cc
 run_unittests_SOURCES += filename_unittest.cc
 run_unittests_SOURCES += logger_unittest.cc
+run_unittests_SOURCES += logger_impl_unittest.cc
 run_unittests_SOURCES += message_dictionary_unittest.cc
 run_unittests_SOURCES += message_reader_unittest.cc
 run_unittests_SOURCES += message_initializer_unittest.cc

+ 93 - 0
src/lib/log/tests/logger_impl_unittest.cc

@@ -0,0 +1,93 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id: $
+
+#include <iostream>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <log/root_logger_name.h>
+#include <log/logger.h>
+#include <log/logger_impl.h>
+#include <log/messagedef.h>
+
+using namespace isc;
+using namespace isc::log;
+using namespace std;
+
+/// \brief Log4cxx Implementation Tests
+///
+/// Some tests of methods that are not directly tested by the logger unit tests
+/// (when the logger is configured to use log4cxx)
+
+namespace isc {
+namespace log {
+
+/// \brief Test Logger
+///
+/// This logger is a subclass of the logger implementation class under test, but
+/// makes protected methods public (for testing)
+
+class TestLoggerImpl : public LoggerImpl {
+public:
+    /// \brief constructor
+    TestLoggerImpl(const string& name) : LoggerImpl(name, true)
+    {}
+
+
+    /// \brief Conversion Between log4cxx Number and BIND-10 Severity
+    Severity convertLevel(int value) {
+        return LoggerImpl::convertLevel(value);
+    }
+};
+
+} // namespace log
+} // namespace isc
+
+
+class LoggerImplTest : public ::testing::Test {
+protected:
+    LoggerImplTest()
+    {
+    }
+};
+
+// Test the number to severity conversion function
+
+TEST_F(LoggerImplTest, ConvertLevel) {
+
+    // Create a logger
+    RootLoggerName::setName("test3");
+    TestLoggerImpl logger("alpha");
+
+    // Basic 1:1
+    EXPECT_EQ(isc::log::DEBUG, logger.convertLevel(log4cxx::Level::DEBUG_INT));
+    EXPECT_EQ(isc::log::INFO, logger.convertLevel(log4cxx::Level::INFO_INT));
+    EXPECT_EQ(isc::log::WARN, logger.convertLevel(log4cxx::Level::WARN_INT));
+    EXPECT_EQ(isc::log::WARN, logger.convertLevel(log4cxx::Level::WARN_INT));
+    EXPECT_EQ(isc::log::ERROR, logger.convertLevel(log4cxx::Level::ERROR_INT));
+    EXPECT_EQ(isc::log::FATAL, logger.convertLevel(log4cxx::Level::FATAL_INT));
+    EXPECT_EQ(isc::log::FATAL, logger.convertLevel(log4cxx::Level::FATAL_INT));
+    EXPECT_EQ(isc::log::NONE, logger.convertLevel(log4cxx::Level::OFF_INT));
+
+    // Now some debug levels
+    EXPECT_EQ(isc::log::DEBUG,
+        logger.convertLevel(log4cxx::Level::DEBUG_INT - 1));
+    EXPECT_EQ(isc::log::DEBUG,
+        logger.convertLevel(log4cxx::Level::DEBUG_INT - MAX_DEBUG_LEVEL));
+    EXPECT_EQ(isc::log::DEBUG,
+        logger.convertLevel(log4cxx::Level::DEBUG_INT - 2 * MAX_DEBUG_LEVEL));
+}

+ 8 - 9
src/lib/log/tests/logger_support_test.cc

@@ -47,13 +47,12 @@ Logger logger_dlm("dlm");
 // "level" is the debug level, a number between 0 and 99
 // "local_file" is the name of a local file.
 //
-// The program sets the attributes on the root logger.  Looking
-// at the output determines whether the program worked.e root logger.  Looking
-// at the output determines whether the 
+// The program sets the attributes on the root logger and logs a set of
+// messages.  Looking at the output determines whether the program worked.
 
 int main(int argc, char** argv) {
 
-    Logger::Severity    severity = Logger::INFO;
+    isc::log::Severity  severity = isc::log::INFO;
     int                 dbglevel = -1;
     const char*         localfile = NULL;
     int                 option;
@@ -63,15 +62,15 @@ int main(int argc, char** argv) {
         switch (option) {
             case 's':
                 if (strcmp(optarg, "debug") == 0) {
-                    severity = Logger::DEBUG;
+                    severity = isc::log::DEBUG;
                 } else if (strcmp(optarg, "info") == 0) {
-                    severity = Logger::INFO;
+                    severity = isc::log::INFO;
                 } else if (strcmp(optarg, "warn") == 0) {
-                    severity = Logger::WARN;
+                    severity = isc::log::WARN;
                 } else if (strcmp(optarg, "error") == 0) {
-                    severity = Logger::ERROR;
+                    severity = isc::log::ERROR;
                 } else if (strcmp(optarg, "fatal") == 0) {
-                    severity = Logger::FATAL;
+                    severity = isc::log::FATAL;
                 } else {
                     std::cout << "Unrecognised severity option: " <<
                         optarg << "\n";

+ 61 - 93
src/lib/log/tests/logger_unittest.cc

@@ -47,14 +47,9 @@ public:
     }
 
     /// \brief Logger is Null
-    bool isInitialized() const {
+    bool isInitialized() {
         return Logger::isInitialized();
     }
-
-    /// \brief Conversion Between log4cxx Number and BIND-10 Severity
-    Severity convertLevel(int value) {
-        return Logger::convertLevel(value);
-    }
 };
 
 } // namespace log
@@ -119,33 +114,6 @@ TEST_F(LoggerTest, GetLogger) {
     EXPECT_FALSE(logger1 == logger3);
 }
 
-// Test the number to severity conversion function
-
-TEST_F(LoggerTest, ConvertLevel) {
-
-    // Create a logger
-    RootLoggerName::setName("test3");
-    TestLogger logger("alpha");
-
-    // Basic 1:1
-    EXPECT_EQ(Logger::DEBUG, logger.convertLevel(log4cxx::Level::DEBUG_INT));
-    EXPECT_EQ(Logger::INFO, logger.convertLevel(log4cxx::Level::INFO_INT));
-    EXPECT_EQ(Logger::WARN, logger.convertLevel(log4cxx::Level::WARN_INT));
-    EXPECT_EQ(Logger::WARN, logger.convertLevel(log4cxx::Level::WARN_INT));
-    EXPECT_EQ(Logger::ERROR, logger.convertLevel(log4cxx::Level::ERROR_INT));
-    EXPECT_EQ(Logger::FATAL, logger.convertLevel(log4cxx::Level::FATAL_INT));
-    EXPECT_EQ(Logger::FATAL, logger.convertLevel(log4cxx::Level::FATAL_INT));
-    EXPECT_EQ(Logger::NONE, logger.convertLevel(log4cxx::Level::OFF_INT));
-
-    // Now some debug levels
-    EXPECT_EQ(Logger::DEBUG,
-        logger.convertLevel(log4cxx::Level::DEBUG_INT - 1));
-    EXPECT_EQ(Logger::DEBUG,
-        logger.convertLevel(log4cxx::Level::DEBUG_INT - MAX_DEBUG_LEVEL));
-    EXPECT_EQ(Logger::DEBUG,
-        logger.convertLevel(log4cxx::Level::DEBUG_INT - 2 * MAX_DEBUG_LEVEL));
-}
-
 // Check that the logger levels are get set properly.
 
 TEST_F(LoggerTest, Severity) {
@@ -155,26 +123,26 @@ TEST_F(LoggerTest, Severity) {
     TestLogger logger("alpha");
 
     // Now check the levels
-    logger.setSeverity(Logger::NONE);
-    EXPECT_EQ(Logger::NONE, logger.getSeverity());
+    logger.setSeverity(isc::log::NONE);
+    EXPECT_EQ(isc::log::NONE, logger.getSeverity());
 
-    logger.setSeverity(Logger::FATAL);
-    EXPECT_EQ(Logger::FATAL, logger.getSeverity());
+    logger.setSeverity(isc::log::FATAL);
+    EXPECT_EQ(isc::log::FATAL, logger.getSeverity());
 
-    logger.setSeverity(Logger::ERROR);
-    EXPECT_EQ(Logger::ERROR, logger.getSeverity());
+    logger.setSeverity(isc::log::ERROR);
+    EXPECT_EQ(isc::log::ERROR, logger.getSeverity());
 
-    logger.setSeverity(Logger::WARN);
-    EXPECT_EQ(Logger::WARN, logger.getSeverity());
+    logger.setSeverity(isc::log::WARN);
+    EXPECT_EQ(isc::log::WARN, logger.getSeverity());
 
-    logger.setSeverity(Logger::INFO);
-    EXPECT_EQ(Logger::INFO, logger.getSeverity());
+    logger.setSeverity(isc::log::INFO);
+    EXPECT_EQ(isc::log::INFO, logger.getSeverity());
 
-    logger.setSeverity(Logger::DEBUG);
-    EXPECT_EQ(Logger::DEBUG, logger.getSeverity());
+    logger.setSeverity(isc::log::DEBUG);
+    EXPECT_EQ(isc::log::DEBUG, logger.getSeverity());
 
-    logger.setSeverity(Logger::DEFAULT);
-    EXPECT_EQ(Logger::DEFAULT, logger.getSeverity());
+    logger.setSeverity(isc::log::DEFAULT);
+    EXPECT_EQ(isc::log::DEFAULT, logger.getSeverity());
 }
 
 // Check that the debug level is set correctly.
@@ -186,36 +154,36 @@ TEST_F(LoggerTest, DebugLevels) {
     TestLogger logger("alpha");
 
     // Debug level should be 0 if not at debug severity
-    logger.setSeverity(Logger::NONE, 20);
+    logger.setSeverity(isc::log::NONE, 20);
     EXPECT_EQ(0, logger.getDebugLevel());
 
-    logger.setSeverity(Logger::INFO, 42);
+    logger.setSeverity(isc::log::INFO, 42);
     EXPECT_EQ(0, logger.getDebugLevel());
 
     // Should be the value set if the severity is set to DEBUG though.
-    logger.setSeverity(Logger::DEBUG, 32);
+    logger.setSeverity(isc::log::DEBUG, 32);
     EXPECT_EQ(32, logger.getDebugLevel());
 
-    logger.setSeverity(Logger::DEBUG, 97);
+    logger.setSeverity(isc::log::DEBUG, 97);
     EXPECT_EQ(97, logger.getDebugLevel());
 
     // Try the limits
-    logger.setSeverity(Logger::DEBUG, -1);
+    logger.setSeverity(isc::log::DEBUG, -1);
     EXPECT_EQ(0, logger.getDebugLevel());
 
-    logger.setSeverity(Logger::DEBUG, 0);
+    logger.setSeverity(isc::log::DEBUG, 0);
     EXPECT_EQ(0, logger.getDebugLevel());
 
-    logger.setSeverity(Logger::DEBUG, 1);
+    logger.setSeverity(isc::log::DEBUG, 1);
     EXPECT_EQ(1, logger.getDebugLevel());
 
-    logger.setSeverity(Logger::DEBUG, 98);
+    logger.setSeverity(isc::log::DEBUG, 98);
     EXPECT_EQ(98, logger.getDebugLevel());
 
-    logger.setSeverity(Logger::DEBUG, 99);
+    logger.setSeverity(isc::log::DEBUG, 99);
     EXPECT_EQ(99, logger.getDebugLevel());
 
-    logger.setSeverity(Logger::DEBUG, 100);
+    logger.setSeverity(isc::log::DEBUG, 100);
     EXPECT_EQ(99, logger.getDebugLevel());
 }
 
@@ -234,22 +202,22 @@ TEST_F(LoggerTest, SeverityInheritance) {
 
     // By default, newly created loggers should have a level of DEFAULT
     // (i.e. default to parent)
-    EXPECT_EQ(Logger::DEFAULT, parent.getSeverity());
-    EXPECT_EQ(Logger::DEFAULT, child.getSeverity());
+    EXPECT_EQ(isc::log::DEFAULT, parent.getSeverity());
+    EXPECT_EQ(isc::log::DEFAULT, child.getSeverity());
 
     // Set the severity of the child to something other than the default -
     // check it changes and that of the parent does not.
-    child.setSeverity(Logger::INFO);
-    EXPECT_EQ(Logger::DEFAULT, parent.getSeverity());
-    EXPECT_EQ(Logger::INFO, child.getSeverity());
+    child.setSeverity(isc::log::INFO);
+    EXPECT_EQ(isc::log::DEFAULT, parent.getSeverity());
+    EXPECT_EQ(isc::log::INFO, child.getSeverity());
 
     // Reset the child severity and set that of the parent
-    child.setSeverity(Logger::DEFAULT);
-    EXPECT_EQ(Logger::DEFAULT, parent.getSeverity());
-    EXPECT_EQ(Logger::DEFAULT, child.getSeverity());
-    parent.setSeverity(Logger::WARN);
-    EXPECT_EQ(Logger::WARN, parent.getSeverity());
-    EXPECT_EQ(Logger::DEFAULT, child.getSeverity());
+    child.setSeverity(isc::log::DEFAULT);
+    EXPECT_EQ(isc::log::DEFAULT, parent.getSeverity());
+    EXPECT_EQ(isc::log::DEFAULT, child.getSeverity());
+    parent.setSeverity(isc::log::WARN);
+    EXPECT_EQ(isc::log::WARN, parent.getSeverity());
+    EXPECT_EQ(isc::log::DEFAULT, child.getSeverity());
 }
 
 // Check that severity is inherited.
@@ -268,27 +236,27 @@ TEST_F(LoggerTest, EffectiveSeverityInheritance) {
     // (i.e. default to parent) and the root should have a default severity
     // of INFO.  However, the latter is only enforced when created by the
     // RootLogger class, so explicitly set it for the parent for now.
-    parent.setSeverity(Logger::INFO);
-    EXPECT_EQ(Logger::INFO, parent.getEffectiveSeverity());
+    parent.setSeverity(isc::log::INFO);
+    EXPECT_EQ(isc::log::INFO, parent.getEffectiveSeverity());
 
-    EXPECT_EQ(Logger::DEFAULT, child.getSeverity());
-    EXPECT_EQ(Logger::INFO, child.getEffectiveSeverity());
+    EXPECT_EQ(isc::log::DEFAULT, child.getSeverity());
+    EXPECT_EQ(isc::log::INFO, child.getEffectiveSeverity());
 
     // Set the severity of the child to something other than the default -
     // check it changes and that of the parent does not.
-    child.setSeverity(Logger::FATAL);
-    EXPECT_EQ(Logger::INFO, parent.getEffectiveSeverity());
-    EXPECT_EQ(Logger::FATAL, child.getEffectiveSeverity());
+    child.setSeverity(isc::log::FATAL);
+    EXPECT_EQ(isc::log::INFO, parent.getEffectiveSeverity());
+    EXPECT_EQ(isc::log::FATAL, child.getEffectiveSeverity());
 
     // Reset the child severity and check again.
-    child.setSeverity(Logger::DEFAULT);
-    EXPECT_EQ(Logger::INFO, parent.getEffectiveSeverity());
-    EXPECT_EQ(Logger::INFO, child.getEffectiveSeverity());
+    child.setSeverity(isc::log::DEFAULT);
+    EXPECT_EQ(isc::log::INFO, parent.getEffectiveSeverity());
+    EXPECT_EQ(isc::log::INFO, child.getEffectiveSeverity());
 
     // Change the parwnt's severity and check it is reflects in the child.
-    parent.setSeverity(Logger::WARN);
-    EXPECT_EQ(Logger::WARN, parent.getEffectiveSeverity());
-    EXPECT_EQ(Logger::WARN, child.getEffectiveSeverity());
+    parent.setSeverity(isc::log::WARN);
+    EXPECT_EQ(isc::log::WARN, parent.getEffectiveSeverity());
+    EXPECT_EQ(isc::log::WARN, child.getEffectiveSeverity());
 }
 
 // Test the isXxxxEnabled methods.
@@ -298,28 +266,28 @@ TEST_F(LoggerTest, IsXxxEnabled) {
     RootLoggerName::setName("test7");
     Logger logger("test7");
 
-    logger.setSeverity(Logger::INFO);
+    logger.setSeverity(isc::log::INFO);
     EXPECT_FALSE(logger.isDebugEnabled());
     EXPECT_TRUE(logger.isInfoEnabled());
     EXPECT_TRUE(logger.isWarnEnabled());
     EXPECT_TRUE(logger.isErrorEnabled());
     EXPECT_TRUE(logger.isFatalEnabled());
 
-    logger.setSeverity(Logger::WARN);
+    logger.setSeverity(isc::log::WARN);
     EXPECT_FALSE(logger.isDebugEnabled());
     EXPECT_FALSE(logger.isInfoEnabled());
     EXPECT_TRUE(logger.isWarnEnabled());
     EXPECT_TRUE(logger.isErrorEnabled());
     EXPECT_TRUE(logger.isFatalEnabled());
 
-    logger.setSeverity(Logger::ERROR);
+    logger.setSeverity(isc::log::ERROR);
     EXPECT_FALSE(logger.isDebugEnabled());
     EXPECT_FALSE(logger.isInfoEnabled());
     EXPECT_FALSE(logger.isWarnEnabled());
     EXPECT_TRUE(logger.isErrorEnabled());
     EXPECT_TRUE(logger.isFatalEnabled());
 
-    logger.setSeverity(Logger::FATAL);
+    logger.setSeverity(isc::log::FATAL);
     EXPECT_FALSE(logger.isDebugEnabled());
     EXPECT_FALSE(logger.isInfoEnabled());
     EXPECT_FALSE(logger.isWarnEnabled());
@@ -328,14 +296,14 @@ TEST_F(LoggerTest, IsXxxEnabled) {
 
     // Check various debug levels
 
-    logger.setSeverity(Logger::DEBUG);
+    logger.setSeverity(isc::log::DEBUG);
     EXPECT_TRUE(logger.isDebugEnabled());
     EXPECT_TRUE(logger.isInfoEnabled());
     EXPECT_TRUE(logger.isWarnEnabled());
     EXPECT_TRUE(logger.isErrorEnabled());
     EXPECT_TRUE(logger.isFatalEnabled());
 
-    logger.setSeverity(Logger::DEBUG, 45);
+    logger.setSeverity(isc::log::DEBUG, 45);
     EXPECT_TRUE(logger.isDebugEnabled());
     EXPECT_TRUE(logger.isInfoEnabled());
     EXPECT_TRUE(logger.isWarnEnabled());
@@ -346,14 +314,14 @@ TEST_F(LoggerTest, IsXxxEnabled) {
     // the severity of the parent logger.
 
     Logger child("test7.child");
-    logger.setSeverity(Logger::FATAL);
+    logger.setSeverity(isc::log::FATAL);
     EXPECT_FALSE(child.isDebugEnabled());
     EXPECT_FALSE(child.isInfoEnabled());
     EXPECT_FALSE(child.isWarnEnabled());
     EXPECT_FALSE(child.isErrorEnabled());
     EXPECT_TRUE(child.isFatalEnabled());
 
-    logger.setSeverity(Logger::INFO);
+    logger.setSeverity(isc::log::INFO);
     EXPECT_FALSE(child.isDebugEnabled());
     EXPECT_TRUE(child.isInfoEnabled());
     EXPECT_TRUE(child.isWarnEnabled());
@@ -371,24 +339,24 @@ TEST_F(LoggerTest, IsDebugEnabledLevel) {
 
     int MID_LEVEL = (MIN_DEBUG_LEVEL + MAX_DEBUG_LEVEL) / 2;
 
-    logger.setSeverity(Logger::DEBUG);
+    logger.setSeverity(isc::log::DEBUG);
     EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
     EXPECT_FALSE(logger.isDebugEnabled(MID_LEVEL));
     EXPECT_FALSE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
 
-    logger.setSeverity(Logger::DEBUG, MIN_DEBUG_LEVEL);
+    logger.setSeverity(isc::log::DEBUG, MIN_DEBUG_LEVEL);
     EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
     EXPECT_FALSE(logger.isDebugEnabled(MID_LEVEL));
     EXPECT_FALSE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
 
-    logger.setSeverity(Logger::DEBUG, MID_LEVEL);
+    logger.setSeverity(isc::log::DEBUG, MID_LEVEL);
     EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
     EXPECT_TRUE(logger.isDebugEnabled(MID_LEVEL - 1));
     EXPECT_TRUE(logger.isDebugEnabled(MID_LEVEL));
     EXPECT_FALSE(logger.isDebugEnabled(MID_LEVEL + 1));
     EXPECT_FALSE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
 
-    logger.setSeverity(Logger::DEBUG, MAX_DEBUG_LEVEL);
+    logger.setSeverity(isc::log::DEBUG, MAX_DEBUG_LEVEL);
     EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
     EXPECT_TRUE(logger.isDebugEnabled(MID_LEVEL));
     EXPECT_TRUE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));