diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/log/logger_manager.cc | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/src/lib/log/logger_manager.cc b/src/lib/log/logger_manager.cc new file mode 100644 index 0000000..1890706 --- /dev/null +++ b/src/lib/log/logger_manager.cc @@ -0,0 +1,216 @@ +// Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <algorithm> +#include <vector> + +#include <log/logger.h> +#include <log/logger_manager.h> +#include <log/logger_manager_impl.h> +#include <log/logger_name.h> +#include <log/logger_support.h> +#include <log/log_messages.h> +#include <log/macros.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/interprocess/interprocess_sync_null.h> + +using namespace std; + +// Older log4cplus versions (1.2.0) don't have the initializer.h header that +// would allow explicit initialization. Newer versions (2.0.4 for sure, possibly +// older as well) have it and it's recommended to use it. We detect whether +// it's present or not and do explicit initialization if possible. +#ifdef LOG4CPLUS_INITIALIZER_H +#include <log4cplus/initializer.h> +namespace { +log4cplus::Initializer initializer; +} +#endif + +namespace { + +// Logger used for logging messages within the logging code itself. +isc::log::Logger logger("log"); + +// Static stores for the initialization severity and debug level. +// These are put in methods to avoid a "static initialization fiasco". + +isc::log::Severity& initSeverity() { + static isc::log::Severity severity = isc::log::INFO; + return (severity); +} + +int& initDebugLevel() { + static int dbglevel = 0; + return (dbglevel); +} + +std::string& initRootName() { + static std::string root(isc::log::getDefaultRootLoggerName()); + return (root); +} + +} // Anonymous namespace + + +namespace isc { +namespace log { + +// 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 logging specification +void +LoggerManager::processSpecification(const LoggerSpecification& spec) { + impl_->processSpecification(spec); +} + +// End Processing +void +LoggerManager::processEnd() { + impl_->processEnd(); +} + + +/// Logging system initialization + +void +LoggerManager::init(const std::string& root, isc::log::Severity severity, + int dbglevel, const char* file, bool buffer) +{ + // Load in the messages declared in the program and registered by + // statically-declared MessageInitializer objects. + MessageInitializer::loadDictionary(); + + // Save name, severity and debug level for later. No need to save the + // file name as once the local message file is read the messages will + // not be lost. + initRootName() = root; + initSeverity() = severity; + initDebugLevel() = dbglevel; + + // Create the Kea 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. After this point, some basic + // logging has been set up and messages can be logged. + // However, they will not appear until a logging specification has been + // processed (or the program exits), see TODO + LoggerManagerImpl::init(severity, dbglevel, buffer); + setLoggingInitialized(); + + // Check if there were any duplicate message IDs in the default dictionary + // and if so, log them. Log using the logging facility logger. + logDuplicatedMessages(); + + // Replace any messages with local ones (if given) + if (file) { + readLocalMessageFile(file); + } + + // Ensure that the mutex is constructed and ready at this point. + (void) getMutex(); +} + +void +LoggerManager::logDuplicatedMessages() { + const list<string>& duplicates = MessageInitializer::getDuplicates(); + if (!duplicates.empty()) { + + // There are duplicates present. This list itself may contain + // duplicates; if so, the message ID is listed as many times as + // there are duplicates. + for (list<string>::const_iterator i = duplicates.begin(); + i != duplicates.end(); ++i) { + LOG_WARN(logger, LOG_DUPLICATE_MESSAGE_ID).arg(*i); + } + MessageInitializer::clearDuplicates(); + } +} + + +// Read local message file +// TODO This should be done after the configuration has been read so that +// the file can be placed in the local configuration +void +LoggerManager::readLocalMessageFile(const char* file) { + + const MessageDictionaryPtr& dictionary = MessageDictionary::globalDictionary(); + MessageReader reader(dictionary.get()); + + // Turn off use of any lock files. This is because this logger can + // be used by standalone programs which may not have write access to + // the local state directory (to create lock files). So we switch to + // using a null interprocess sync object here. + logger.setInterprocessSync( + new isc::log::interprocess::InterprocessSyncNull("logger")); + + try { + + logger.info(LOG_READING_LOCAL_FILE).arg(file); + reader.readFile(file, MessageReader::REPLACE); + + // File successfully read. As each message in the file is supposed to + // replace one in the dictionary, any ID read that can't be located in + // the dictionary will not be used. To aid problem diagnosis, the + // unknown message IDs are listed. + 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(LOG_NO_SUCH_MESSAGE).arg(message_id); + } + } + catch (const MessageException& e) { + MessageID ident = e.id(); + vector<string> args = e.arguments(); + + // Log the variable number of arguments. The actual message will be + // logged when the error_message variable is destroyed. + Formatter<isc::log::Logger> error_message = logger.error(ident); + for (vector<string>::size_type i = 0; i < args.size(); ++i) { + error_message = error_message.arg(args[i]); + } + } +} + +// Reset logging to settings passed to init() +void +LoggerManager::reset() { + setRootLoggerName(initRootName()); + LoggerManagerImpl::reset(initSeverity(), initDebugLevel()); +} + +std::mutex& +LoggerManager::getMutex() { + static std::mutex mutex; + + return (mutex); +} + +} // namespace log +} // namespace isc |