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