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>
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 <boost/lexical_cast.hpp>
32 
33 using namespace std;
34 using boost::lexical_cast;
35 
36 namespace isc {
37 namespace 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.)
44 void
45 LoggerManagerImpl::processInit() {
46  storeBufferAppenders();
47 
48  log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
49  initRootLogger();
50 }
51 
52 // Flush the BufferAppenders at the end of processing a new specification
53 void
54 LoggerManagerImpl::processEnd() {
55  flushBufferAppenders();
56 }
57 
58 // Process logging specification. Set up the common states then dispatch to
59 // add output specifications.
60 void
61 LoggerManagerImpl::processSpecification(const LoggerSpecification& spec) {
62  log4cplus::Logger logger = log4cplus::Logger::getInstance(
63  expandLoggerName(spec.getName()));
64 
65  // Set severity level according to specification entry.
66  logger.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
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) {
81  case OutputOption::DEST_CONSOLE:
82  createConsoleAppender(logger, *i);
83  break;
84 
85  case OutputOption::DEST_FILE:
86  createFileAppender(logger, *i);
87  break;
88 
89  case OutputOption::DEST_SYSLOG:
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.
107 void
108 LoggerManagerImpl::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.
125 void
126 LoggerManagerImpl::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 
154 void
155 LoggerManagerImpl::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.
165 void
166 LoggerManagerImpl::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
180 void
181 LoggerManagerImpl::init(isc::log::Severity severity, int dbglevel,
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
192  LoggerLevelImpl::init();
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.
200 void
201 LoggerManagerImpl::reset(isc::log::Severity severity, int dbglevel)
202 {
203  // Initialize the root logger
204  initRootLogger(severity, dbglevel);
205 }
206 
207 // Initialize the root logger
208 void 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 
239 void 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 
259 void 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 
275 void 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 
288 void 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
logger_manager.h
isc::data::copy
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1114
isc::log::LoggerSpecification::getDbglevel
int getDbglevel() const
Definition: logger_specification.h:80
isc::log::LoggerSpecification::getName
std::string getName() const
Definition: logger_specification.h:56
isc::log::LoggerSpecification
Definition: logger_specification.h:29
isc::log::Severity
Severity
Severity Levels.
Definition: logger_level.h:23
isc::log::getRootLoggerName
const std::string & getRootLoggerName()
Get root logger name.
Definition: logger_name.cc:33
isc::log::LoggerSpecification::getSeverity
isc::log::Severity getSeverity() const
Definition: logger_specification.h:68
isc::log::OutputOption
Definition: output_option.h:37
isc::log::Level
Log level structure.
Definition: logger_level.h:42
logger.h
isc::log::OutputOption::flush
bool flush
true to flush after each message
Definition: output_option.h:63
buffer_appender_impl.h
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::log::LoggerSpecification::getAdditive
bool getAdditive() const
Definition: logger_specification.h:92
isc::log::OutputOption::stream
Stream stream
stdout/stderr if console output
Definition: output_option.h:62
logger_specification.h
isc::asiodns::logger
isc::log::Logger logger("asiodns")
Use the ASIO logger.
Definition: asiodns/logger.h:15
logger_manager_impl.h
isc::log::LoggerSpecification::end
iterator end()
Definition: logger_specification.h:114
logger_level_impl.h
isc::log::LoggerSpecification::begin
iterator begin()
Definition: logger_specification.h:104
UnknownLoggingDestination
Definition: logger_manager.h:18
logger_name.h
isc::log::LoggerSpecification::optionCount
size_t optionCount() const
Definition: logger_specification.h:124
isc::log::expandLoggerName
std::string expandLoggerName(const std::string &name)
Expand logger name.
Definition: logger_name.cc:42
logger_support.h
Logging initialization functions.
isc::log::LoggerSpecification::const_iterator
std::vector< OutputOption >::const_iterator const_iterator
Definition: logger_specification.h:32
log_messages.h