Browse Source

[trac555] Move logging initialization to LoggerManager

This is the global object that controls the logging system, so
it is logical that initialization is done here instead of in the
Logger class (which controls the operation of one logger).
Stephen Morris 14 years ago
parent
commit
9e48d735ae

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

@@ -45,9 +45,6 @@ namespace log {
 // Constructor
 // Constructor
 LoggerImpl::LoggerImpl(const string& name)
 LoggerImpl::LoggerImpl(const string& name)
 {
 {
-    // Initialize log4cplus if not already done
-    initLog4cplus();
-
     // Are we the root logger?
     // Are we the root logger?
     if (name == getRootLoggerName()) {
     if (name == getRootLoggerName()) {
         name_ = name;
         name_ = name;
@@ -133,64 +130,12 @@ LoggerImpl::outputRaw(const Severity& severity, const string& message) {
     }
     }
 }
 }
 
 
-// Initialization.  This is one initialization for all loggers, so requires
-// a singleton to hold the initialization flag.  The flag is held within a
-// static method to ensure that it is created (and initialized) when needed.
-// This avoids a static initialization fiasco.
-
-bool&
-LoggerImpl::initialized() {
-    static bool initialized = false;
-    return (initialized);
-}
-
-void
-LoggerImpl::initLog4cplus() {
-
-    if (! initialized()) {
-
-        // Set up basic configurator.  This attaches a ConsoleAppender to the
-        // root logger with suitable output.  This is used until we we have
-        // actually read the logging configuration, in which case the output
-        // may well be changed.
-        log4cplus::BasicConfigurator config;
-        config.configure();
-        setRootAppenderLayout();
-
-        // Add additional debug levels
-        LoggerLevelImpl::init();
-
-        // All done.
-        initialized() = true;
-    }
-}
-
-void LoggerImpl::setRootAppenderLayout() {
-
-    // Create the pattern we want for the output - local time.
-    string pattern = "%D{%Y-%m-%d %H:%M:%S.%q} %-5p [";
-    pattern += getRootLoggerName() + string(".%c] %m\n");
-
-    // Retrieve the appenders on the root instance and set the layout to
-    // use that pattern.
-    log4cplus::SharedAppenderPtrList list =
-        log4cplus::Logger::getRoot().getAllAppenders();
-
-    for (log4cplus::SharedAppenderPtrList::iterator i = list.begin();
-         i != list.end(); ++i) {
-        auto_ptr<log4cplus::Layout> layout(
-            new log4cplus::PatternLayout(pattern));
-        (*i)->setLayout(layout);
-    }
-}
-
 // Reset.  Just reset logger hierarchy to default settings (don't remove the
 // Reset.  Just reset logger hierarchy to default settings (don't remove the
 // loggers - this appears awkward); this is effectively the same as removing
 // loggers - this appears awkward); this is effectively the same as removing
 // them.
 // them.
 void
 void
 LoggerImpl::reset() {
 LoggerImpl::reset() {
     log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
     log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
-    initialized() = false;
 
 
     // N.B.  The documentation is not clear, but it does not appear that the
     // N.B.  The documentation is not clear, but it does not appear that the
     // methods used to format the new logging levels are removed from the
     // methods used to format the new logging levels are removed from the

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

@@ -192,23 +192,6 @@ public:
 
 
 
 
 private:
 private:
-
-    /// \brief Initialize log4cplus
-    ///
-    /// Static method to perform initialization of the log4cplus system.
-    static void initLog4cplus();
-
-    /// \brief Initialization Flag
-    ///
-    /// Static method to access an initialization flag.  Doing it this
-    /// way means that there is no static initialization fiasco.
-    static bool& initialized();
-
-    /// \brief Set layout pattern
-    ///
-    /// Sets the layout for root logger appender(s)
-    static void setRootAppenderLayout();
-
     std::string         name_;              ///< Full name of this logger
     std::string         name_;              ///< Full name of this logger
     log4cplus::Logger   logger_;            ///< Underlying log4cplus logger
     log4cplus::Logger   logger_;            ///< Underlying log4cplus logger
 };
 };

+ 100 - 2
src/lib/log/logger_manager.cc

@@ -12,8 +12,24 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#include <algorithm>
+#include <vector>
+
+#include <log/logger.h>
 #include <log/logger_manager_impl.h>
 #include <log/logger_manager_impl.h>
 #include <log/logger_manager.h>
 #include <log/logger_manager.h>
+#include <log/messagedef.h>
+#include <log/message_dictionary.h>
+#include <log/message_exception.h>
+#include <log/message_initializer.h>
+#include <log/message_reader.h>
+#include <log/message_types.h>
+#include <log/root_logger_name.h>
+#include <log/macros.h>
+#include <log/messagedef.h>
+#include <log/message_initializer.h>
+
+using namespace std;
 
 
 namespace isc {
 namespace isc {
 namespace log {
 namespace log {
@@ -33,10 +49,10 @@ LoggerManager::~LoggerManager() {
 // Initialize processing
 // Initialize processing
 void
 void
 LoggerManager::processInit() {
 LoggerManager::processInit() {
-    impl_->processInit();
+    impl_->processInit(getRootLoggerName());
 }
 }
 
 
-// Process loggging specification
+// Process logging specification
 void
 void
 LoggerManager::processSpecification(const LoggerSpecification& spec) {
 LoggerManager::processSpecification(const LoggerSpecification& spec) {
     impl_->processSpecification(spec);
     impl_->processSpecification(spec);
@@ -48,5 +64,87 @@ LoggerManager::processEnd() {
     impl_->processEnd();
     impl_->processEnd();
 }
 }
 
 
+
+/// Logging system initialization
+
+void
+LoggerManager::init(const std::string& root, const char* file,
+                    isc::log::Severity severity, int dbglevel)
+{
+    // Create the BIND 10 root logger and set the default severity and
+    // debug level.  This is the logger that has the name of the application.
+    // All other loggers created in this application will be its children.
+    setRootLoggerName(root);
+
+    // Initialize the implementation logging.
+    LoggerManagerImpl::init(root, severity, dbglevel);
+
+    // TODO: sort out the names.
+    Logger logger("log");
+
+    // Check if there were any duplicate message IDs in the default dictionary
+    // and if so, log them.  Log using the logging facility root logger.
+    vector<string>& duplicates = MessageInitializer::getDuplicates();
+    if (!duplicates.empty()) {
+
+        // There are - sort and remove any duplicates.
+        sort(duplicates.begin(), duplicates.end());
+        vector<string>::iterator new_end =
+            unique(duplicates.begin(), duplicates.end());
+        for (vector<string>::iterator i = duplicates.begin(); i != new_end; ++i) {
+            LOG_WARN(logger, MSG_DUPMSGID).arg(*i);
+        }
+
+    }
+
+    // Replace any messages with local ones (if given)
+    if (file) {
+        readLocalMessageFile(file);
+    }
+}
+
+
+/// Read local message file
+void
+LoggerManager::readLocalMessageFile(const char* file) {
+
+    Logger logger("log");
+
+    MessageDictionary& dictionary = MessageDictionary::globalDictionary();
+    MessageReader reader(&dictionary);
+    try {
+        logger.info(MSG_RDLOCMES).arg(file);
+        reader.readFile(file, MessageReader::REPLACE);
+
+        // File successfully read, list the duplicates
+        MessageReader::MessageIDCollection unknown = reader.getNotAdded();
+        for (MessageReader::MessageIDCollection::const_iterator
+            i = unknown.begin(); i != unknown.end(); ++i) {
+            string message_id = boost::lexical_cast<string>(*i);
+                logger.warn(MSG_IDNOTFND).arg(message_id);
+        }
+    }
+    catch (MessageException& e) {
+        MessageID ident = e.id();
+        vector<string> args = e.arguments();
+        switch (args.size()) {
+        case 0:
+            LOG_ERROR(logger, ident);
+            break;
+
+        case 1:
+            LOG_ERROR(logger, ident).arg(args[0]);
+            break;
+
+        case 2:
+            LOG_ERROR(logger, ident).arg(args[0]).arg(args[1]);
+            break;
+
+        default:    // 3 or more (3 should be the maximum)
+            LOG_ERROR(logger, ident).arg(args[0]).arg(args[1]).arg(args[2]);
+        }
+    }
+}
+
 } // namespace log
 } // namespace log
 } // namespace isc
 } // namespace isc

+ 22 - 6
src/lib/log/logger_manager.h

@@ -67,12 +67,20 @@ public:
         processEnd();
         processEnd();
     }
     }
 
 
-    /// \brief Initialization
+    /// \brief Run-Time Initialization
     ///
     ///
-    /// Static method for initializing the whole of the logging system.  This
-    /// must be called before anything else.
-    static void init();
-
+    /// Performs run-time initialization of the logger system, in particular
+    /// supplying the root logger name and name of a replacement message file.
+    ///
+    /// This must be the first logging function called in the program.
+    ///
+    /// \param root Name of the root logger
+    /// \param file Name of the local message file.
+    /// \param severity Severity at which to log
+    /// \param dbglevel Debug severity (ignored if "severity" is not "DEBUG")
+    static void init(const std::string& root, const char* file = NULL,
+                    isc::log::Severity severity = isc::log::INFO,
+                    int dbglevel = 0);
 
 
 private:
 private:
     /// \brief Initialize Processing
     /// \brief Initialize Processing
@@ -88,13 +96,21 @@ private:
     /// either the logger does not exist or has been made inactive.
     /// either the logger does not exist or has been made inactive.
     void processSpecification(const LoggerSpecification& spec);
     void processSpecification(const LoggerSpecification& spec);
 
 
-
     /// \brief End Processing
     /// \brief End Processing
     ///
     ///
     /// Place holder for finish processing.
     /// Place holder for finish processing.
     /// TODO: Check that the root logger has something enabled
     /// TODO: Check that the root logger has something enabled
     void processEnd();
     void processEnd();
 
 
+    /// \brief Read local message file
+    ///
+    /// Reads the local message file into the global dictionary, overwriting
+    /// existing messages.  If the file contained any message IDs not in the
+    /// dictionary, they are listed in a warning message.
+    ///
+    /// \param file Name of the local message file
+    static void readLocalMessageFile(const char* file);
+
     // Members
     // Members
     LoggerManagerImpl*  impl_;      ///< Pointer to implementation
     LoggerManagerImpl*  impl_;      ///< Pointer to implementation
 };
 };

+ 63 - 2
src/lib/log/logger_manager_impl.cc

@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#include <algorithm>
+
 #include <log4cplus/logger.h>
 #include <log4cplus/logger.h>
 #include <log4cplus/configurator.h>
 #include <log4cplus/configurator.h>
 #include <log4cplus/consoleappender.h>
 #include <log4cplus/consoleappender.h>
@@ -21,6 +23,9 @@
 #include "log/logger_specification.h"
 #include "log/logger_specification.h"
 #include "log/root_logger_name.h"
 #include "log/root_logger_name.h"
 
 
+#include "log/logger.h"
+#include "log/messagedef.h"
+
 #include "exceptions/exceptions.h"
 #include "exceptions/exceptions.h"
 
 
 // Generated exceptions.  Methods in this file can't log exceptions as they may
 // Generated exceptions.  Methods in this file can't log exceptions as they may
@@ -38,6 +43,8 @@ public:
 // informational messages.  (This last is not a log4cplus default, so we have to
 // informational messages.  (This last is not a log4cplus default, so we have to
 // explicitly reset the logging severity.)
 // explicitly reset the logging severity.)
 
 
+using namespace std;
+
 namespace isc {
 namespace isc {
 namespace log {
 namespace log {
 
 
@@ -46,9 +53,9 @@ namespace log {
 // configuration update removes the logger.)
 // configuration update removes the logger.)
 
 
 void
 void
-LoggerManagerImpl::processInit() {
+LoggerManagerImpl::processInit(const std::string& root_name) {
     log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
     log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
-    log4cplus::Logger::getRoot().setLogLevel(log4cplus::INFO_LOG_LEVEL);
+    initRootLogger(root_name);
 }
 }
 
 
 // Process logging specification.  Set up the common states then dispatch to
 // Process logging specification.  Set up the common states then dispatch to
@@ -104,5 +111,59 @@ LoggerManagerImpl::createConsoleAppender(log4cplus::Logger& logger,
 }
 }
 
 
 
 
+// One-time initialization of the log4cplus system
+
+void
+LoggerManagerImpl::init(const std::string& root_name,
+                        isc::log::Severity severity, int dbglevel)
+{
+    // Set up basic configurator.  This attaches a ConsoleAppender to the
+    // root logger with suitable output.  This is used until we we have
+    // actually read the logging configuration, in which case the output
+    // may well be changed.
+    log4cplus::BasicConfigurator config;
+    config.configure();
+
+    // Add the additional debug levels
+    LoggerLevelImpl::init();
+
+    // And initialize the root logger
+    initRootLogger(root_name, severity, dbglevel);
+}
+
+// Initialize the root logger
+void LoggerManagerImpl::initRootLogger(const std::string& root_name,
+                                       isc::log::Severity severity,
+                                       int dbglevel) {
+
+    // Set the severity for the root logger
+    log4cplus::Logger::getRoot().setLogLevel(
+            LoggerLevelImpl::convertFromBindLevel(Level(severity, dbglevel)));
+
+    // Retrieve the appenders on the root instance and set the layout to
+    // use the "console" pattern.
+    log4cplus::SharedAppenderPtrList list =
+        log4cplus::Logger::getRoot().getAllAppenders();
+    for (log4cplus::SharedAppenderPtrList::iterator i = list.begin();
+         i != list.end(); ++i) {
+         setConsoleAppenderLayout(*i, root_name);
+    }
+}
+
+// Set the the "console" layout for the given appenders.  This layout includes
+// a date/time and the name of the logger.
+
+void LoggerManagerImpl::setConsoleAppenderLayout(
+        log4cplus::SharedAppenderPtr& appender, const std::string& root_name)
+{
+    // Create the pattern we want for the output - local time.
+    string pattern = "%D{%Y-%m-%d %H:%M:%S.%q} %-5p [";
+    pattern += root_name + string(".%c] %m\n");
+
+    // Finally the text of the message
+    auto_ptr<log4cplus::Layout> layout(new log4cplus::PatternLayout(pattern));
+    appender->setLayout(layout);
+}
+
 } // namespace log
 } // namespace log
 } // namespace isc
 } // namespace isc

+ 46 - 2
src/lib/log/logger_manager_impl.h

@@ -15,16 +15,24 @@
 #ifndef __LOGGER_MANAGER_IMPL_H
 #ifndef __LOGGER_MANAGER_IMPL_H
 #define __LOGGER_MANAGER_IMPL_H
 #define __LOGGER_MANAGER_IMPL_H
 
 
-#include <log/logger_specification.h>
+#include <string>
+
+#include <log4cplus/appender.h>
+#include <log/logger_level.h>
 
 
 // Forward declaration to avoid need to include log4cplus header file here.
 // Forward declaration to avoid need to include log4cplus header file here.
 namespace log4cplus {
 namespace log4cplus {
 class Logger;
 class Logger;
+class Appender;
 }
 }
 
 
 namespace isc {
 namespace isc {
 namespace log {
 namespace log {
 
 
+// Forward declarations
+class LoggerSpecification;
+class OutputOption;
+
 /// \brief Logger Manager Implementation
 /// \brief Logger Manager Implementation
 ///
 ///
 /// This is the implementation of the logger manager for the log4cplus
 /// This is the implementation of the logger manager for the log4cplus
@@ -46,7 +54,9 @@ public:
     /// This resets the hierachy of loggers back to their defaults.  This means
     /// This resets the hierachy of loggers back to their defaults.  This means
     /// that all non-root loggers (if they exist) are set to NOT_SET, and the
     /// that all non-root loggers (if they exist) are set to NOT_SET, and the
     /// root logger reset to logging informational messages.
     /// root logger reset to logging informational messages.
-    void processInit();
+    ///
+    /// \param root_name BIOND 10 name of the root logger
+    void processInit(const std::string& root_name);
 
 
     /// \brief Process Specification
     /// \brief Process Specification
     ///
     ///
@@ -60,6 +70,16 @@ public:
     /// Terminates the processing of the logging specifications.
     /// Terminates the processing of the logging specifications.
     void processEnd();
     void processEnd();
 
 
+    /// \brief Implementation-specific initialization
+    ///
+    /// Performs any implementation-specific initialization.
+    ///
+    /// \param root_name Name of the BIND 10 root logger.
+    /// \param severity Severity to be associated with this logger
+    /// \param dbglevel Debug level associated with the root logger
+    static void init(const std::string& root_name, isc::log::Severity severity,
+                     int dbglevel);
+
 private:
 private:
     /// \brief Create console appender
     /// \brief Create console appender
     ///
     ///
@@ -91,6 +111,30 @@ private:
     /// \param opt Output options for this appender.
     /// \param opt Output options for this appender.
     void createSyslogAppender(log4cplus::Logger& logger,
     void createSyslogAppender(log4cplus::Logger& logger,
                               const OutputOption& opt) {}
                               const OutputOption& opt) {}
+
+    /// \brief Set default layout and severity for root logger
+    ///
+    /// Initializes the root logger to BIND 10 defaults - console output and
+    /// the passed severity/debug level.
+    ///
+    /// \param root_name Name of the BIND 10 root logger.
+    /// \param severity Severity of messages that the logger should output.
+    /// \param dbglevel Debug level if severity = DEBUG
+    static void initRootLogger(const std::string& root_name,
+                               isc::log::Severity severity = isc::log::INFO,
+                               int dbglevel = 0);
+
+    /// \brief Set layout for console appender
+    ///
+    /// Sets the layout of the specified appender to one suitable for file
+    /// or console output:
+    ///
+    /// YYYY-MM-DD HH:MM:SS.ssss <severity> [root.logger] message
+    ///
+    /// \param appender Appender for which this pattern is to be set.
+    /// \param root_name Name of the BIND 10 root logger.
+    static void setConsoleAppenderLayout(
+        log4cplus::SharedAppenderPtr& appender, const std::string& root_name);
 };
 };
 
 
 } // namespace log
 } // namespace log

+ 2 - 86
src/lib/log/logger_support.cc

@@ -28,18 +28,10 @@
 #include <algorithm>
 #include <algorithm>
 #include <iostream>
 #include <iostream>
 #include <string>
 #include <string>
-#include <vector>
-#include <boost/lexical_cast.hpp>
 
 
 #include <log/logger.h>
 #include <log/logger.h>
+#include <log/logger_manager.h>
 #include <log/logger_support.h>
 #include <log/logger_support.h>
-#include <log/messagedef.h>
-#include <log/message_dictionary.h>
-#include <log/message_exception.h>
-#include <log/message_initializer.h>
-#include <log/message_reader.h>
-#include <log/message_types.h>
-#include <log/root_logger_name.h>
 
 
 namespace isc {
 namespace isc {
 namespace log {
 namespace log {
@@ -50,88 +42,12 @@ using namespace std;
 // root logger and is used in all functions in this file.
 // root logger and is used in all functions in this file.
 Logger logger("log");
 Logger logger("log");
 
 
-
-/// \brief Reads Local Message File
-///
-/// Reads the local message file into the global dictionary, overwriting
-/// existing messages.  If the file contained any message IDs not in the
-/// dictionary, they are listed in a warning message.
-///
-/// \param file Name of the local message file
-static void
-readLocalMessageFile(const char* file) {
-
-    MessageDictionary& dictionary = MessageDictionary::globalDictionary();
-    MessageReader reader(&dictionary);
-    try {
-        logger.info(MSG_RDLOCMES).arg(file);
-        reader.readFile(file, MessageReader::REPLACE);
-
-        // File successfully read, list the duplicates
-        MessageReader::MessageIDCollection unknown = reader.getNotAdded();
-        for (MessageReader::MessageIDCollection::const_iterator
-            i = unknown.begin(); i != unknown.end(); ++i) {
-            string message_id = boost::lexical_cast<string>(*i);
-                logger.warn(MSG_IDNOTFND).arg(message_id);
-        }
-    }
-    catch (MessageException& e) {
-        MessageID ident = e.id();
-        vector<string> args = e.arguments();
-        switch (args.size()) {
-        case 0:
-            logger.error(ident);
-            break;
-
-        case 1:
-            logger.error(ident).arg(args[0]);
-            break;
-
-        case 2:
-            logger.error(ident).arg(args[0]).arg(args[1]);
-            break;
-
-        default:    // 3 or more (3 should be the maximum)
-            logger.error(ident).arg(args[0]).arg(args[1]).arg(args[2]);
-        }
-    }
-}
-
 /// Logger Run-Time Initialization
 /// Logger Run-Time Initialization
 
 
 void
 void
 initLogger(const string& root, isc::log::Severity severity, int dbglevel,
 initLogger(const string& root, isc::log::Severity severity, int dbglevel,
     const char* file) {
     const char* file) {
-
-    // Create the application root logger and set the default severity and
-    // debug level.  This is the logger that has the name of the application.
-    // All other loggers created in this application will be its children.
-    setRootLoggerName(root);
-    Logger root_logger(isc::log::getRootLoggerName());
-
-    // Set the severity associated with it.  If no other logger has a severity,
-    // this will be the default.
-    root_logger.setSeverity(severity, dbglevel);
-
-    // Check if there were any duplicate message IDs in the default dictionary
-    // and if so, log them.  Log using the logging facility root logger.
-    vector<string>& duplicates = MessageInitializer::getDuplicates();
-    if (!duplicates.empty()) {
-
-        // There are - sort and remove any duplicates.
-        sort(duplicates.begin(), duplicates.end());
-        vector<string>::iterator new_end =
-            unique(duplicates.begin(), duplicates.end());
-        for (vector<string>::iterator i = duplicates.begin(); i != new_end; ++i) {
-            logger.warn(MSG_DUPMSGID).arg(*i);
-        }
-
-    }
-
-    // Replace any messages with local ones (if given)
-    if (file) {
-        readLocalMessageFile(file);
-    }
+    LoggerManager::init(root, file, severity, dbglevel);
 }
 }
 
 
 /// Logger Run-Time Initialization via Environment Variables
 /// Logger Run-Time Initialization via Environment Variables

+ 2 - 3
src/lib/log/tests/logger_support_test.cc

@@ -28,7 +28,6 @@
 #include <log/logger.h>
 #include <log/logger.h>
 #include <log/logger_manager.h>
 #include <log/logger_manager.h>
 #include <log/logger_specification.h>
 #include <log/logger_specification.h>
-#include <log/logger_support.h>
 #include <log/macros.h>
 #include <log/macros.h>
 #include <log/root_logger_name.h>
 #include <log/root_logger_name.h>
 
 
@@ -146,7 +145,7 @@ int main(int argc, char** argv) {
     }
     }
 
 
     // Update the logging parameters
     // Update the logging parameters
-    initLogger(ROOT_NAME, isc::log::INFO, 0, localfile);
+    LoggerManager::init(ROOT_NAME, localfile, isc::log::INFO, 0);
 
 
     // Set an output option if we have not done so already.
     // Set an output option if we have not done so already.
     if (! (c_found || f_found || l_found)) {
     if (! (c_found || f_found || l_found)) {
@@ -157,7 +156,7 @@ int main(int argc, char** argv) {
 
 
     // Set the logging options for the root logger.
     // Set the logging options for the root logger.
     LoggerManager manager;
     LoggerManager manager;
-    manager.process(spec);
+    //manager.process(spec);
 
 
 
 
     // Log a few messages
     // Log a few messages