Commit 192aefd9 authored by Stephen Morris's avatar Stephen Morris
Browse files

[trac899] Implemented debug levels

Debug logging levels implemented as new log4cplus levels.  With
this change, most of the tests pass.  The ones that fail are caused
by the different form of output.
parent 4fcd0d31
......@@ -6,12 +6,16 @@ AM_CPPFLAGS += $(BOOST_INCLUDES) $(LOG4CPLUS_INCLUDES)
CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = liblog.la
liblog_la_SOURCES =
liblog_la_SOURCES += debug_levels.h logger_levels.h
liblog_la_SOURCES = b.cc
liblog_la_SOURCES += logger_levels.h
liblog_la_SOURCES += dummylog.h dummylog.cc
liblog_la_SOURCES += log_formatter.h log_formatter.cc
liblog_la_SOURCES += logger.cc logger.h
liblog_la_SOURCES += logger_impl.cc logger_impl.h
liblog_la_SOURCES += logger_level.h
liblog_la_SOURCES += logger_level_impl.cc logger_level_impl.h
liblog_la_SOURCES += logger_support.cc logger_support.h
liblog_la_SOURCES += macros.h
liblog_la_SOURCES += messagedef.cc messagedef.h
liblog_la_SOURCES += message_dictionary.cc message_dictionary.h
liblog_la_SOURCES += message_exception.h
......@@ -19,13 +23,11 @@ liblog_la_SOURCES += message_initializer.cc message_initializer.h
liblog_la_SOURCES += message_reader.cc message_reader.h
liblog_la_SOURCES += message_types.h
liblog_la_SOURCES += root_logger_name.cc root_logger_name.h
liblog_la_SOURCES += log_formatter.h log_formatter.cc
liblog_la_SOURCES += macros.h
EXTRA_DIST = README
EXTRA_DIST += messagedef.mes
EXTRA_DIST += logger_impl_log4cxx.cc logger_impl_log4cxx.h
EXTRA_DIST += xdebuglevel.cc xdebuglevel.h
EXTRA_DIST += logger_impl_simple.cc logger_impl_simple.h
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
# B10_CXXFLAGS)
......
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef __DEBUG_LEVELS_H
#define __DEBUG_LEVELS_H
/// \brief Defines Debug Levels
///
/// Defines the maximum and minimum debug levels and the number of levels.
/// These are defined using #define as they are referenced in the construction
/// of variables declared outside execution units. (In this way we avoid the
/// "static initialization fiasco" problem.)
#define MIN_DEBUG_LEVEL (0)
#define MAX_DEBUG_LEVEL (99)
#define NUM_DEBUG_LEVEL (MAX_DEBUG_LEVEL - MIN_DEBUG_LEVEL + 1)
#endif // __DEBUG_LEVELS_H
......@@ -17,7 +17,7 @@
#include <string>
#include <boost/lexical_cast.hpp>
#include <log/logger_levels.h>
#include <log/logger_level.h>
namespace isc {
namespace log {
......
......@@ -112,7 +112,7 @@ Logger::isFatalEnabled() {
// Output methods
void
Logger::output(const Severity& severity, const string& message) {
Logger::output(const Severity& severity, const std::string& message) {
getLoggerPtr()->outputRaw(severity, message);
}
......@@ -170,12 +170,5 @@ bool Logger::operator==(Logger& other) {
return (*getLoggerPtr() == *other.getLoggerPtr());
}
// Protected methods (used for testing)
void
Logger::reset() {
LoggerImpl::reset();
}
} // namespace log
} // namespace isc
......@@ -18,8 +18,7 @@
#include <cstdlib>
#include <string>
#include <log/debug_levels.h>
#include <log/logger_levels.h>
#include <log/logger_level.h>
#include <log/message_types.h>
#include <log/log_formatter.h>
......@@ -179,14 +178,6 @@ public:
/// \return true if the logger objects are instances of the same logger.
bool operator==(Logger& other);
protected:
/// \brief Reset Global Data
///
/// Used for testing, this calls upon the underlying logger implementation
/// to clear any global data.
static void reset();
private:
friend class isc::log::Formatter<Logger>;
......
......@@ -12,7 +12,6 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE
#include <iostream>
#include <iomanip>
#include <algorithm>
......@@ -23,10 +22,10 @@
#include <log4cplus/configurator.h>
#include <log/debug_levels.h>
#include <log/root_logger_name.h>
#include <log/logger.h>
#include <log/logger_levels.h>
#include <log/logger_level.h>
#include <log/logger_level_impl.h>
#include <log/logger_impl.h>
#include <log/message_dictionary.h>
#include <log/message_types.h>
......@@ -35,6 +34,7 @@
#include <util/strutil.h>
using namespace std;
using namespace log4cplus;
namespace isc {
namespace log {
......@@ -45,21 +45,24 @@ namespace log {
// Constructor
LoggerImpl::LoggerImpl(const std::string& name, bool)
{
// Initialize log4cplus if not already done
initLog4cplus();
// Are we the root logger?
if (name == getRootLoggerName()) {
is_root_ = true;
name_ = name;
logger_ = log4cplus::Logger::getRoot();
} else {
is_root_ = false;
name_ = getRootLoggerName() + "." + name;
logger_ = log4cplus::Logger::getInstance(name_);
}
fmt_name_ = std::string("[") + name_ + std::string("] ");
// Initialize log4cplus if not already done
initLog4cplus();
// Return existing instance of logger, creating it if it does not exist.
logger_ = log4cplus::Logger::getInstance(name_);
// Create a formatted name for use in messages (speeds up formatting if
// we do it now.)
fmt_name_ = std::string("[") + name_ + std::string("] ");
}
// Destructor. (Here because of virtual declaration.)
......@@ -68,49 +71,44 @@ LoggerImpl::~LoggerImpl() {
}
// Set the severity for logging.
// TODO IGNORE DEBUG LEVEL FOR NOW
void
LoggerImpl::setSeverity(isc::log::Severity severity, int /*dbglevel*/) {
// Silently coerce the debug level into the valid range of 0 to 99
//int debug_level = max(MIN_DEBUG_LEVEL, min(MAX_DEBUG_LEVEL, dbglevel));
logger_.setLogLevel(convertFromBindSeverity(severity));
LoggerImpl::setSeverity(isc::log::Severity severity, int dbglevel) {
isc::log::Level level(severity, dbglevel);
logger_.setLogLevel(LoggerLevelImpl::convertFromBindLevel(level));
}
// Return severity level
isc::log::Severity
LoggerImpl::getSeverity() {
return convertToBindSeverity(logger_.getLogLevel());
isc::log::Level level =
LoggerLevelImpl::convertToBindLevel(logger_.getLogLevel());
return level.severity;
}
// Return current debug level (only valid if current severity level is DEBUG).
int
LoggerImpl::getDebugLevel() {
isc::log::Level level =
LoggerLevelImpl::convertToBindLevel(logger_.getLogLevel());
return level.dbglevel;
}
// Get effective severity. Either the current severity or, if not set, the
// severity of the root level.
isc::log::Severity
LoggerImpl::getEffectiveSeverity() {
return convertToBindSeverity(logger_.getChainedLogLevel());
isc::log::Level level =
LoggerLevelImpl::convertToBindLevel(logger_.getChainedLogLevel());
return level.severity;
}
// Get the debug level. This returns 0 unless the severity is DEBUG.
// TODO: DEBUG LEVEL IGNORED FOR NOW
// Return effective debug level (only valid if current effective severity level
// is DEBUG).
int
LoggerImpl::getDebugLevel() {
return (0);
}
// The code for isXxxEnabled is quite simple and is in the header. The only
// exception is isDebugEnabled() where we have the complication of the debug
// levels.
// TODO: DEBUG LEVEL IGNORED FOR NOW
bool
LoggerImpl::isDebugEnabled(int dbglevel) {
return logger_.isEnabledFor(log4cplus::DEBUG_LOG_LEVEL);
LoggerImpl::getEffectiveDebugLevel() {
isc::log::Level level =
LoggerLevelImpl::convertToBindLevel(logger_.getChainedLogLevel());
return level.dbglevel;
}
......@@ -145,68 +143,6 @@ LoggerImpl::outputRaw(const Severity& severity, const string& message) {
}
}
// Convert levels - from BIND 10 level to log4cplus level.
// Namespaces explicitly used to clarify what level we are talking about
log4cplus::LogLevel
LoggerImpl::convertFromBindSeverity(const isc::log::Severity& inlevel) {
// BIND 10 logging levels are small integers so we can do a table lookup
static const log4cplus::LogLevel level[] = {
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>(isc::log::DEFAULT) == 0);
BOOST_STATIC_ASSERT(static_cast<int>(isc::log::DEBUG) == 1);
BOOST_STATIC_ASSERT(static_cast<int>(isc::log::INFO) == 2);
BOOST_STATIC_ASSERT(static_cast<int>(isc::log::WARN) == 3);
BOOST_STATIC_ASSERT(static_cast<int>(isc::log::ERROR) == 4);
BOOST_STATIC_ASSERT(static_cast<int>(isc::log::FATAL) == 5);
BOOST_STATIC_ASSERT(static_cast<int>(isc::log::NONE) == 6);
// No need to check that the iundex is out of range. Setting the type of
// the argument to 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 (level[inlevel]);
}
// Convert levels - from log4plus level to BIND 10 level
// Namespaces explicitly used to clarify what level we are talking about
isc::log::Severity
LoggerImpl::convertToBindSeverity(const log4cplus::LogLevel& inlevel) {
// Not easy to do a table lookup as the numerical values of log4cplus levels
// are quite high.
switch (inlevel) {
case log4cplus::NOT_SET_LOG_LEVEL:
return (isc::log::DEFAULT);
case log4cplus::DEBUG_LOG_LEVEL:
return (isc::log::DEBUG);
case log4cplus::INFO_LOG_LEVEL:
return (isc::log::INFO);
case log4cplus::WARN_LOG_LEVEL:
return (isc::log::WARN);
case log4cplus::ERROR_LOG_LEVEL:
return (isc::log::ERROR);
case log4cplus::FATAL_LOG_LEVEL:
return (isc::log::FATAL);
}
return (isc::log::NONE);
}
// One-time initialization of log4cplus
......@@ -215,8 +151,14 @@ LoggerImpl::initLog4cplus() {
static bool not_initialized = true;
if (not_initialized) {
// Set up basic configurator
log4cplus::BasicConfigurator config;
config.configure();
// Add additional debug levels
LoggerLevelImpl::init();
// All done.
not_initialized = false;
}
}
......
......@@ -18,6 +18,7 @@
#include <stdarg.h>
#include <time.h>
#include <iostream>
#include <cstdlib>
#include <string>
#include <map>
......@@ -28,10 +29,8 @@
#include <log4cplus/logger.h>
// BIND-10 logger files
#include <log/debug_levels.h>
#include <log/logger.h>
#include <log/logger_level_impl.h>
#include <log/message_types.h>
#include <log/root_logger_name.h>
namespace isc {
namespace log {
......@@ -40,37 +39,24 @@ namespace log {
///
/// The logger uses a "pimpl" idiom for implementation, where the base logger
/// class contains little more than a pointer to the implementation class, and
/// all actions are carried out by the latter. This class is an implementation
/// class that just outputs to stdout.
/// all actions are carried out by the latter.
///
/// This particular implementation is based on log4cplus (from sourceforge:
/// http://log4cplus.sourceforge.net). Particular items of note:
///
/// a) BIND 10 loggers have names of the form "root.sublogger". Log4cplus
/// loggers are always subloggers of a "root" logger. In this implementation,
/// the name of the logger is checked. If it is the root name (as evidenced
/// by the setting of the BIND 10 root logger name), the log4cplus root logger
/// is used. Otherwise the name is used as the name of a logger and a log4cplus
/// sub-logger created.
///
/// b) The idea of debug levels is implemented. Seee logger_level.h and
/// logger_level_impl.h for more details on this.
class LoggerImpl {
public:
/// \brief Information About Logger
///
/// Holds a information about a logger, namely its severity and its debug
/// level. This could be a std::pair, except that it gets confusing when
/// accessing the LoggerInfoMap: that returns a pair, so we to reference
/// elements we would use constructs like ((i->first).second);
struct LoggerInfo {
isc::log::Severity severity;
int dbglevel;
LoggerInfo(isc::log::Severity sev = isc::log::INFO,
int dbg = MIN_DEBUG_LEVEL) : severity(sev), dbglevel(dbg)
{}
};
/// \brief Information About All Loggers
///
/// Information about all loggers in the system - except the root logger -
/// is held in a map, linking name of the logger (excluding the root
/// name component) and its set severity and debug levels. The root
/// logger information is held separately.
typedef std::map<std::string, LoggerInfo> LoggerInfoMap;
/// \brief Constructor
///
/// Creates a logger of the specific name.
......@@ -99,16 +85,16 @@ public:
///
/// \param severity Severity level to log
/// \param dbglevel If the severity is DEBUG, this is the debug level.
/// This can be in the range 1 to 100 and controls the verbosity. A value
/// This can be in the range 0 to 99 and controls the verbosity. A value
/// outside these limits is silently coerced to the nearest boundary.
virtual void setSeverity(isc::log::Severity severity, int dbglevel = 1);
virtual void setSeverity(Severity severity, int dbglevel = 1);
/// \brief Get Severity Level for Logger
///
/// \return The current logging level of this logger. In most cases though,
/// the effective logging level is what is required.
virtual isc::log::Severity getSeverity();
virtual Severity getSeverity();
/// \brief Get Effective Severity Level for Logger
......@@ -116,23 +102,32 @@ public:
/// \return The effective severity level of the logger. This is the same
/// as getSeverity() if the logger has a severity level set, but otherwise
/// is the severity of the parent.
virtual isc::log::Severity getEffectiveSeverity();
virtual Severity getEffectiveSeverity();
/// \brief Return DEBUG Level
/// \brief Return debug level
///
/// \return Current setting of debug level. This is returned regardless of
/// whether the
/// \return Current setting of debug level. This will be zero if the
/// the current severity level is not DEBUG.
virtual int getDebugLevel();
/// \brief Return effective debug level
///
/// \return Current setting of effective debug level. This will be zero if
/// the current effective severity level is not DEBUG.
virtual int getEffectiveDebugLevel();
/// \brief Returns if Debug Message Should Be Output
///
/// \param dbglevel Level for which debugging is checked. Debugging is
/// enabled only if the logger has DEBUG enabled and if the dbglevel
/// checked is less than or equal to the debug level set for the logger.
virtual bool
isDebugEnabled(int dbglevel = MIN_DEBUG_LEVEL);
virtual bool isDebugEnabled(int dbglevel = MIN_DEBUG_LEVEL) {
Level level(DEBUG, dbglevel);
return logger_.isEnabledFor(LoggerLevelImpl::convertFromBindLevel(level));
}
/// \brief Is INFO Enabled?
virtual bool isInfoEnabled() {
......@@ -180,36 +175,7 @@ public:
}
/// \brief Reset Global Data
///
/// Only used for testing, this clears all the logger information and
/// resets it back to default values.
static void reset() {
//root_logger_info_ = LoggerInfo(isc::log::INFO, MIN_DEBUG_LEVEL);
//logger_info_.clear();
}
private:
/// \brief Convert Log Levels
///
/// Converts a BIND 10 log level to a log4cplus log level.
///
/// \param inlevel BIND 10 log level.
///
/// \return Log4cplus log level.
log4cplus::LogLevel convertFromBindSeverity(
const isc::log::Severity& inlevel);
/// \brief Convert Log Levels
///
/// Converts a log4cplus log level to a BIND 10 log level.
///
/// \param inlevel log4cplus log level.
///
/// \return BIND 10 log level.
isc::log::Severity convertToBindSeverity(
const log4cplus::LogLevel& inlevel);
/// \brief Initialize log4cplus
///
......@@ -219,9 +185,8 @@ private:
bool is_root_; ///< Is this BIND 10 root logger?
std::string name_; ///< Full name of this logger
std::string fmt_name_; ///< Formatted name
std::string fmt_name_; ///< Formatted name for output
log4cplus::Logger logger_; ///< Underlying log4cplus logger
};
} // namespace log
......
......@@ -12,8 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef __LOGGER_LEVELS_H
#define __LOGGER_LEVELS_H
#ifndef __LOGGER_LEVEL_H
#define __LOGGER_LEVEL_H
namespace isc {
namespace log {
......@@ -36,7 +36,27 @@ typedef enum {
NONE = 6 // Disable logging
} Severity;
/// Minimum/maximum debug levels. These are defined wi
const int MIN_DEBUG_LEVEL = 0;
const int MAX_DEBUG_LEVEL = 99;
/// \brief Log level structure
///
/// A simple pair structure that provides suitable names for the members. It
/// holds a combination of logging severity and debug level.
struct Level {
Severity severity; ///< Logging severity
int dbglevel; ///< Debug level
Level(Severity sev = DEFAULT, int dbg = MIN_DEBUG_LEVEL) :
severity(sev), dbglevel(dbg)
{}
// Default assignment and copy constructor is appropriate
};
} // namespace log
} // namespace isc
#endif // __LOGGER_LEVELS_H
#endif // __LOGGER_LEVEL_H
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <algorithm>
#include <string.h>
#include <boost/lexical_cast.hpp>
#include <log4cplus/logger.h>
#include <log/logger_level.h>
#include <log/logger_level_impl.h>
using namespace log4cplus;
using namespace std;
namespace isc {
namespace log {
// Convert BIND 10 level to a log4cplus logging level.
log4cplus::LogLevel
LoggerLevelImpl::convertFromBindLevel(const Level& level) {
// BIND 10 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);
BOOST_STATIC_ASSERT(static_cast<int>(DEBUG) == 1);
BOOST_STATIC_ASSERT(static_cast<int>(INFO) == 2);
BOOST_STATIC_ASSERT(static_cast<int>(WARN) == 3);
BOOST_STATIC_ASSERT(static_cast<int>(ERROR) == 4);
BOOST_STATIC_ASSERT(static_cast<int>(FATAL) == 5);
BOOST_STATIC_ASSERT(static_cast<int>(NONE) == 6);
// 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 BIND 10 debug level. It is up to the
// caller to validate that the debug level is valid.
Level
LoggerLevelImpl::convertToBindLevel(const log4cplus::LogLevel loglevel) {