// Copyright (C) 2011-2024 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 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& 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 (auto const& i : duplicates) { 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(*i); logger.warn(LOG_NO_SUCH_MESSAGE).arg(message_id); } } catch (const MessageException& e) { MessageID ident = e.id(); vector args = e.arguments(); // Log the variable number of arguments. The actual message will be // logged when the error_message variable is destroyed. Formatter error_message = logger.error(ident); for (vector::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