logger_manager_impl.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <algorithm>
  16. #include <iostream>
  17. #include <log4cplus/logger.h>
  18. #include <log4cplus/configurator.h>
  19. #include <log4cplus/hierarchy.h>
  20. #include <log4cplus/consoleappender.h>
  21. #include <log4cplus/fileappender.h>
  22. #include <log4cplus/syslogappender.h>
  23. #include <log4cplus/helpers/loglog.h>
  24. #include <log/logger.h>
  25. #include <log/logger_support.h>
  26. #include <log/logger_level_impl.h>
  27. #include <log/logger_manager.h>
  28. #include <log/logger_manager_impl.h>
  29. #include <log/log_messages.h>
  30. #include <log/logger_name.h>
  31. #include <log/logger_specification.h>
  32. #include <log/buffer_appender_impl.h>
  33. using namespace std;
  34. namespace isc {
  35. namespace log {
  36. // Reset hierarchy of loggers back to default settings. This removes all
  37. // appenders from loggers, sets their severity to NOT_SET (so that events are
  38. // passed back to the parent) and resets the root logger to logging
  39. // informational messages. (This last is not a log4cplus default, so we have to
  40. // explicitly reset the logging severity.)
  41. void
  42. LoggerManagerImpl::processInit() {
  43. storeBufferAppenders();
  44. log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
  45. initRootLogger();
  46. }
  47. // Flush the BufferAppenders at the end of processing a new specification
  48. void
  49. LoggerManagerImpl::processEnd() {
  50. flushBufferAppenders();
  51. }
  52. // Process logging specification. Set up the common states then dispatch to
  53. // add output specifications.
  54. void
  55. LoggerManagerImpl::processSpecification(const LoggerSpecification& spec) {
  56. log4cplus::Logger logger = log4cplus::Logger::getInstance(
  57. expandLoggerName(spec.getName()));
  58. // Set severity level according to specification entry.
  59. logger.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
  60. Level(spec.getSeverity(), spec.getDbglevel())));
  61. // Set the additive flag.
  62. logger.setAdditivity(spec.getAdditive());
  63. // Output options given?
  64. if (spec.optionCount() > 0) {
  65. // Replace all appenders for this logger.
  66. logger.removeAllAppenders();
  67. // Now process output specifications.
  68. for (LoggerSpecification::const_iterator i = spec.begin();
  69. i != spec.end(); ++i) {
  70. switch (i->destination) {
  71. case OutputOption::DEST_CONSOLE:
  72. createConsoleAppender(logger, *i);
  73. break;
  74. case OutputOption::DEST_FILE:
  75. createFileAppender(logger, *i);
  76. break;
  77. case OutputOption::DEST_SYSLOG:
  78. createSyslogAppender(logger, *i);
  79. break;
  80. default:
  81. // Not a valid destination. As we are in the middle of updating
  82. // logging destinations, we could be in the situation where
  83. // there are no valid appenders. For this reason, throw an
  84. // exception.
  85. isc_throw(UnknownLoggingDestination,
  86. "Unknown logging destination, code = " <<
  87. i->destination);
  88. }
  89. }
  90. }
  91. }
  92. // Console appender - log to either stdout or stderr.
  93. void
  94. LoggerManagerImpl::createConsoleAppender(log4cplus::Logger& logger,
  95. const OutputOption& opt)
  96. {
  97. log4cplus::SharedAppenderPtr console(
  98. new log4cplus::ConsoleAppender(
  99. (opt.stream == OutputOption::STR_STDERR), opt.flush));
  100. setConsoleAppenderLayout(console);
  101. logger.addAppender(console);
  102. }
  103. // File appender. Depending on whether a maximum size is given, either
  104. // a standard file appender or a rolling file appender will be created.
  105. void
  106. LoggerManagerImpl::createFileAppender(log4cplus::Logger& logger,
  107. const OutputOption& opt)
  108. {
  109. // Append to existing file
  110. std::ios::openmode mode = std::ios::app;
  111. log4cplus::SharedAppenderPtr fileapp;
  112. if (opt.maxsize == 0) {
  113. fileapp = log4cplus::SharedAppenderPtr(new log4cplus::FileAppender(
  114. opt.filename, mode, opt.flush));
  115. } else {
  116. fileapp = log4cplus::SharedAppenderPtr(
  117. new log4cplus::RollingFileAppender(opt.filename, opt.maxsize,
  118. opt.maxver, opt.flush));
  119. }
  120. // use the same console layout for the files.
  121. setConsoleAppenderLayout(fileapp);
  122. logger.addAppender(fileapp);
  123. }
  124. void
  125. LoggerManagerImpl::createBufferAppender(log4cplus::Logger& logger) {
  126. log4cplus::SharedAppenderPtr bufferapp(new internal::BufferAppender());
  127. bufferapp->setName("buffer");
  128. logger.addAppender(bufferapp);
  129. // Since we do not know at what level the loggers will end up
  130. // running, set it to the highest for now
  131. logger.setLogLevel(log4cplus::TRACE_LOG_LEVEL);
  132. }
  133. // Syslog appender.
  134. void
  135. LoggerManagerImpl::createSyslogAppender(log4cplus::Logger& logger,
  136. const OutputOption& opt)
  137. {
  138. log4cplus::SharedAppenderPtr syslogapp(
  139. new log4cplus::SysLogAppender(opt.facility));
  140. setSyslogAppenderLayout(syslogapp);
  141. logger.addAppender(syslogapp);
  142. }
  143. // One-time initialization of the log4cplus system
  144. void
  145. LoggerManagerImpl::init(isc::log::Severity severity, int dbglevel,
  146. bool buffer)
  147. {
  148. // Set up basic configurator. This attaches a ConsoleAppender to the
  149. // root logger with suitable output. This is used until we we have
  150. // actually read the logging configuration, in which case the output
  151. // may well be changed.
  152. log4cplus::BasicConfigurator config;
  153. config.configure();
  154. // Add the additional debug levels
  155. LoggerLevelImpl::init();
  156. initRootLogger(severity, dbglevel, buffer);
  157. }
  158. // Reset logging to default configuration. This closes all appenders
  159. // and resets the root logger to output INFO messages to the console.
  160. // It is principally used in testing.
  161. void
  162. LoggerManagerImpl::reset(isc::log::Severity severity, int dbglevel)
  163. {
  164. // Initialize the root logger
  165. initRootLogger(severity, dbglevel);
  166. }
  167. // Initialize the root logger
  168. void LoggerManagerImpl::initRootLogger(isc::log::Severity severity,
  169. int dbglevel, bool buffer)
  170. {
  171. log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
  172. // Disable log4cplus' own logging, unless --enable-debug was
  173. // specified to configure. Note that this does not change
  174. // LogLog's levels (that is still just INFO).
  175. #ifndef ENABLE_DEBUG
  176. log4cplus::helpers::LogLog::getLogLog()->setQuietMode(true);
  177. #endif
  178. // Set the log4cplus root to not output anything - effectively we are
  179. // ignoring it.
  180. log4cplus::Logger::getRoot().setLogLevel(log4cplus::OFF_LOG_LEVEL);
  181. // Set the level for the BIND 10 root logger to the given severity and
  182. // debug level.
  183. log4cplus::Logger b10root = log4cplus::Logger::getInstance(
  184. getRootLoggerName());
  185. b10root.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
  186. Level(severity, dbglevel)));
  187. if (buffer) {
  188. createBufferAppender(b10root);
  189. } else {
  190. OutputOption opt;
  191. createConsoleAppender(b10root, opt);
  192. }
  193. }
  194. void LoggerManagerImpl::setConsoleAppenderLayout(
  195. log4cplus::SharedAppenderPtr& appender)
  196. {
  197. // Create the pattern we want for the output - local time.
  198. string pattern = "%D{%Y-%m-%d %H:%M:%S.%q} %-5p [%c/%i] %m\n";
  199. // Finally the text of the message
  200. auto_ptr<log4cplus::Layout> layout(new log4cplus::PatternLayout(pattern));
  201. appender->setLayout(layout);
  202. }
  203. // Set the the "syslog" layout for the given appenders. This is the same
  204. // as the console, but without the timestamp (which is expected to be
  205. // set by syslogd).
  206. void LoggerManagerImpl::setSyslogAppenderLayout(
  207. log4cplus::SharedAppenderPtr& appender)
  208. {
  209. // Create the pattern we want for the output - local time.
  210. string pattern = "%-5p [%c] %m\n";
  211. // Finally the text of the message
  212. auto_ptr<log4cplus::Layout> layout(new log4cplus::PatternLayout(pattern));
  213. appender->setLayout(layout);
  214. }
  215. void LoggerManagerImpl::storeBufferAppenders() {
  216. // Walk through all loggers, and find any buffer appenders there
  217. log4cplus::LoggerList loggers = log4cplus::Logger::getCurrentLoggers();
  218. log4cplus::LoggerList::iterator it;
  219. for (it = loggers.begin(); it != loggers.end(); ++it) {
  220. log4cplus::SharedAppenderPtr buffer_appender =
  221. it->getAppender("buffer");
  222. if (buffer_appender) {
  223. buffer_appender_store_.push_back(buffer_appender);
  224. }
  225. }
  226. }
  227. void LoggerManagerImpl::flushBufferAppenders() {
  228. std::vector<log4cplus::SharedAppenderPtr> copy;
  229. buffer_appender_store_.swap(copy);
  230. std::vector<log4cplus::SharedAppenderPtr>::iterator it;
  231. for (it = copy.begin(); it != copy.end(); ++it) {
  232. internal::BufferAppender* app =
  233. dynamic_cast<internal::BufferAppender*>(it->get());
  234. assert(app != NULL);
  235. app->flush();
  236. }
  237. }
  238. } // namespace log
  239. } // namespace isc