logger_level_impl.cc 7.3 KB

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