Commit 9e48d735 authored by Stephen Morris's avatar Stephen Morris
Browse files

[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).
parent cfa31a99
......@@ -45,9 +45,6 @@ namespace log {
// Constructor
LoggerImpl::LoggerImpl(const string& name)
{
// Initialize log4cplus if not already done
initLog4cplus();
// Are we the root logger?
if (name == getRootLoggerName()) {
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
// loggers - this appears awkward); this is effectively the same as removing
// them.
void
LoggerImpl::reset() {
log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
initialized() = false;
// 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
......
......@@ -192,23 +192,6 @@ public:
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
log4cplus::Logger logger_; ///< Underlying log4cplus logger
};
......
......@@ -12,8 +12,24 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <algorithm>
#include <vector>
#include <log/logger.h>
#include <log/logger_manager_impl.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 log {
......@@ -33,10 +49,10 @@ LoggerManager::~LoggerManager() {
// Initialize processing
void
LoggerManager::processInit() {
impl_->processInit();
impl_->processInit(getRootLoggerName());
}
// Process loggging specification
// Process logging specification
void
LoggerManager::processSpecification(const LoggerSpecification& spec) {
impl_->processSpecification(spec);
......@@ -48,5 +64,87 @@ LoggerManager::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 isc
......@@ -67,12 +67,20 @@ public:
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:
/// \brief Initialize Processing
......@@ -88,13 +96,21 @@ private:
/// 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();
/// \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
LoggerManagerImpl* impl_; ///< Pointer to implementation
};
......
......@@ -12,6 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <algorithm>
#include <log4cplus/logger.h>
#include <log4cplus/configurator.h>
#include <log4cplus/consoleappender.h>
......@@ -21,6 +23,9 @@
#include "log/logger_specification.h"
#include "log/root_logger_name.h"
#include "log/logger.h"
#include "log/messagedef.h"
#include "exceptions/exceptions.h"
// 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
// explicitly reset the logging severity.)
using namespace std;
namespace isc {
namespace log {
......@@ -46,9 +53,9 @@ namespace log {
// configuration update removes the logger.)
void
LoggerManagerImpl::processInit() {
LoggerManagerImpl::processInit(const std::string& root_name) {
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
......@@ -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 isc
......@@ -15,16 +15,24 @@
#ifndef __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.
namespace log4cplus {
class Logger;
class Appender;
}
namespace isc {
namespace log {
// Forward declarations
class LoggerSpecification;
class OutputOption;
/// \brief Logger Manager Implementation
///
/// 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
/// that all non-root loggers (if they exist) are set to NOT_SET, and the
/// 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
///
......@@ -60,6 +70,16 @@ public:
/// Terminates the processing of the logging specifications.
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:
/// \brief Create console appender
///
......@@ -91,6 +111,30 @@ private:
/// \param opt Output options for this appender.
void createSyslogAppender(log4cplus::Logger& logger,
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
......
......@@ -28,18 +28,10 @@
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <log/logger.h>
#include <log/logger_manager.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 log {
......@@ -50,88 +42,12 @@ using namespace std;
// root logger and is used in all functions in this file.
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
void
initLogger(const string& root, isc::log::Severity severity, int dbglevel,
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
......
......@@ -28,7 +28,6 @@
#include <log/logger.h>
#include <log/logger_manager.h>
#include <log/logger_specification.h>
#include <log/logger_support.h>
#include <log/macros.h>
#include <log/root_logger_name.h>
......@@ -146,7 +145,7 @@ int main(int argc, char** argv) {
}
// 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.
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.
LoggerManager manager;
manager.process(spec);
//manager.process(spec);
// Log a few messages
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment