Commit 7855203e authored by Stephen Morris's avatar Stephen Morris
Browse files

[trac976] Remove all traces of old log4cxx implementation

parent e006dc3e
// 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 <iostream>
#include <stdarg.h>
#include <stdio.h>
#include <log4cxx/appender.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/patternlayout.h>
#include <log4cxx/consoleappender.h>
#include <log/root_logger_name.h>
#include <log/logger.h>
#include <log/logger_impl.h>
#include <log/message_dictionary.h>
#include <log/message_types.h>
#include <log/xdebuglevel.h>
#include <util/strutil.h>
using namespace std;
namespace isc {
namespace log {
// Static initializations
bool LoggerImpl::init_ = false;
// Destructor. Delete log4cxx stuff if "don't delete" is clear.
LoggerImpl::~LoggerImpl() {
if (exit_delete_) {
delete loggerptr_;
}
}
// Initialize logger - create a logger as a child of the root logger. With
// log4cxx this is assured by naming the logger <parent>.<child>.
void
LoggerImpl::initLogger() {
// Initialize basic logging if not already done. This is a one-off for
// all loggers.
if (!init_) {
// TEMPORARY
// Add a suitable console logger to the log4cxx root logger. (This
// is the logger at the root of the log4cxx tree, not the BIND-10 root
// logger, which is one level down.) The chosen format is:
//
// YYYY-MM-DD hh:mm:ss.sss [logger] SEVERITY: text
//
// As noted, this is a temporary hack: it is done here to ensure that
// a suitable output and output pattern is set. Future versions of the
// software will set this based on configuration data.
log4cxx::LayoutPtr layout(
new log4cxx::PatternLayout(
"%d{yyyy-MM-DD HH:mm:ss.SSS} %-5p [%c] %m\n"));
log4cxx::AppenderPtr console(
new log4cxx::ConsoleAppender(layout));
log4cxx::LoggerPtr sys_root_logger = log4cxx::Logger::getRootLogger();
sys_root_logger->addAppender(console);
// Set the default logging to INFO
sys_root_logger->setLevel(log4cxx::Level::getInfo());
// All static stuff initialized
init_ = true;
}
// Initialize this logger. Name this as to whether the BIND-10 root logger
// name has been set. (If not, this mucks up the hierarchy :-( ).
string root_name = RootLoggerName::getName();
if (root_name.empty() || (name_ == root_name)) {
loggerptr_ = new log4cxx::LoggerPtr(log4cxx::Logger::getLogger(name_));
}
else {
loggerptr_ = new log4cxx::LoggerPtr(
log4cxx::Logger::getLogger(root_name + "." + name_)
);
}
}
// Set the severity for logging. There is a 1:1 mapping between the logging
// severity and the log4cxx logging levels, apart from DEBUG.
//
// In log4cxx, each of the logging levels (DEBUG, INFO, WARN etc.) has a numeric
// value. The level is set to one of these and any numeric level equal to or
// above it that is reported. For example INFO has a value of 20000 and ERROR
// a value of 40000. So if a message of WARN severity (= 30000) is logged, it is
// not logged when the logger's severity level is ERROR (as 30000 !>= 40000).
// It is reported if the logger's severity level is set to WARN (as 30000 >=
/// 30000) or INFO (30000 >= 20000).
//
// This gives a simple system for handling different debug levels. The debug
// level is a number between 0 and 99, with 0 being least verbose and 99 the
// most. To implement this seamlessly, when DEBUG is set, the numeric value
// of the logging level is actually set to (DEBUG - debug-level). Similarly
// messages of level "n" are logged at a logging level of (DEBUG - n). Thus if
// the logging level is set to DEBUG and the debug level set to 25, the actual
// level set is 10000 - 25 = 99975.
//
// Attempting to log a debug message of level 26 is an attempt to log a message
// of level 10000 - 26 = 9974. As 9974 !>= 9975, it is not logged. A
// message of level 25 is, because 9975 >= 9975.
//
// The extended set of logging levels is implemented by the XDebugLevel class.
void
LoggerImpl::setSeverity(isc::log::Severity severity, int dbglevel) {
switch (severity) {
case NONE:
getLogger()->setLevel(log4cxx::Level::getOff());
break;
case FATAL:
getLogger()->setLevel(log4cxx::Level::getFatal());
break;
case ERROR:
getLogger()->setLevel(log4cxx::Level::getError());
break;
case WARN:
getLogger()->setLevel(log4cxx::Level::getWarn());
break;
case INFO:
getLogger()->setLevel(log4cxx::Level::getInfo());
break;
case DEBUG:
getLogger()->setLevel(
log4cxx::XDebugLevel::getExtendedDebug(dbglevel));
break;
// Will get here for DEFAULT or any other value. This disables the
// logger's own severity and it defaults to the severity of the parent
// logger.
default:
getLogger()->setLevel(0);
}
}
// Convert between numeric log4cxx logging level and BIND-10 logging severity.
isc::log::Severity
LoggerImpl::convertLevel(int value) {
// The order is optimised. This is only likely to be called when testing
// for writing debug messages, so the check for DEBUG_INT is first.
if (value <= log4cxx::Level::DEBUG_INT) {
return (DEBUG);
} else if (value <= log4cxx::Level::INFO_INT) {
return (INFO);
} else if (value <= log4cxx::Level::WARN_INT) {
return (WARN);
} else if (value <= log4cxx::Level::ERROR_INT) {
return (ERROR);
} else if (value <= log4cxx::Level::FATAL_INT) {
return (FATAL);
} else {
return (NONE);
}
}
// Return the logging severity associated with this logger.
isc::log::Severity
LoggerImpl::getSeverityCommon(const log4cxx::LoggerPtr& ptrlogger,
bool check_parent) {
log4cxx::LevelPtr level = ptrlogger->getLevel();
if (level == log4cxx::LevelPtr()) {
// Null level returned, logging should be that of the parent.
if (check_parent) {
log4cxx::LoggerPtr parent = ptrlogger->getParent();
if (parent == log4cxx::LoggerPtr()) {
// No parent, so reached the end of the chain. Return INFO
// severity.
return (INFO);
}
else {
return (getSeverityCommon(parent, check_parent));
}
}
else {
return (DEFAULT);
}
} else {
return (convertLevel(level->toInt()));
}
}
// Get the debug level. This returns 0 unless the severity is DEBUG.
int
LoggerImpl::getDebugLevel() {
log4cxx::LevelPtr level = getLogger()->getLevel();
if (level == log4cxx::LevelPtr()) {
// Null pointer returned, logging should be that of the parent.
return (0);
} else {
int severity = level->toInt();
if (severity <= log4cxx::Level::DEBUG_INT) {
return (log4cxx::Level::DEBUG_INT - severity);
}
else {
return (0);
}
}
}
} // namespace log
} // namespace isc
// 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 __LOGGER_IMPL_LOG4CXX_H
#define __LOGGER_IMPL_LOG4CXX_H
#include <cstdlib>
#include <string>
#include <boost/lexical_cast.hpp>
#include <log4cxx/logger.h>
#include <log4cxx/logger.h>
#include <log/debug_levels.h>
#include <log/logger.h>
#include <log/message_types.h>
namespace isc {
namespace log {
/// \brief Log4cxx Logger Implementation
///
/// 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 interfacing to the log4cxx logging system.
class LoggerImpl {
public:
/// \brief Constructor
///
/// Creates/attaches to a logger of a specific name.
///
/// \param name Name of the logger. If the name is that of the root name,
/// this creates an instance of the root logger; otherwise it creates a
/// child of the root logger.
///
/// \param exit_delete This argument is present to get round a bug in
/// log4cxx. If a log4cxx logger is declared outside an execution unit, it
/// is not deleted until the program runs down. At that point all such
/// objects - including internal log4cxx objects - are deleted. However,
/// there seems to be a bug in log4cxx where the way that such objects are
/// destroyed causes a MutexException to be thrown (this is described in
/// https://issues.apache.org/jira/browse/LOGCXX-322). As this only occurs
/// during program rundown, the issue is not serious - it just looks bad to
/// have the program crash instead of shut down cleanly.\n
/// \n
/// The original implementation of the isc::log::Logger had as a member a
/// log4cxx logger (actually a LoggerPtr). If the isc:: Logger was declared
/// statically, when it was destroyed at the end of the program the internal
/// LoggerPtr was destroyed, which triggered the problem. The problem did
/// not occur if the isc::log::Logger was created on the stack. To get
/// round this, the internal LoggerPtr is now created dynamically. The
/// exit_delete argument controls its destruction: if true, it is destroyed
/// in the ISC Logger destructor. If false, it is not.\n
/// \n
/// When creating an isc::log::Logger on the stack, the argument should be
/// false (the default); when the Logger is destroyed, all the internal
/// log4cxx objects are destroyed. As only the logger (and not the internal
/// log4cxx data structures are being destroyed), all is well. However,
/// when creating the logger statically, the argument should be false. This
/// means that the log4cxx objects are not destroyed at program rundown;
/// instead memory is reclaimed and files are closed when the process is
/// destroyed, something that does not trigger the bug.
LoggerImpl(const std::string& name, bool exit_delete = false) :
loggerptr_(NULL), name_(name), exit_delete_(exit_delete)
{}
/// \brief Destructor
virtual ~LoggerImpl();
/// \brief Get the full name of the logger (including the root name)
virtual std::string getName() {
return (getLogger()->getName());
}
/// \brief Set Severity Level for Logger
///
/// Sets the level at which this logger will log messages. If none is set,
/// the level is inherited from the parent.
///
/// \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
/// outside these limits is silently coerced to the nearest boundary.
virtual void setSeverity(isc::log::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() {
return (getSeverityCommon(getLogger(), false));
}
/// \brief Get Effective Severity Level for Logger
///
/// \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() {
return (getSeverityCommon(getLogger(), true));
}
/// \brief Return DEBUG Level
///
/// \return Current setting of debug level. This is returned regardless of
/// whether the
virtual int getDebugLevel();
/// \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) {
return (getLogger()->getEffectiveLevel()->toInt() <=
(log4cxx::Level::DEBUG_INT - dbglevel));
}
/// \brief Is INFO Enabled?
virtual bool isInfoEnabled() {
return (getLogger()->isInfoEnabled());
}
/// \brief Is WARNING Enabled?
virtual bool isWarnEnabled() {
return (getLogger()->isWarnEnabled());
}
/// \brief Is ERROR Enabled?
virtual bool isErrorEnabled() {
return (getLogger()->isErrorEnabled());
}
/// \brief Is FATAL Enabled?
virtual bool isFatalEnabled() {
return (getLogger()->isFatalEnabled());
}
/// \brief Output Debug Message
///
/// \param ident Message identification.
/// \param text Text to log
void debug(const MessageID& ident, const char* text) {
LOG4CXX_DEBUG(getLogger(), ident << ", " << text);
}
/// \brief Output Informational Message
///
/// \param ident Message identification.
/// \param text Text to log
void info(const MessageID& ident, const char* text) {
LOG4CXX_INFO(getLogger(), ident << ", " << text);
}
/// \brief Output Warning Message
///
/// \param ident Message identification.
/// \param text Text to log
void warn(const MessageID& ident, const char* text) {
LOG4CXX_WARN(getLogger(), ident << ", " << text);
}
/// \brief Output Error Message
///
/// \param ident Message identification.
/// \param text Text to log
void error(const MessageID& ident, const char* text) {
LOG4CXX_ERROR(getLogger(), ident << ", " << text);
}
/// \brief Output Fatal Message
///
/// \param ident Message identification.
/// \param text Text to log
void fatal(const MessageID& ident, const char* text) {
LOG4CXX_FATAL(getLogger(), ident << ", " << text);
}
//@{
/// \brief Testing Methods
///
/// The next set of methods are used in testing. As they are accessed from
/// the main logger class, they must be public.
/// \brief Equality
///
/// Check if two instances of this logger refer to the same stream.
/// (This method is principally for testing.)
///
/// \return true if the logger objects are instances of the same logger.
bool operator==(LoggerImpl& other) {
return (*loggerptr_ == *other.loggerptr_);
}
/// \brief Logger Initialized
///
/// Check that the logger has been properly initialized. (This method
/// is principally for testing.)
///
/// \return true if this logger object has been initialized.
bool isInitialized() {
return (loggerptr_ != NULL);
}
/// \brief Reset Global Data
///
/// Only used for testing, this clears all the logger information and
/// resets it back to default values. This is a no-op for log4cxx.
static void reset() {
}
//@}
protected:
/// \brief Convert Between BIND-10 and log4cxx Logging Levels
///
/// This method is marked protected to allow for unit testing.
///
/// \param value log4cxx numeric logging level
///
/// \return BIND-10 logging severity
isc::log::Severity convertLevel(int value);
private:
/// \brief Get Severity Level for Logger
///
/// This is common code for getSeverity() and getEffectiveSeverity() -
/// it returns the severity of the logger; if not set (and the check_parent)
/// flag is set, it searches up the parent-child tree until a severity
/// level is found and uses that.
///
/// \param ptrlogger Pointer to the log4cxx logger to check.
/// \param check_parent true to search up the tree, false to return the
/// current level.
///
/// \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.
isc::log::Severity getSeverityCommon(const log4cxx::LoggerPtr& ptrlogger,
bool check_parent);
/// \brief Initialize log4cxx Logger
///
/// Creates the log4cxx logger used internally. A function is provided for
/// this so that the creation does not take place when this Logger object
/// is created but when it is used. As the latter occurs in executable
/// code but the former can occur during initialization, this order
/// guarantees that anything that is statically initialized has completed
/// its initialization by the time the logger is used.
void initLogger();
/// \brief Return underlying log4cxx logger, initializing it if necessary
///
/// \return Loggerptr object
log4cxx::LoggerPtr& getLogger() {
if (loggerptr_ == NULL) {
initLogger();
}
return (*loggerptr_);
}
// Members. Note that loggerptr_ is a pointer to a LoggerPtr, which is
// itself a pointer to the underlying log4cxx logger. This is due to the
// problems with memory deletion on program exit, explained in the comments
// for the "exit_delete" parameter in this class's constructor.
log4cxx::LoggerPtr* loggerptr_; ///< Pointer to the underlying logger
std::string name_; ///< Name of this logger]
bool exit_delete_; ///< Delete loggerptr_ on exit?
// NOTE - THIS IS A PLACE HOLDER
static bool init_; ///< Set true when initialized
};
} // namespace log
} // namespace isc
#endif // __LOGGER_IMPL_LOG4CXX_H
......@@ -20,8 +20,8 @@
/// \brief Define Name of Root Logger
///
/// In BIND-10, the name root logger of a program is the name of the program
/// itself (in contrast to packages such as log4cxx where the root logger name
// is something like "."). These trivial functions allow the setting and
/// itself (in contrast to packages such as log4cplus where the root logger name
// is something like "root"). These trivial functions allow the setting and
// getting of that name by the logger classes.
namespace isc {
......
// 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 <iostream>
#include <string>
#include <gtest/gtest.h>
#include <log/root_logger_name.h>
#include <log/logger.h>
#include <log/logger_impl.h>
#include <log/messagedef.h>
using namespace isc;
using namespace isc::log;
using namespace std;
/// \brief Log4cxx Implementation Tests
///
/// Some tests of methods that are not directly tested by the logger unit tests
/// (when the logger is configured to use log4cxx)
namespace isc {
namespace log {
/// \brief Test Logger
///
/// This logger is a subclass of the logger implementation class under test, but
/// makes protected methods public (for testing)
class TestLoggerImpl : public LoggerImpl {
public:
/// \brief constructor
TestLoggerImpl(const string& name) : LoggerImpl(name, true)
{}
/// \brief Conversion Between log4cxx Number and BIND-10 Severity
Severity convertLevel(int value) {
return (LoggerImpl::convertLevel(value));
}
};
} // namespace log
} // namespace isc