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