logger_level_impl.cc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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 <algorithm>
  15. #include <string.h>
  16. #include <iostream>
  17. #include <boost/lexical_cast.hpp>
  18. #include <log4cplus/logger.h>
  19. #include <log/logger_level.h>
  20. #include <log/logger_level_impl.h>
  21. #include <log/logimpl_messages.h>
  22. #include <log/macros.h>
  23. using namespace log4cplus;
  24. using namespace std;
  25. namespace {
  26. isc::log::Logger logger("log");
  27. }
  28. namespace isc {
  29. namespace log {
  30. // Convert BIND 10 level to a log4cplus logging level.
  31. log4cplus::LogLevel
  32. LoggerLevelImpl::convertFromBindLevel(const Level& level) {
  33. // BIND 10 logging levels are small integers so we can do a table lookup
  34. static const log4cplus::LogLevel log4cplus_levels[] = {
  35. log4cplus::NOT_SET_LOG_LEVEL,
  36. log4cplus::DEBUG_LOG_LEVEL,
  37. log4cplus::INFO_LOG_LEVEL,
  38. log4cplus::WARN_LOG_LEVEL,
  39. log4cplus::ERROR_LOG_LEVEL,
  40. log4cplus::FATAL_LOG_LEVEL,
  41. log4cplus::OFF_LOG_LEVEL
  42. };
  43. // ... with compile-time checks to ensure that table indexes are correct.
  44. BOOST_STATIC_ASSERT(static_cast<int>(DEFAULT) == 0);
  45. BOOST_STATIC_ASSERT(static_cast<int>(DEBUG) == 1);
  46. BOOST_STATIC_ASSERT(static_cast<int>(INFO) == 2);
  47. BOOST_STATIC_ASSERT(static_cast<int>(WARN) == 3);
  48. BOOST_STATIC_ASSERT(static_cast<int>(ERROR) == 4);
  49. BOOST_STATIC_ASSERT(static_cast<int>(FATAL) == 5);
  50. BOOST_STATIC_ASSERT(static_cast<int>(NONE) == 6);
  51. // Do the conversion
  52. if (level.severity == DEBUG) {
  53. // Debug severity, so the log4cplus level returned depends on the
  54. // debug level. Silently limit the debug level to the range
  55. // MIN_DEBUG_LEVEL to MAX_DEBUG_LEVEL (avoids the hassle of throwing
  56. // and catching exceptions and besides, this is for debug information).
  57. int limited = std::max(MIN_DEBUG_LEVEL,
  58. std::min(level.dbglevel, MAX_DEBUG_LEVEL));
  59. LogLevel newlevel = static_cast<int>(DEBUG_LOG_LEVEL -
  60. (limited - MIN_DEBUG_LEVEL));
  61. return (static_cast<log4cplus::LogLevel>(newlevel));
  62. } else {
  63. // Can do a table lookup to speed things up. There is no need to check
  64. // that the index is out of range. That the variable is of type
  65. // isc::log::Severity ensures that it must be one of the Severity enum
  66. // members - conversion of a numeric value to an enum is not permitted.
  67. return (log4cplus_levels[level.severity]);
  68. }
  69. }
  70. // Convert log4cplus logging level to BIND 10 debug level. It is up to the
  71. // caller to validate that the debug level is valid.
  72. Level
  73. LoggerLevelImpl::convertToBindLevel(const log4cplus::LogLevel loglevel) {
  74. // Not easy to do a table lookup as the numerical values of log4cplus levels
  75. // are quite high.
  76. if (loglevel <= log4cplus::NOT_SET_LOG_LEVEL) {
  77. return (Level(DEFAULT));
  78. } else if (loglevel <= log4cplus::DEBUG_LOG_LEVEL) {
  79. // Debug severity, so extract the debug level from the numeric value.
  80. // If outside the limits, change the severity to the level above or
  81. // below.
  82. int dbglevel = MIN_DEBUG_LEVEL +
  83. static_cast<int>(log4cplus::DEBUG_LOG_LEVEL) -
  84. static_cast<int>(loglevel);
  85. if (dbglevel > MAX_DEBUG_LEVEL) {
  86. return (Level(DEFAULT));
  87. } else if (dbglevel < MIN_DEBUG_LEVEL) {
  88. return (Level(INFO));
  89. }
  90. return (Level(DEBUG, dbglevel));
  91. } else if (loglevel <= log4cplus::INFO_LOG_LEVEL) {
  92. return (Level(INFO));
  93. } else if (loglevel <= log4cplus::WARN_LOG_LEVEL) {
  94. return (Level(WARN));
  95. } else if (loglevel <= log4cplus::ERROR_LOG_LEVEL) {
  96. return (Level(ERROR));
  97. } else if (loglevel <= log4cplus::FATAL_LOG_LEVEL) {
  98. return (Level(FATAL));
  99. }
  100. return (Level(NONE));
  101. }
  102. // Convert string to appropriate logging level
  103. log4cplus::LogLevel
  104. LoggerLevelImpl::logLevelFromString(const log4cplus::tstring& level) {
  105. std::string name = level; // Get to known type
  106. size_t length = name.size(); // Length of the string
  107. if (length < 5) {
  108. // String can't possibly start DEBUG so we don't know what it is.
  109. // As per documentation, return NOT_SET level.
  110. return (NOT_SET_LOG_LEVEL);
  111. }
  112. else {
  113. if (strncasecmp(name.c_str(), "DEBUG", 5) == 0) {
  114. // String starts "DEBUG" (or "debug" or any case mixture). The
  115. // rest of the string - if any - should be a number.
  116. if (length == 5) {
  117. // It is plain "DEBUG". Take this as level 0.
  118. return (DEBUG_LOG_LEVEL);
  119. }
  120. else {
  121. // Try converting the remainder to an integer. The "5" is
  122. // the length of the string "DEBUG". Note that if the number
  123. // is outside the range of debug levels, it is coerced to the
  124. // nearest limit. Thus a level of DEBUG509 will end up as
  125. // if DEBUG99 has been specified.
  126. try {
  127. int dbglevel = boost::lexical_cast<int>(name.substr(5));
  128. if (dbglevel < MIN_DEBUG_LEVEL) {
  129. LOG_WARN(logger, LOGIMPL_BELOW_MIN_DEBUG).arg(dbglevel)
  130. .arg(MIN_DEBUG_LEVEL);
  131. dbglevel = MIN_DEBUG_LEVEL;
  132. } else if (dbglevel > MAX_DEBUG_LEVEL) {
  133. LOG_WARN(logger, LOGIMPL_ABOVE_MAX_DEBUG).arg(dbglevel)
  134. .arg(MAX_DEBUG_LEVEL);
  135. dbglevel = MAX_DEBUG_LEVEL;
  136. }
  137. return convertFromBindLevel(Level(DEBUG, dbglevel));
  138. }
  139. catch (boost::bad_lexical_cast&) {
  140. LOG_ERROR(logger, LOGIMPL_BAD_DEBUG_STRING).arg(name);
  141. return (NOT_SET_LOG_LEVEL);
  142. }
  143. }
  144. } else {
  145. // Unknown string - return default. Log4cplus will call any other
  146. // registered conversion functions to interpret it.
  147. return (NOT_SET_LOG_LEVEL);
  148. }
  149. }
  150. }
  151. // Convert logging level to string. If the level is a valid debug level,
  152. // return the string DEBUG, else return the empty string.
  153. log4cplus::tstring
  154. LoggerLevelImpl::logLevelToString(log4cplus::LogLevel level) {
  155. Level bindlevel = convertToBindLevel(level);
  156. Severity& severity = bindlevel.severity;
  157. int& dbglevel = bindlevel.dbglevel;
  158. if ((severity == DEBUG) &&
  159. ((dbglevel >= MIN_DEBUG_LEVEL) && (dbglevel <= MAX_DEBUG_LEVEL))) {
  160. return (tstring("DEBUG"));
  161. }
  162. // Unknown, so return empty string for log4cplus to try other conversion
  163. // functions.
  164. return (tstring());
  165. }
  166. // Initialization. Register the conversion functions with the LogLevelManager.
  167. void
  168. LoggerLevelImpl::init() {
  169. // Get the singleton log-level manager.
  170. LogLevelManager& manager = getLogLevelManager();
  171. // Register the conversion functions
  172. manager.pushFromStringMethod(LoggerLevelImpl::logLevelFromString);
  173. manager.pushToStringMethod(LoggerLevelImpl::logLevelToString);
  174. }
  175. } // namespace log
  176. } // namespace isc