1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// Copyright (C) 2011-2022 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <config.h>

#include <algorithm><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <string.h><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <iostream><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/lexical_cast.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <log4cplus/logger.h><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <log/logger_level.h>
#include <log/logger_level_impl.h>
#include <log/logimpl_messages.h>
#include <log/macros.h>

using namespace log4cplus;
using namespace std;

namespace {
isc::log::Logger logger("log");
}

namespace isc {
namespace log {

// Convert Kea level to a log4cplus logging level.
log4cplus::LogLevel
LoggerLevelImpl::convertFromBindLevel(const Level& level) {

    // Kea logging levels are small integers so we can do a table lookup
    static const log4cplus::LogLevel log4cplus_levels[] = {
        log4cplus::NOT_SET_LOG_LEVEL,
        log4cplus::DEBUG_LOG_LEVEL,
        log4cplus::INFO_LOG_LEVEL,
        log4cplus::WARN_LOG_LEVEL,
        log4cplus::ERROR_LOG_LEVEL,
        log4cplus::FATAL_LOG_LEVEL,
        log4cplus::OFF_LOG_LEVEL
    };

    // ... with compile-time checks to ensure that table indexes are correct.
    BOOST_STATIC_ASSERT(static_cast<int>(DEFAULT) == 0);<--- Condition 'static_cast(DEFAULT)==0' is always true
    BOOST_STATIC_ASSERT(static_cast<int>(DEBUG) == 1);<--- Condition 'static_cast(DEBUG)==1' is always true
    BOOST_STATIC_ASSERT(static_cast<int>(INFO) == 2);<--- Condition 'static_cast(INFO)==2' is always true
    BOOST_STATIC_ASSERT(static_cast<int>(WARN) == 3);<--- Condition 'static_cast(WARN)==3' is always true
    BOOST_STATIC_ASSERT(static_cast<int>(ERROR) == 4);<--- Condition 'static_cast(ERROR)==4' is always true
    BOOST_STATIC_ASSERT(static_cast<int>(FATAL) == 5);<--- Condition 'static_cast(FATAL)==5' is always true
    BOOST_STATIC_ASSERT(static_cast<int>(NONE) == 6);<--- Condition 'static_cast(NONE)==6' is always true

    // Do the conversion
    if (level.severity == DEBUG) {

        // Debug severity, so the log4cplus level returned depends on the
        // debug level.  Silently limit the debug level to the range
        // MIN_DEBUG_LEVEL to MAX_DEBUG_LEVEL (avoids the hassle of throwing
        // and catching exceptions and besides, this is for debug information).
        int limited = std::max(MIN_DEBUG_LEVEL,
                               std::min(level.dbglevel, MAX_DEBUG_LEVEL));
        LogLevel newlevel = static_cast<int>(DEBUG_LOG_LEVEL -
                                            (limited - MIN_DEBUG_LEVEL));
        return (static_cast<log4cplus::LogLevel>(newlevel));

    } else {

        // Can do a table lookup to speed things up.  There is no need to check
        // that the index is out of range.  That the variable is of type
        // isc::log::Severity ensures that it must be one of the Severity enum
        // members - conversion of a numeric value to an enum is not permitted.
        return (log4cplus_levels[level.severity]);
    }
}

// Convert log4cplus logging level to Kea debug level.  It is up to the
// caller to validate that the debug level is valid.
Level
LoggerLevelImpl::convertToBindLevel(const log4cplus::LogLevel loglevel) {

    // Not easy to do a table lookup as the numerical values of log4cplus levels
    // are quite high.
    if (loglevel <= log4cplus::NOT_SET_LOG_LEVEL) {
        return (Level(DEFAULT));

    } else if (loglevel <= log4cplus::DEBUG_LOG_LEVEL) {

        // Debug severity, so extract the debug level from the numeric value.
        // If outside the limits, change the severity to the level above or
        // below.
        int dbglevel = MIN_DEBUG_LEVEL +
                       static_cast<int>(log4cplus::DEBUG_LOG_LEVEL) -
                       static_cast<int>(loglevel);
        if (dbglevel > MAX_DEBUG_LEVEL) {
            return (Level(DEFAULT));
        } else if (dbglevel < MIN_DEBUG_LEVEL) {
            return (Level(INFO));
        }
        return (Level(DEBUG, dbglevel));

    } else if (loglevel <= log4cplus::INFO_LOG_LEVEL) {
        return (Level(INFO));

    } else if (loglevel <= log4cplus::WARN_LOG_LEVEL) {
        return (Level(WARN));

    } else if (loglevel <= log4cplus::ERROR_LOG_LEVEL) {
        return (Level(ERROR));

    } else if (loglevel <= log4cplus::FATAL_LOG_LEVEL) {
        return (Level(FATAL));

    }

    return (Level(NONE));
}


// Convert string to appropriate logging level
log4cplus::LogLevel
LoggerLevelImpl::logLevelFromString(const log4cplus::tstring& level) {

    std::string name = level;       // Get to known type
    size_t length = name.size();    // Length of the string

    if (length < 5) {

        // String can't possibly start DEBUG so we don't know what it is.
        // As per documentation, return NOT_SET level.
        return (NOT_SET_LOG_LEVEL);
    } else {
        if (strncasecmp(name.c_str(), "DEBUG", 5) == 0) {

            // String starts "DEBUG" (or "debug" or any case mixture).  The
            // rest of the string - if any - should be a number.
            if (length == 5) {

                // It is plain "DEBUG".  Take this as level 0.
                return (DEBUG_LOG_LEVEL);
            } else {

                // Try converting the remainder to an integer.  The "5" is
                // the length of the string "DEBUG".  Note that if the number
                // is outside the range of debug levels, it is coerced to the
                // nearest limit.  Thus a level of DEBUG509 will end up as
                // if DEBUG99 has been specified.
                try {
                    int dbglevel = boost::lexical_cast<int>(name.substr(5));
                    if (dbglevel < MIN_DEBUG_LEVEL) {
                        LOG_WARN(logger, LOGIMPL_BELOW_MIN_DEBUG).arg(dbglevel)
                            .arg(MIN_DEBUG_LEVEL);
                        dbglevel = MIN_DEBUG_LEVEL;

                    } else if (dbglevel > MAX_DEBUG_LEVEL) {
                        LOG_WARN(logger, LOGIMPL_ABOVE_MAX_DEBUG).arg(dbglevel)
                            .arg(MAX_DEBUG_LEVEL);
                        dbglevel = MAX_DEBUG_LEVEL;

                    }
                    return convertFromBindLevel(Level(DEBUG, dbglevel));
                }
                catch (const boost::bad_lexical_cast&) {
                    LOG_ERROR(logger, LOGIMPL_BAD_DEBUG_STRING).arg(name);
                    return (NOT_SET_LOG_LEVEL);
                }
            }
        } else {

            // Unknown string - return default.  Log4cplus will call any other
            // registered conversion functions to interpret it.
            return (NOT_SET_LOG_LEVEL);
        }
    }
}

// Convert logging level to string.  If the level is a valid debug level,
// return the string DEBUG, else return the empty string.
#if LOG4CPLUS_VERSION < LOG4CPLUS_MAKE_VERSION(2, 0, 0)
LoggerLevelImpl::LogLevelString
#else
const LoggerLevelImpl::LogLevelString&
#endif
LoggerLevelImpl::logLevelToString(log4cplus::LogLevel level) {
    Level bindlevel = convertToBindLevel(level);
    Severity& severity = bindlevel.severity;
    int& dbglevel = bindlevel.dbglevel;<--- Variable 'dbglevel' can be declared as reference to const
    static LoggerLevelImpl::LogLevelString debug_ = tstring("DEBUG");
    static LoggerLevelImpl::LogLevelString empty_ = tstring();

    if ((severity == DEBUG) &&
        ((dbglevel >= MIN_DEBUG_LEVEL) && (dbglevel <= MAX_DEBUG_LEVEL))) {
        return (debug_);
    }

    // Unknown, so return empty string for log4cplus to try other conversion
    // functions.
    return (empty_);
}

// Initialization.  Register the conversion functions with the LogLevelManager.
void
LoggerLevelImpl::init() {

    // Get the singleton log-level manager.
    LogLevelManager& manager = getLogLevelManager();

    // Register the conversion functions
    manager.pushFromStringMethod(LoggerLevelImpl::logLevelFromString);
    manager.pushToStringMethod(LoggerLevelImpl::logLevelToString);
}

} // namespace log
} // namespace isc