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