Browse Source

[trac555] Checkpoint

Checkpoint of work at end of 23 May (so that code is copied down to
the BIND 10 server).  Work is in progress on the logger manager
implementation class.
Stephen Morris 14 years ago
parent
commit
58ec390c5c

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

@@ -14,6 +14,7 @@ liblog_la_SOURCES += logger_impl.cc logger_impl.h
 liblog_la_SOURCES += logger_level.h
 liblog_la_SOURCES += logger_level.h
 liblog_la_SOURCES += logger_level_impl.cc logger_level_impl.h
+liblog_la_SOURCES += logger_manager.cc logger_manager.h
 liblog_la_SOURCES += logger_specification.h
 liblog_la_SOURCES += logger_support.cc logger_support.h
 liblog_la_SOURCES += macros.h

+ 44 - 0
src/lib/log/logger_manager.cc

@@ -0,0 +1,44 @@
+// 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.
+
+#include <log/logger_manager_impl.h>
+#include <log/logger_manager.h>
+
+// Constructor - create the implementation  class.
+LoggerManager::LoggerManager() {
+    impl_ = new LoggerManagerImpl();
+}
+
+// Destructor - get rid of the implementation class
+LoggerManager::~LoggerManager() {
+    delete impl_;
+}
+
+// Initialize processing
+void
+LoggerManager::processInit() {
+    impl_->processInit();
+}
+
+// Process loggging specification
+void
+LoggerManager::processSpecification(const LoggerSpecification& spec) {
+    impl_->processSpecification(spec);
+}
+
+// End Processing
+void
+LoggerManager::processEnd() {
+    impl_->processEnd();
+}

+ 88 - 0
src/lib/log/logger_manager.h

@@ -0,0 +1,88 @@
+// 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.
+
+#ifndef __LOGGER_MANAGER_H
+#define __LOGGER_MANAGER_H
+
+#include </log/logger_specification.h>
+
+namespace isc {
+namespace log {
+
+class LoggerManagerImpl;
+
+/// \brief Logger Manager
+///
+/// The logger manager class exists to process the set of logger specifications
+/// and use them to set up the logging in the program appropriately.
+///
+/// To isolate the underlying implementation from basic processing, the
+/// LoggerManager is implemented using the "pimpl" idiom.
+
+class LoggerManager {
+public:
+    /// \brief Constructor
+    LoggerManager();
+
+    /// \brief Destructor
+    ~LoggerManager();
+
+    /// \brief Process Specifications
+    ///
+    /// Given a list of logger specifications, disables all current logging
+    /// and resets the properties of each logger to that given.
+    ///
+    /// \param start Iterator pointing to the start of the collection of
+    ///        logging specifications.
+    /// \param finish Iterator pointing to the end of the collection of
+    ///        logging specification.
+    template <typename T>
+    void process(T start, T finish) {
+        processInit();
+        for (T i = start; i != finish; ++i) {
+            processSpecification(*i);
+        }
+        processEnd();
+    }
+
+private:
+    /// \brief Initialize Processing
+    ///
+    /// Initializes the processing of a list of specifications by resetting all
+    /// loggers to their defaults.  Note that loggers aren't removed as unless
+    /// a previously-enabled logger is re-enabled, it becomes inactive.
+    void processInit();
+
+    /// \brief Process Logging Specification
+    ///
+    /// Processes the given specification.  It is assumed at this point that
+    /// either the logger does not exist or has been made inactive.
+    void processSpecification(const LoggerSpecification& spec);
+
+
+    /// \brief End Processing
+    ///
+    /// Place holder for finish processing.
+    /// TODO: Check that the root logger has something enabled
+    void processEnd();
+
+    // Members
+    LoggerManagerImpl*  impl_;      ///< Pointer to implementation
+};
+
+} // namespace log
+} // namespace isc
+
+
+#endif // __LOGGER_MANAGER_H

+ 62 - 0
src/lib/log/logger_manager_impl.h

@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef __LOGGER_MANAGER_IMPL_H
+#define __LOGGER_MANAGER_IMPL_H
+
+#include <log/logger_specification.h>
+
+namespace isc {
+namespace log {
+
+/// \brief Logger Manager Implementation
+///
+/// This is the implementation of the logger manager for the log4cplus
+/// underlying logger.
+///
+/// As noted in logger_manager.h, the logger manager class exists to set up the
+/// logging given a set of specifications.  This class handles the processing
+/// of those specifications.
+
+class LoggerManagerImpl {
+public:
+
+    /// \brief Constructor
+    LoggerManagerImpl()
+    {}
+
+    /// \brief Initialize Processing
+    ///
+    /// 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
+    /// root logger reset to logging informational messages.
+    void processInit();
+
+    /// \brief Process Specification
+    ///
+    /// Processes the specification for a single logger.
+    ///
+    /// \param spec Logging specification for this logger
+    void process(const LoggerSpecification& spec);
+
+    /// \brief End Processing
+    ///
+    /// Terminates the processing of the logging specifications.
+    void processEnd();
+};
+
+} // namespace log
+} // namespace isc
+
+#endif // __LOGGER_MANAGER_IMPL_H

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

@@ -17,6 +17,7 @@ run_unittests_SOURCES  = run_unittests.cc
 run_unittests_SOURCES += log_formatter_unittest.cc
 run_unittests_SOURCES += logger_level_impl_unittest.cc
 run_unittests_SOURCES += logger_level_unittest.cc
+run_unittests_SOURCES += logger_manager_unittest.cc
 run_unittests_SOURCES += logger_unittest.cc
 run_unittests_SOURCES += logger_specification_unittest.cc
 run_unittests_SOURCES += message_dictionary_unittest.cc

+ 183 - 0
src/lib/log/tests/logger_manager_unittest.cc

@@ -0,0 +1,183 @@
+// 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.
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <log/macros.h>
+#include <log/messagedef.h>
+#include <log/logger.h>
+#include <log/logger_level.h>
+#include <log/logger_manager.h>
+#include <log/logger_specification.h>
+#include <log/output_option.h>
+
+using namespace isc::log;
+using namespace std;
+
+/// \brief Derived logger
+///
+/// Only exists to make the protected static methods in Logger public for
+/// test purposes.
+
+class DerivedLogger : public isc::log::Logger {
+public:
+    DerivedLogger(std::string name) : isc::log::Logger(name)
+    {}
+    virtual ~DerivedLogger()
+    {}
+
+    static void reset() {
+        isc::log::Logger::reset();
+    }
+};
+
+/// \brief LoggerManager Test
+class LoggerManagerTest : public ::testing::Test {
+public:
+    LoggerManagerTest()
+    {}
+    ~LoggerManagerTest()
+    {
+        DerivedLogger::reset();
+    }
+};
+
+
+
+// Convenience class to create the specification for the logger "filelogger",
+// which, as the name suggests, logs to a file.  It remembers the file name and
+// deletes the file when instance of the class is destroyed.
+class SpecificationForFileLogger {
+public:
+
+    // Constructor - allocate file and create the specification object
+    SpecificationForFileLogger() : spec_(), name_(""), logname_("filelogger") {
+        OutputOption option;
+        option.destination = OutputOption::DEST_FILE;
+        name_ = option.filename = std::string(tmpnam(NULL));
+
+        spec_.setName(logname_);
+        spec_.addOutputOption(option);
+    }
+
+    // Destructor, remove the file.  This is only a test, so ignore failures
+    ~SpecificationForFileLogger() {
+        if (! name_.empty()) {
+            (void) unlink(name_.c_str());
+        }
+    }
+
+    // Return reference to the logging specification for this loggger
+    LoggerSpecification& getSpecification() {
+        return spec_;
+    }
+
+    // Return name of the logger
+    string getLoggerName() const {
+        return logname_;
+    }
+
+    // Return name of the file
+    string getFileName() const {
+        return name_;
+    }
+
+
+private:
+    LoggerSpecification     spec_;      // Specification for this file logger
+    string                  name_;      // Name of the output file
+    string                  logname_;   // Name of this logger
+};
+
+
+// Convenience function to read an output log file and check that each line
+// contains the expected message ID
+//
+// \param filename Name of the file to check
+// \param start Iterator pointing to first expected message ID
+// \param finish Iterator pointing to last expected message ID
+template <typename T>
+void checkFileContents(const std::string& filename, T start, T finish) {
+
+    // Access the file for input
+    ifstream infile(filename.c_str());
+    if (! infile.good()) {
+        FAIL() << "Unable to open the logging file " << filename;
+    }
+
+    // Iterate round the expected message IDs and check that they appear in
+    // the string.
+    string line;    // Line read from the file
+
+    T i = start;    // Iterator
+    getline(infile, line);
+    int lineno = 1;
+
+    while ((i != finish) && (infile.good())) {
+
+        // Check that the message ID appears in the line.
+        EXPECT_TRUE(line.find(string(*i)) != string::npos)
+            << "Expected to find " << string(*i) << " on line " << lineno
+            << " of logging file " << filename;
+
+        // Go for the next line
+        ++i;
+        getline(infile, line);
+        ++lineno;
+    }
+
+    // Why did the loop end?
+    EXPECT_TRUE(i == finish) << "Did not reach the end of the message ID list";
+    EXPECT_TRUE(infile.eof()) << "Did not reach the end of the logging file";
+
+    // File will close when the instream is deleted at the end of this
+    // function.
+}
+
+// Check that the logger correctly creates something logging to a file.
+TEST_F(LoggerManagerTest, FileLogger) {
+
+    // Create a specification for the file logger and use the manager to
+    // connect the "filelogger" logger to it.
+    SpecificationForFileLogger file_spec;
+    vector<LoggerSpecification> specVector(1, file_spec.getSpecification());
+    LoggerManager manager;
+    manager.process(specVector.begin(), specVector.end());
+
+    // Try logging to the file.  Local scope is set to ensure that the logger
+    // is destroyed before we reset the global logging.  We record what we
+    // put in the file for a later comparison.
+    vector<MessageID> ids;
+    {
+        Logger logger(file_spec.getLoggerName());
+
+        LOG_FATAL(logger, MSG_DUPMSGID).arg("test");
+        ids.push_back(MSG_DUPMSGID);
+
+        LOG_FATAL(logger, MSG_DUPLNS).arg("test");
+        ids.push_back(MSG_DUPLNS);
+    }
+    DerivedLogger::reset();
+
+    // At this point, the output file should contain two lines with messages
+    // LOGTEST_TEST1 and LOGTEST_TEST2 messages - test this.
+    checkFileContents(file_spec.getFileName(), ids.begin(), ids.end());
+}