summaryrefslogtreecommitdiffstats
path: root/src/lib/log/logger_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/log/logger_manager.cc')
-rw-r--r--src/lib/log/logger_manager.cc216
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