Kea 1.5.0
logger_manager_impl.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <algorithm>
10#include <iostream>
11
12#include <log4cplus/logger.h>
13#include <log4cplus/configurator.h>
14#include <log4cplus/hierarchy.h>
15#include <log4cplus/consoleappender.h>
16#include <log4cplus/fileappender.h>
17#include <log4cplus/syslogappender.h>
18#include <log4cplus/helpers/loglog.h>
19#include <log4cplus/version.h>
20
21#include <log/logger.h>
22#include <log/logger_support.h>
24#include <log/logger_manager.h>
26#include <log/log_messages.h>
27#include <log/logger_name.h>
30
31#include <boost/lexical_cast.hpp>
32
33using namespace std;
34using boost::lexical_cast;
35
36namespace isc {
37namespace log {
38
39// Reset hierarchy of loggers back to default settings. This removes all
40// appenders from loggers, sets their severity to NOT_SET (so that events are
41// passed back to the parent) and resets the root logger to logging
42// informational messages. (This last is not a log4cplus default, so we have to
43// explicitly reset the logging severity.)
44void
46 storeBufferAppenders();
47
48 log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
49 initRootLogger();
50}
51
52// Flush the BufferAppenders at the end of processing a new specification
53void
55 flushBufferAppenders();
56}
57
58// Process logging specification. Set up the common states then dispatch to
59// add output specifications.
60void
62 log4cplus::Logger logger = log4cplus::Logger::getInstance(
64
65 // Set severity level according to specification entry.
67 Level(spec.getSeverity(), spec.getDbglevel())));
68
69 // Set the additive flag.
70 logger.setAdditivity(spec.getAdditive());
71
72 // Output options given?
73 if (spec.optionCount() > 0) {
74 // Replace all appenders for this logger.
75 logger.removeAllAppenders();
76
77 // Now process output specifications.
79 i != spec.end(); ++i) {
80 switch (i->destination) {
82 createConsoleAppender(logger, *i);
83 break;
84
86 createFileAppender(logger, *i);
87 break;
88
90 createSyslogAppender(logger, *i);
91 break;
92
93 default:
94 // Not a valid destination. As we are in the middle of updating
95 // logging destinations, we could be in the situation where
96 // there are no valid appenders. For this reason, throw an
97 // exception.
99 "Unknown logging destination, code = " <<
100 i->destination);
101 }
102 }
103 }
104}
105
106// Console appender - log to either stdout or stderr.
107void
108LoggerManagerImpl::createConsoleAppender(log4cplus::Logger& logger,
109 const OutputOption& opt)
110{
111 log4cplus::SharedAppenderPtr console(
112 new log4cplus::ConsoleAppender(
113 (opt.stream == OutputOption::STR_STDERR), opt.flush));
114 setConsoleAppenderLayout(console);
115 logger.addAppender(console);
116}
117
118// File appender. Depending on whether a maximum size is given, either
119// a standard file appender or a rolling file appender will be created.
120// In the case of the latter, we set "UseLockFile" to true so that
121// log4cplus internally avoids race in rolling over the files by multiple
122// processes. This feature isn't supported in log4cplus 1.0.x, but setting
123// the property unconditionally is okay as unknown properties are simply
124// ignored.
125void
126LoggerManagerImpl::createFileAppender(log4cplus::Logger& logger,
127 const OutputOption& opt)
128{
129 // Append to existing file
130 const std::ios::openmode mode = std::ios::app;
131
132 log4cplus::SharedAppenderPtr fileapp;
133 if (opt.maxsize == 0) {
134 fileapp = log4cplus::SharedAppenderPtr(new log4cplus::FileAppender(
135 opt.filename, mode, opt.flush));
136 } else {
137 log4cplus::helpers::Properties properties;
138 properties.setProperty("File", opt.filename);
139 properties.setProperty("MaxFileSize",
140 lexical_cast<string>(opt.maxsize));
141 properties.setProperty("MaxBackupIndex",
142 lexical_cast<string>(opt.maxver));
143 properties.setProperty("ImmediateFlush", opt.flush ? "true" : "false");
144 properties.setProperty("UseLockFile", "true");
145 fileapp = log4cplus::SharedAppenderPtr(
146 new log4cplus::RollingFileAppender(properties));
147 }
148
149 // use the same console layout for the files.
150 setConsoleAppenderLayout(fileapp);
151 logger.addAppender(fileapp);
152}
153
154void
155LoggerManagerImpl::createBufferAppender(log4cplus::Logger& logger) {
156 log4cplus::SharedAppenderPtr bufferapp(new internal::BufferAppender());
157 bufferapp->setName("buffer");
158 logger.addAppender(bufferapp);
159 // Since we do not know at what level the loggers will end up
160 // running, set it to the highest for now
161 logger.setLogLevel(log4cplus::TRACE_LOG_LEVEL);
162}
163
164// Syslog appender.
165void
166LoggerManagerImpl::createSyslogAppender(log4cplus::Logger& logger,
167 const OutputOption& opt)
168{
169 log4cplus::helpers::Properties properties;
170 properties.setProperty("ident", getRootLoggerName());
171 properties.setProperty("facility", opt.facility);
172 log4cplus::SharedAppenderPtr syslogapp(
173 new log4cplus::SysLogAppender(properties));
174 setSyslogAppenderLayout(syslogapp);
175 logger.addAppender(syslogapp);
176}
177
178
179// One-time initialization of the log4cplus system
180void
182 bool buffer)
183{
184 // Set up basic configurator. This attaches a ConsoleAppender to the
185 // root logger with suitable output. This is used until we we have
186 // actually read the logging configuration, in which case the output
187 // may well be changed.
188 log4cplus::BasicConfigurator config;
189 config.configure();
190
191 // Add the additional debug levels
193
194 initRootLogger(severity, dbglevel, buffer);
195}
196
197// Reset logging to default configuration. This closes all appenders
198// and resets the root logger to output INFO messages to the console.
199// It is principally used in testing.
200void
202{
203 // Initialize the root logger
204 initRootLogger(severity, dbglevel);
205}
206
207// Initialize the root logger
208void LoggerManagerImpl::initRootLogger(isc::log::Severity severity,
209 int dbglevel, bool buffer)
210{
211 log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
212
213 // Disable log4cplus' own logging, unless --enable-debug was
214 // specified to configure. Note that this does not change
215 // LogLog's levels (that is still just INFO).
216#ifndef ENABLE_DEBUG
217 log4cplus::helpers::LogLog::getLogLog()->setQuietMode(true);
218#endif
219
220 // Set the log4cplus root to not output anything - effectively we are
221 // ignoring it.
222 log4cplus::Logger::getRoot().setLogLevel(log4cplus::OFF_LOG_LEVEL);
223
224 // Set the level for the Kea root logger to the given severity and
225 // debug level.
226 log4cplus::Logger kea_root = log4cplus::Logger::getInstance(
228 kea_root.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
229 Level(severity, dbglevel)));
230
231 if (buffer) {
232 createBufferAppender(kea_root);
233 } else {
234 OutputOption opt;
235 createConsoleAppender(kea_root, opt);
236 }
237}
238
239void LoggerManagerImpl::setConsoleAppenderLayout(
240 log4cplus::SharedAppenderPtr& appender)
241{
242 // Create the pattern we want for the output - local time.
243 string pattern = "%D{%Y-%m-%d %H:%M:%S.%q} %-5p [%c/%i] %m\n";
244
245 // Finally the text of the message
246 appender->setLayout(
247#if LOG4CPLUS_VERSION < LOG4CPLUS_MAKE_VERSION(2, 0, 0)
248 auto_ptr<log4cplus::Layout>
249#else
250 unique_ptr<log4cplus::Layout>
251#endif
252 (new log4cplus::PatternLayout(pattern)));
253}
254
255// Set the the "syslog" layout for the given appenders. This is the same
256// as the console, but without the timestamp (which is expected to be
257// set by syslogd).
258
259void LoggerManagerImpl::setSyslogAppenderLayout(
260 log4cplus::SharedAppenderPtr& appender)
261{
262 // Create the pattern we want for the output - local time.
263 string pattern = "%-5p [%c] %m\n";
264
265 // Finally the text of the message
266 appender->setLayout(
267#if LOG4CPLUS_VERSION < LOG4CPLUS_MAKE_VERSION(2, 0, 0)
268 auto_ptr<log4cplus::Layout>
269#else
270 unique_ptr<log4cplus::Layout>
271#endif
272 (new log4cplus::PatternLayout(pattern)));
273}
274
275void LoggerManagerImpl::storeBufferAppenders() {
276 // Walk through all loggers, and find any buffer appenders there
277 log4cplus::LoggerList loggers = log4cplus::Logger::getCurrentLoggers();
278 log4cplus::LoggerList::iterator it;
279 for (it = loggers.begin(); it != loggers.end(); ++it) {
280 log4cplus::SharedAppenderPtr buffer_appender =
281 it->getAppender("buffer");
282 if (buffer_appender) {
283 buffer_appender_store_.push_back(buffer_appender);
284 }
285 }
286}
287
288void LoggerManagerImpl::flushBufferAppenders() {
289 std::vector<log4cplus::SharedAppenderPtr> copy;
290 buffer_appender_store_.swap(copy);
291
292 std::vector<log4cplus::SharedAppenderPtr>::iterator it;
293 for (it = copy.begin(); it != copy.end(); ++it) {
294 internal::BufferAppender* app =
295 dynamic_cast<internal::BufferAppender*>(it->get());
296 assert(app != NULL);
297 app->flush();
298 }
299}
300
301} // namespace log
302} // namespace isc
static log4cplus::LogLevel convertFromBindLevel(const isc::log::Level &level)
Convert Kea level to log4cplus logging level.
static void init()
Initialize extended logging levels.
static void processSpecification(const LoggerSpecification &spec)
Process Specification.
void processEnd()
End Processing.
static void init(isc::log::Severity severity=isc::log::INFO, int dbglevel=0, bool buffer=false)
Implementation-specific initialization.
static void reset(isc::log::Severity severity=isc::log::INFO, int dbglevel=0)
Reset logging.
void processInit()
Initialize Processing.
isc::log::Severity getSeverity() const
std::vector< OutputOption >::const_iterator const_iterator
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Logging initialization functions.
isc::log::Logger logger("asiodns")
Use the ASIO logger.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1114
const std::string & getRootLoggerName()
Get root logger name.
Definition: logger_name.cc:33
std::string expandLoggerName(const std::string &name)
Expand logger name.
Definition: logger_name.cc:42
Severity
Severity Levels.
Definition: logger_level.h:23
Defines the logger used by the top-level component of kea-dhcp-ddns.
Log level structure.
Definition: logger_level.h:42
bool flush
true to flush after each message
Definition: output_option.h:63
Stream stream
stdout/stderr if console output
Definition: output_option.h:62