logger_manager.cc 6.66 KB
Newer Older
Stephen Morris's avatar
Stephen Morris committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 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.

15 16 17 18
#include <algorithm>
#include <vector>

#include <log/logger.h>
Stephen Morris's avatar
Stephen Morris committed
19
#include <log/logger_manager.h>
20
#include <log/logger_manager_impl.h>
21
#include <log/logger_name.h>
22
#include <log/logger_support.h>
23 24
#include <log/log_messages.h>
#include <log/macros.h>
25 26 27
#include <log/message_dictionary.h>
#include <log/message_exception.h>
#include <log/message_initializer.h>
28
#include <log/message_initializer.h>
29 30
#include <log/message_reader.h>
#include <log/message_types.h>
31
#include <log/interprocess/interprocess_sync_null.h>
32 33

using namespace std;
Stephen Morris's avatar
Stephen Morris committed
34

35 36 37 38
namespace {

// Logger used for logging messages within the logging code itself.
isc::log::Logger logger("log");
39 40 41 42 43 44 45

// 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);
46 47
}

48 49 50 51 52 53
int& initDebugLevel() {
    static int dbglevel = 0;
    return (dbglevel);
}

std::string& initRootName() {
54
    static std::string root("kea");
55 56 57 58 59 60
    return (root);
}

} // Anonymous namespace


61 62 63
namespace isc {
namespace log {

Stephen Morris's avatar
Stephen Morris committed
64 65 66 67 68 69 70 71 72 73 74 75 76
// 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() {
77
    impl_->processInit();
Stephen Morris's avatar
Stephen Morris committed
78 79
}

80
// Process logging specification
Stephen Morris's avatar
Stephen Morris committed
81 82 83 84 85 86 87 88 89 90
void
LoggerManager::processSpecification(const LoggerSpecification& spec) {
    impl_->processSpecification(spec);
}

// End Processing
void
LoggerManager::processEnd() {
    impl_->processEnd();
}
91

92 93 94 95

/// Logging system initialization

void
96
LoggerManager::init(const std::string& root, isc::log::Severity severity,
97
                    int dbglevel, const char* file, bool buffer)
98
{
99
    // Load in the messages declared in the program and registered by
100 101 102
    // statically-declared MessageInitializer objects.
    MessageInitializer::loadDictionary();

103 104 105 106 107 108 109
    // 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;

110 111 112 113 114
    // 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);

Stephen Morris's avatar
Stephen Morris committed
115 116
    // Initialize the implementation logging.  After this point, some basic
    // logging has been set up and messages can be logged.
117 118 119
    // However, they will not appear until a logging specification has been
    // processed (or the program exits), see TODO
    LoggerManagerImpl::init(severity, dbglevel, buffer);
120
    setLoggingInitialized();
121 122

    // Check if there were any duplicate message IDs in the default dictionary
123
    // and if so, log them.  Log using the logging facility logger.
Jelte Jansen's avatar
Jelte Jansen committed
124
    const vector<string>& duplicates = MessageInitializer::getDuplicates();
125 126
    if (!duplicates.empty()) {

Jelte Jansen's avatar
Jelte Jansen committed
127 128
        // There are duplicates present. This list itself may contain
        // duplicates; if so, the message ID is listed as many times as
Stephen Morris's avatar
Stephen Morris committed
129
        // there are duplicates.
Jelte Jansen's avatar
Jelte Jansen committed
130
        for (vector<string>::const_iterator i = duplicates.begin();
Stephen Morris's avatar
Stephen Morris committed
131
             i != duplicates.end(); ++i) {
132
            LOG_WARN(logger, LOG_DUPLICATE_MESSAGE_ID).arg(*i);
133
        }
134
        MessageInitializer::clearDuplicates();
135 136 137 138 139 140
    }

    // Replace any messages with local ones (if given)
    if (file) {
        readLocalMessageFile(file);
    }
141 142 143

    // Ensure that the mutex is constructed and ready at this point.
    (void) getMutex();
144 145 146
}


Stephen Morris's avatar
Stephen Morris committed
147
// Read local message file
Stephen Morris's avatar
Stephen Morris committed
148 149
// TODO This should be done after the configuration has been read so that
// the file can be placed in the local configuration
150 151 152 153 154
void
LoggerManager::readLocalMessageFile(const char* file) {

    MessageDictionary& dictionary = MessageDictionary::globalDictionary();
    MessageReader reader(&dictionary);
155

156 157 158 159
    // 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.
160
    logger.setInterprocessSync(
161
        new isc::log::interprocess::InterprocessSyncNull("logger"));
162

163
    try {
Stephen Morris's avatar
Stephen Morris committed
164

165
        logger.info(LOG_READING_LOCAL_FILE).arg(file);
166 167
        reader.readFile(file, MessageReader::REPLACE);

Stephen Morris's avatar
Stephen Morris committed
168 169 170 171
        // 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.
172 173 174 175
        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);
176
                logger.warn(LOG_NO_SUCH_MESSAGE).arg(message_id);
177 178 179 180 181 182
        }
    }
    catch (MessageException& e) {
        MessageID ident = e.id();
        vector<string> args = e.arguments();

Stephen Morris's avatar
Stephen Morris committed
183 184
        // Log the variable number of arguments.  The actual message will be
        // logged when the error_message variable is destroyed.
185
        Formatter<isc::log::Logger> error_message = logger.error(ident);
186
        for (vector<string>::size_type i = 0; i < args.size(); ++i) {
187
            error_message = error_message.arg(args[i]);
188 189 190 191
        }
    }
}

192
// Reset logging to settings passed to init()
Stephen Morris's avatar
Stephen Morris committed
193
void
194
LoggerManager::reset() {
195
    setRootLoggerName(initRootName());
196
    LoggerManagerImpl::reset(initSeverity(), initDebugLevel());
Stephen Morris's avatar
Stephen Morris committed
197 198
}

199 200 201 202 203 204 205
isc::util::thread::Mutex&
LoggerManager::getMutex() {
    static isc::util::thread::Mutex mutex;

    return (mutex);
}

206 207
} // namespace log
} // namespace isc