logger_manager_impl.cc 8.73 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
#include <algorithm>
Stephen Morris's avatar
Stephen Morris committed
16
#include <iostream>
17

Stephen Morris's avatar
Stephen Morris committed
18
19
#include <log4cplus/logger.h>
#include <log4cplus/configurator.h>
20
#include <log4cplus/hierarchy.h>
Stephen Morris's avatar
Stephen Morris committed
21
#include <log4cplus/consoleappender.h>
Stephen Morris's avatar
Stephen Morris committed
22
#include <log4cplus/fileappender.h>
23
#include <log4cplus/syslogappender.h>
Stephen Morris's avatar
Stephen Morris committed
24

25
#include <log/logger.h>
Jelte Jansen's avatar
Jelte Jansen committed
26
#include <log/logger_support.h>
27
28
29
30
31
32
#include <log/logger_level_impl.h>
#include <log/logger_manager.h>
#include <log/logger_manager_impl.h>
#include <log/log_messages.h>
#include <log/logger_name.h>
#include <log/logger_specification.h>
33
#include <log/log_buffer.h>
34

Jelte Jansen's avatar
Jelte Jansen committed
35
36
#include <boost/scoped_ptr.hpp>

37
38
using namespace std;

Stephen Morris's avatar
Stephen Morris committed
39
40
41
namespace isc {
namespace log {

Stephen Morris's avatar
Stephen Morris committed
42
43
44
45
46
// Reset hierarchy of loggers back to default settings.  This removes all
// appenders from loggers, sets their severity to NOT_SET (so that events are
// passed back to the parent) and resets the root logger to logging
// informational messages.  (This last is not a log4cplus default, so we have to
// explicitly reset the logging severity.)
Stephen Morris's avatar
Stephen Morris committed
47
void
48
LoggerManagerImpl::processInit() {
Stephen Morris's avatar
Stephen Morris committed
49
    log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
50
    initRootLogger();
Stephen Morris's avatar
Stephen Morris committed
51
52
53
54
55
56
}

// Process logging specification.  Set up the common states then dispatch to
// add output specifications.
void
LoggerManagerImpl::processSpecification(const LoggerSpecification& spec) {
Jelte Jansen's avatar
Jelte Jansen committed
57
58
59
60
61
62
    log4cplus::Logger logger;
    // If this is an 'empty' specification, just set the root logger
    if (spec.getName() == "") {
        logger = log4cplus::Logger::getInstance(getRootLoggerName());
    } else {
        logger = log4cplus::Logger::getInstance(
63
                                   expandLoggerName(spec.getName()));
Jelte Jansen's avatar
Jelte Jansen committed
64
    }
Stephen Morris's avatar
Stephen Morris committed
65
66
67
68
69
70
71
72

    // Set severity level according to specification entry.
    logger.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
                       Level(spec.getSeverity(), spec.getDbglevel())));

    // Set the additive flag.
    logger.setAdditivity(spec.getAdditive());

73
74
75
    // Replace all appenders for this logger.
    logger.removeAllAppenders();

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    // Output options given?
    if (spec.optionCount() > 0) {

        // Now process output specifications.
        for (LoggerSpecification::const_iterator i = spec.begin();
             i != spec.end(); ++i) {
            switch (i->destination) {
            case OutputOption::DEST_CONSOLE:
                createConsoleAppender(logger, *i);
                break;

            case OutputOption::DEST_FILE:
                createFileAppender(logger, *i);
                break;

            case OutputOption::DEST_SYSLOG:
92
                createSyslogAppender(logger, *i);
93
94
95
                break;

            default:
96
97
98
99
                // Not a valid destination.  As we are in the middle of updating
                // logging destinations, we could be in the situation where
                // there are no valid appenders.  For this reason, throw an
                // exception.
100
101
102
103
                isc_throw(UnknownLoggingDestination,
                          "Unknown logging destination, code = " <<
                          i->destination);
            }
Stephen Morris's avatar
Stephen Morris committed
104
        }
Jelte Jansen's avatar
Jelte Jansen committed
105
106
107
108
    } else {
        // If no output options are given, use a default appender
        OutputOption opt;
        createConsoleAppender(logger, opt);
Stephen Morris's avatar
Stephen Morris committed
109
    }
Jelte Jansen's avatar
Jelte Jansen committed
110
111
    // Should anything be left in the buffer, this is the time to flush it.
    getLogBuffer().flush();
Stephen Morris's avatar
Stephen Morris committed
112
113
114
115
116
117
118
119
120
121
}

// Console appender - log to either stdout or stderr.
void
LoggerManagerImpl::createConsoleAppender(log4cplus::Logger& logger,
                                         const OutputOption& opt)
{
    log4cplus::SharedAppenderPtr console(
        new log4cplus::ConsoleAppender(
            (opt.stream == OutputOption::STR_STDERR), opt.flush));
122
    setConsoleAppenderLayout(console);
Stephen Morris's avatar
Stephen Morris committed
123
124
125
    logger.addAppender(console);
}

Stephen Morris's avatar
Stephen Morris committed
126
127
128
129
130
131
// File appender.  Depending on whether a maximum size is given, either
// a standard file appender or a rolling file appender will be created.
void
LoggerManagerImpl::createFileAppender(log4cplus::Logger& logger,
                                         const OutputOption& opt)
{
132
133
    // Append to existing file
    std::ios::openmode mode = std::ios::app;
Stephen Morris's avatar
Stephen Morris committed
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

    log4cplus::SharedAppenderPtr fileapp;
    if (opt.maxsize == 0) {
        fileapp = log4cplus::SharedAppenderPtr(new log4cplus::FileAppender(
            opt.filename, mode, opt.flush));
    } else {
        fileapp = log4cplus::SharedAppenderPtr(
            new log4cplus::RollingFileAppender(opt.filename, opt.maxsize,
                                               opt.maxver, opt.flush));
    }

    // use the same console layout for the files.
    setConsoleAppenderLayout(fileapp);
    logger.addAppender(fileapp);
}

Jelte Jansen's avatar
Jelte Jansen committed
150
151
152
void
LoggerManagerImpl::createBufferAppender(log4cplus::Logger& logger)
{
153
    log4cplus::SharedAppenderPtr bufferapp(new BufferAppender(getLogBuffer()));
Jelte Jansen's avatar
Jelte Jansen committed
154
155
    bufferapp->setName("buffer");
    logger.addAppender(bufferapp);
156
157
158
    // Since we do not know at what level the loggers will end up
    // running, set it to the highest for now
    logger.setLogLevel(log4cplus::TRACE_LOG_LEVEL);
Jelte Jansen's avatar
Jelte Jansen committed
159
160
161
}

// Syslog appender.
162
void
163
LoggerManagerImpl::createSyslogAppender(log4cplus::Logger& logger,
164
165
166
167
                                         const OutputOption& opt)
{
    log4cplus::SharedAppenderPtr syslogapp(
        new log4cplus::SysLogAppender(opt.facility));
168
    setSyslogAppenderLayout(syslogapp);
169
170
171
    logger.addAppender(syslogapp);
}

Stephen Morris's avatar
Stephen Morris committed
172

173
174
// One-time initialization of the log4cplus system
void
175
176
177
LoggerManagerImpl::init(isc::log::Severity severity, int dbglevel,
                        bool buffer)
{
178
179
180
181
182
183
184
185
186
187
    // 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();

188
    initRootLogger(severity, dbglevel, buffer);
Stephen Morris's avatar
Stephen Morris committed
189
190
191
192
193
194
}

// Reset logging to default configuration.  This closes all appenders
// and resets the root logger to output INFO messages to the console.
// It is principally used in testing.
void
195
LoggerManagerImpl::reset(isc::log::Severity severity, int dbglevel)
196
{
Stephen Morris's avatar
Stephen Morris committed
197
    // Initialize the root logger
198
    initRootLogger(severity, dbglevel);
199
200
201
}

// Initialize the root logger
202
void LoggerManagerImpl::initRootLogger(isc::log::Severity severity,
203
                                       int dbglevel, bool buffer)
Stephen Morris's avatar
Stephen Morris committed
204
205
{
    log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
206

207
208
209
    // Set the log4cplus root to not output anything - effectively we are
    // ignoring it.
    log4cplus::Logger::getRoot().setLogLevel(log4cplus::OFF_LOG_LEVEL);
210

211
212
213
214
215
216
217
    // Set the level for the BIND 10 root logger to the given severity and
    // debug level.
    log4cplus::Logger b10root = log4cplus::Logger::getInstance(
                                                    getRootLoggerName());
    b10root.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
                                                    Level(severity, dbglevel)));

218
219
220
221
222
223
    if (buffer) {
        createBufferAppender(b10root);
    } else {
        OutputOption opt;
        createConsoleAppender(b10root, opt);
    }
224
225
226
}

void LoggerManagerImpl::setConsoleAppenderLayout(
227
        log4cplus::SharedAppenderPtr& appender)
228
229
{
    // Create the pattern we want for the output - local time.
230
    string pattern = "%D{%Y-%m-%d %H:%M:%S.%q} %-5p [%c/%i] %m\n";
231
232
233
234
235
236

    // Finally the text of the message
    auto_ptr<log4cplus::Layout> layout(new log4cplus::PatternLayout(pattern));
    appender->setLayout(layout);
}

237
238
239
240
// Set the the "syslog" layout for the given appenders.  This is the same
// as the console, but without the timestamp (which is expected to be
// set by syslogd).

241
void LoggerManagerImpl::setSyslogAppenderLayout(
242
243
244
        log4cplus::SharedAppenderPtr& appender)
{
    // Create the pattern we want for the output - local time.
245
    string pattern = "%-5p [%c] %m\n";
246
247
248
249
250
251

    // Finally the text of the message
    auto_ptr<log4cplus::Layout> layout(new log4cplus::PatternLayout(pattern));
    appender->setLayout(layout);
}

Stephen Morris's avatar
Stephen Morris committed
252
253
} // namespace log
} // namespace isc