Kea 2.2.0
logger_manager_impl.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2021 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#include <array>
12
13#include <log4cplus/logger.h>
14#include <log4cplus/configurator.h>
15#include <log4cplus/hierarchy.h>
16#include <log4cplus/consoleappender.h>
17#include <log4cplus/fileappender.h>
18#include <log4cplus/syslogappender.h>
19#include <log4cplus/helpers/loglog.h>
20#include <log4cplus/version.h>
21
22#include <log/logger.h>
23#include <log/logger_support.h>
25#include <log/logger_manager.h>
27#include <log/log_messages.h>
28#include <log/logger_name.h>
31
33
34#include <boost/lexical_cast.hpp>
35
36using namespace std;
37using boost::lexical_cast;
38
39namespace isc {
40namespace log {
41
42// Reset hierarchy of loggers back to default settings. This removes all
43// appenders from loggers, sets their severity to NOT_SET (so that events are
44// passed back to the parent) and resets the root logger to logging
45// informational messages. (This last is not a log4cplus default, so we have to
46// explicitly reset the logging severity.)
47void
49 storeBufferAppenders();
50
51 log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
52 initRootLogger();
53}
54
55// Flush the BufferAppenders at the end of processing a new specification
56void
58 flushBufferAppenders();
59}
60
61// Process logging specification. Set up the common states then dispatch to
62// add output specifications.
63void
65 log4cplus::Logger logger = log4cplus::Logger::getInstance(
67
68 // Set severity level according to specification entry.
70 Level(spec.getSeverity(), spec.getDbglevel())));
71
72 // Set the additive flag.
73 logger.setAdditivity(spec.getAdditive());
74
75 // Output options given?
76 if (spec.optionCount() > 0) {
77 // Replace all appenders for this logger.
78 logger.removeAllAppenders();
79
80 // Now process output specifications.
82 i != spec.end(); ++i) {
83 switch (i->destination) {
85 createConsoleAppender(logger, *i);
86 break;
87
89 createFileAppender(logger, *i);
90 break;
91
93 createSyslogAppender(logger, *i);
94 break;
95
96 default:
97 // Not a valid destination. As we are in the middle of updating
98 // logging destinations, we could be in the situation where
99 // there are no valid appenders. For this reason, throw an
100 // exception.
102 "Unknown logging destination, code = " <<
103 i->destination);
104 }
105 }
106 }
107}
108
109// Console appender - log to either stdout or stderr.
110void
111LoggerManagerImpl::createConsoleAppender(log4cplus::Logger& logger,
112 const OutputOption& opt)
113{
114 log4cplus::SharedAppenderPtr console(
115 new log4cplus::ConsoleAppender(
116 (opt.stream == OutputOption::STR_STDERR), opt.flush));
117
118 setAppenderLayout(console, (opt.pattern.empty() ?
120 logger.addAppender(console);
121}
122
123// File appender. Depending on whether a maximum size is given, either
124// a standard file appender or a rolling file appender will be created.
125// In the case of the latter, we set "UseLockFile" to true so that
126// log4cplus internally avoids race in rolling over the files by multiple
127// processes. This feature isn't supported in log4cplus 1.0.x, but setting
128// the property unconditionally is okay as unknown properties are simply
129// ignored.
130void
131LoggerManagerImpl::createFileAppender(log4cplus::Logger& logger,
132 const OutputOption& opt)
133{
134 // Append to existing file
135 const std::ios::openmode mode = std::ios::app;
136
137 log4cplus::SharedAppenderPtr fileapp;
138 if (opt.maxsize == 0) {
139 fileapp = log4cplus::SharedAppenderPtr(new log4cplus::FileAppender(
140 opt.filename, mode, opt.flush));
141 } else {
142 log4cplus::helpers::Properties properties;
143 properties.setProperty("File", opt.filename);
144
145 // log4cplus supports file sizes past INT_MAX only in suffixed format.
146 // Convert from integer.
147 uint64_t maxsize(opt.maxsize);
148 size_t i(0);
149 while (std::numeric_limits<int32_t>::max() < maxsize && i < 2) {
150 maxsize /= 1000;
151 ++i;
152 }
153 std::array<std::string, 3> const suffixes({"", "KB", "MB"});
154 std::string const max_file_size(to_string(maxsize) + suffixes[i]);
155
156 // If maxsize is still past INT_MAX, it will overflow in log4cplus,
157 // so stop here instead.
158 if (std::numeric_limits<int32_t>::max() < maxsize) {
159 isc_throw(BadValue, "expected maxsize < "
160 << std::numeric_limits<int32_t>::max()
161 << "MB, but instead got " << max_file_size);
162 }
163
164 properties.setProperty("MaxFileSize", max_file_size);
165 properties.setProperty("MaxBackupIndex",
166 lexical_cast<string>(opt.maxver));
167 properties.setProperty("ImmediateFlush", opt.flush ? "true" : "false");
168 properties.setProperty("UseLockFile", "true");
169 fileapp = log4cplus::SharedAppenderPtr(
170 new log4cplus::RollingFileAppender(properties));
171 }
172
173 setAppenderLayout(fileapp, (opt.pattern.empty() ?
175 logger.addAppender(fileapp);
176}
177
178void
179LoggerManagerImpl::createBufferAppender(log4cplus::Logger& logger) {
180 log4cplus::SharedAppenderPtr bufferapp(new internal::BufferAppender());
181 bufferapp->setName("buffer");
182 logger.addAppender(bufferapp);
183 // Since we do not know at what level the loggers will end up
184 // running, set it to the highest for now
185 logger.setLogLevel(log4cplus::TRACE_LOG_LEVEL);
186}
187
188// Syslog appender.
189void
190LoggerManagerImpl::createSyslogAppender(log4cplus::Logger& logger,
191 const OutputOption& opt)
192{
193 log4cplus::helpers::Properties properties;
194 properties.setProperty("ident", getRootLoggerName());
195 properties.setProperty("facility", opt.facility);
196 log4cplus::SharedAppenderPtr syslogapp(
197 new log4cplus::SysLogAppender(properties));
198 setAppenderLayout(syslogapp, (opt.pattern.empty() ?
200 logger.addAppender(syslogapp);
201}
202
203
204// One-time initialization of the log4cplus system
205void
207 bool buffer)
208{
209 // Set up basic configurator. This attaches a ConsoleAppender to the
210 // root logger with suitable output. This is used until we we have
211 // actually read the logging configuration, in which case the output
212 // may well be changed.
213 log4cplus::BasicConfigurator config;
214 config.configure();
215
216 // Add the additional debug levels
218
219 initRootLogger(severity, dbglevel, buffer);
220}
221
222// Reset logging to default configuration. This closes all appenders
223// and resets the root logger to output INFO messages to the console.
224// It is principally used in testing.
225void
227{
228 // Initialize the root logger
229 initRootLogger(severity, dbglevel);
230}
231
232// Initialize the root logger
233void LoggerManagerImpl::initRootLogger(isc::log::Severity severity,
234 int dbglevel, bool buffer)
235{
236 log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
237
238 // Disable log4cplus' own logging, unless --enable-debug was
239 // specified to configure. Note that this does not change
240 // LogLog's levels (that is still just INFO).
241#ifndef ENABLE_DEBUG
242 log4cplus::helpers::LogLog::getLogLog()->setQuietMode(true);
243#endif
244
245 // Set the log4cplus root to not output anything - effectively we are
246 // ignoring it.
247 log4cplus::Logger::getRoot().setLogLevel(log4cplus::OFF_LOG_LEVEL);
248
249 // Set the level for the Kea root logger to the given severity and
250 // debug level.
251 log4cplus::Logger kea_root = log4cplus::Logger::getInstance(
253 kea_root.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
254 Level(severity, dbglevel)));
255
256 if (buffer) {
257 createBufferAppender(kea_root);
258 } else {
259 OutputOption opt;
260 createConsoleAppender(kea_root, opt);
261 }
262}
263
264
265void LoggerManagerImpl::setAppenderLayout(
266 log4cplus::SharedAppenderPtr& appender,
267 std::string pattern)
268{
269 // Finally the text of the message
270 appender->setLayout(
271#if LOG4CPLUS_VERSION < LOG4CPLUS_MAKE_VERSION(2, 0, 0)
272 auto_ptr<log4cplus::Layout>
273#else
274 unique_ptr<log4cplus::Layout>
275#endif
276 (new log4cplus::PatternLayout(pattern)));
277}
278
279void LoggerManagerImpl::storeBufferAppenders() {
280 // Walk through all loggers, and find any buffer appenders there
281 log4cplus::LoggerList loggers = log4cplus::Logger::getCurrentLoggers();
282 log4cplus::LoggerList::iterator it;
283 for (it = loggers.begin(); it != loggers.end(); ++it) {
284 log4cplus::SharedAppenderPtr buffer_appender =
285 it->getAppender("buffer");
286 if (buffer_appender) {
287 buffer_appender_store_.push_back(buffer_appender);
288 }
289 }
290}
291
292void LoggerManagerImpl::flushBufferAppenders() {
293 std::vector<log4cplus::SharedAppenderPtr> copy;
294 buffer_appender_store_.swap(copy);
295
296 std::vector<log4cplus::SharedAppenderPtr>::iterator it;
297 for (it = copy.begin(); it != copy.end(); ++it) {
298 internal::BufferAppender* app =
299 dynamic_cast<internal::BufferAppender*>(it->get());
300 isc_throw_assert(app);
301 app->flush();
302 }
303}
304
305} // namespace log
306} // 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.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition: isc_assert.h:18
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:1360
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-lfc.
Log level structure.
Definition: logger_level.h:42
std::string pattern
log content pattern
Definition: output_option.h:75
bool flush
true to flush after each message
Definition: output_option.h:70
static const std::string DEFAULT_FILE_PATTERN
Default layout pattern for file logs.
Definition: output_option.h:42
Stream stream
stdout/stderr if console output
Definition: output_option.h:69
static const std::string DEFAULT_SYSLOG_PATTERN
Default layout pattern for syslog logs.
Definition: output_option.h:44
static const std::string DEFAULT_CONSOLE_PATTERN
Default layout pattern for console logs.
Definition: output_option.h:40