Commit 8e66cc33 authored by Stephen Morris's avatar Stephen Morris
Browse files

[trac1024] Suppress logging messages in logging library unit tests

Add a reset logging function to specific tests to ensure that the
logging is routed to the stream selected by the B10 environment
variables prior to each test that generates messages.
parent e540aaf2
......@@ -15,7 +15,7 @@
#include <gtest/gtest.h>
#include <util/unittests/run_all.h>
#include <log/logger_manager.h>
#include <log/logger_support.h>
#include <dns/tests/unittest_util.h>
int
......
......@@ -20,6 +20,7 @@ liblog_la_SOURCES += logger_manager_impl.cc logger_manager_impl.h
liblog_la_SOURCES += logger_name.cc logger_name.h
liblog_la_SOURCES += logger_specification.h
liblog_la_SOURCES += logger_support.cc logger_support.h
liblog_la_SOURCES += logger_unittest_support.cc logger_unittest_support.h
liblog_la_SOURCES += macros.h
liblog_la_SOURCES += log_messages.cc log_messages.h
liblog_la_SOURCES += message_dictionary.cc message_dictionary.h
......
......@@ -12,28 +12,9 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE
/// \brief Temporary Logger Support
///
/// Performs run-time initialization of the logger system. In particular, it
/// is passed information from the command line and:
///
/// a) Sets the severity of the messages being logged (and debug level if
/// appropriate).
/// b) Reads in the local message file is one has been supplied.
///
/// These functions will be replaced once the code has been written to obtain
/// the logging parameters from the configuration database.
#include <iostream>
#include <algorithm>
#include <iostream>
#include <string>
#include <log/logger_level.h>
#include <log/logger_manager.h>
#include <log/logger_specification.h>
#include <log/logger_support.h>
#include <log/output_option.h>
#include <log/logger_manager.h>
using namespace std;
......@@ -42,80 +23,6 @@ namespace {
// Flag to hold logging initialization state.
bool logging_init_state = false;
// Set logging destination according to the setting of B10_LOGGER_DESTINATION.
// (See header for initLogger() for more details.) This is a no-op if the
// environment variable is not defined.
//
// \param root Name of the root logger
// \param severity Severity level to be assigned to the root logger
// \param dbglevel Debug level
void
setDestination(const char* root, const isc::log::Severity severity,
const int dbglevel) {
using namespace isc::log;
// Constants: not declared static as this is function is expected to be
// called once only
const string DEVNULL = "/dev/null";
const string STDOUT = "stdout";
const string STDERR = "stderr";
const string SYSLOG = "syslog";
const string SYSLOG_COLON = "syslog:";
// Get the destination. If not specified, assume /dev/null. (The default
// severity for unit tests is DEBUG, which generates a lot of output.
// Routing the logging to /dev/null will suppress that, whilst still
// ensuring that the code paths are tested.)
const char* destination = getenv("B10_LOGGER_DESTINATION");
const string dest((destination == NULL) ? DEVNULL : destination);
// Prepare the objects to define the logging specification
LoggerSpecification spec(root, severity, dbglevel);
OutputOption option;
// Set up output option according to destination specification
if (dest == STDOUT) {
option.destination = OutputOption::DEST_CONSOLE;
option.stream = OutputOption::STR_STDOUT;
} else if (dest == STDERR) {
option.destination = OutputOption::DEST_CONSOLE;
option.stream = OutputOption::STR_STDERR;
} else if (dest == SYSLOG) {
option.destination = OutputOption::DEST_SYSLOG;
// Use default specified in OutputOption constructor for the
// syslog destination
} else if (dest.find(SYSLOG_COLON) == 0) {
option.destination = OutputOption::DEST_SYSLOG;
// Must take account of the string actually being "syslog:"
if (dest == SYSLOG_COLON) {
cerr << "**ERROR** value for B10_LOGGER_DESTINATION of " <<
SYSLOG_COLON << " is invalid, " << SYSLOG <<
" will be used instead\n";
// Use default for logging facility
} else {
// Everything else in the string is the facility name
option.facility = dest.substr(SYSLOG_COLON.size());
}
} else {
// Not a recognised destination, assume a file.
option.destination = OutputOption::DEST_FILE;
option.filename = dest;
}
// ... and set the destination
spec.addOutputOption(option);
LoggerManager manager;
manager.process(spec);
}
} // Anonymous namespace
namespace isc {
......@@ -143,63 +50,5 @@ initLogger(const string& root, isc::log::Severity severity, int dbglevel,
LoggerManager::init(root, severity, dbglevel, file);
}
// Logger Run-Time Initialization via Environment Variables
void initLogger(isc::log::Severity severity, int dbglevel) {
// Root logger name is defined by the environment variable B10_LOGGER_ROOT.
// If not present, the name is "bind10".
const char* DEFAULT_ROOT = "bind10";
const char* root = getenv("B10_LOGGER_ROOT");
if (! root) {
root = DEFAULT_ROOT;
}
// Set the logging severity. The environment variable is
// B10_LOGGER_SEVERITY, and can be one of "DEBUG", "INFO", "WARN", "ERROR"
// of "FATAL". Note that the string must be in upper case with no leading
// of trailing blanks.
const char* sev_char = getenv("B10_LOGGER_SEVERITY");
if (sev_char) {
severity = isc::log::getSeverity(sev_char);
}
// If the severity is debug, get the debug level (environment variable
// B10_LOGGER_DBGLEVEL), which should be in the range 0 to 99.
if (severity == isc::log::DEBUG) {
const char* dbg_char = getenv("B10_LOGGER_DBGLEVEL");
if (dbg_char) {
int level = 0;
try {
level = boost::lexical_cast<int>(dbg_char);
if (level < MIN_DEBUG_LEVEL) {
cerr << "**ERROR** debug level of " << level
<< " is invalid - a value of " << MIN_DEBUG_LEVEL
<< " will be used\n";
level = MIN_DEBUG_LEVEL;
} else if (level > MAX_DEBUG_LEVEL) {
cerr << "**ERROR** debug level of " << level
<< " is invalid - a value of " << MAX_DEBUG_LEVEL
<< " will be used\n";
level = MAX_DEBUG_LEVEL;
}
} catch (...) {
// Error, but not fatal to the test
cerr << "**ERROR** Unable to translate "
"B10_LOGGER_DBGLEVEL - a value of 0 will be used\n";
}
dbglevel = level;
}
}
// Set the local message file
const char* localfile = getenv("B10_LOGGER_LOCALMSG");
// Initialize logging
initLogger(root, severity, dbglevel, localfile);
// Now set the destination for logging output
setDestination(root, severity, dbglevel);
}
} // namespace log
} // namespace isc
......@@ -20,6 +20,9 @@
#include <string>
#include <log/logger.h>
// Include the unit test function declarations here for compatibility
#include <log/logger_unittest_support.h>
namespace isc {
namespace log {
......@@ -63,50 +66,6 @@ void initLogger(const std::string& root,
int dbglevel = 0, const char* file = NULL);
/// \brief Run-Time Initialization from Environment
///
/// Performs run-time initialization of the logger via the setting of
/// environment variables. These are:
///
/// - B10_LOGGER_ROOT\n
/// Name of the root logger. If not given, the string "bind10" will be used.
///
/// - B10_LOGGER_SEVERITY\n
/// Severity of messages that will be logged. This must be one of the strings
/// "DEBUG", "INFO", "WARN", "ERROR", "FATAL" or "NONE". (Must be upper case
/// and must not contain leading or trailing spaces.) If not specified (or if
/// specified but incorrect), the default passed as argument to this function
/// (currently DEBUG) will be used.
///
/// - B10_LOGGER_DBGLEVEL\n
/// Ignored if the level is not DEBUG, this should be a number between 0 and
/// 99 indicating the logging severity. The default is 0. If outside these
/// limits or if not a number, The value passed to this function (default
/// of MAX_DEBUG_LEVEL) is used.
///
/// - B10_LOGGER_LOCALMSG\n
/// If defined, the path specification of a file that contains message
/// definitions replacing ones in the default dictionary.
///
/// - B10_LOGGER_DESTINATION\n
/// If defined, the destination of the logging output. This can be one of:
/// - \c stdout Send output to stdout.
/// - \c stderr Send output to stderr
/// - \c syslog Send output to syslog using the facility local0.
/// - \c syslog:xxx Send output to syslog, using the facility xxx. ("xxx"
/// should be one of the syslog facilities such as "local0".) There must
/// be a colon between "syslog" and "xxx
/// - \c other Anything else is interpreted as the name of a file to which
/// output is appended. If the file does not exist, it is created.
///
/// Any errors in the settings cause messages to be output to stderr.
///
/// This function is aimed at test programs, allowing the default settings to
/// be overridden by the tester. It is not intended for use in production
/// code.
void initLogger(isc::log::Severity severity = isc::log::DEBUG,
int dbglevel = isc::log::MAX_DEBUG_LEVEL);
} // 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.
#include <iostream>
#include <algorithm>
#include <string>
#include <log/logger_level.h>
#include <log/logger_name.h>
#include <log/logger_manager.h>
#include <log/logger_specification.h>
#include <log/logger_unittest_support.h>
#include <log/logger_support.h>
#include <log/output_option.h>
using namespace std;
namespace isc {
namespace log {
// Get the logging severity. This is defined by the environment variable
// B10_LOGGER_SEVERITY, and can be one of "DEBUG", "INFO", "WARN", "ERROR"
// of "FATAL". (Note that the string must be in upper case with no leading
// of trailing blanks.) If not present, the default severity passed to the
// function is returned.
isc::log::Severity
b10LoggerSeverity(isc::log::Severity defseverity) {
const char* sev_char = getenv("B10_LOGGER_SEVERITY");
if (sev_char) {
return (isc::log::getSeverity(sev_char));
}
return (defseverity);
}
// Get the debug level. This is defined by the envornment variable
// B10_LOGGER_DBGLEVEL. If not defined, a default value passed to the function
// is returned.
int
b10LoggerDbglevel(int defdbglevel) {
const char* dbg_char = getenv("B10_LOGGER_DBGLEVEL");
if (dbg_char) {
int level = 0;
try {
level = boost::lexical_cast<int>(dbg_char);
if (level < MIN_DEBUG_LEVEL) {
std::cerr << "**ERROR** debug level of " << level
<< " is invalid - a value of " << MIN_DEBUG_LEVEL
<< " will be used\n";
level = MIN_DEBUG_LEVEL;
} else if (level > MAX_DEBUG_LEVEL) {
std::cerr << "**ERROR** debug level of " << level
<< " is invalid - a value of " << MAX_DEBUG_LEVEL
<< " will be used\n";
level = MAX_DEBUG_LEVEL;
}
} catch (...) {
// Error, but not fatal to the test
std::cerr << "**ERROR** Unable to translate "
"B10_LOGGER_DBGLEVEL - a value of 0 will be used\n";
}
return (level);
}
return (defdbglevel);
}
// Reset characteristics of the root logger to that set by the environment
// variables B10_LOGGER_SEVERITY, B10_LOGGER_DBGLEVEL and B10_LOGGER_DESTINATION.
void
setUnitTestRootLoggerCharacteristics() {
using namespace isc::log;
// Constants: not declared static as this is function is expected to be
// called once only
const string DEVNULL = "/dev/null";
const string STDOUT = "stdout";
const string STDERR = "stderr";
const string SYSLOG = "syslog";
const string SYSLOG_COLON = "syslog:";
// Get the destination. If not specified, assume /dev/null. (The default
// severity for unit tests is DEBUG, which generates a lot of output.
// Routing the logging to /dev/null will suppress that, whilst still
// ensuring that the code paths are tested.)
const char* destination = getenv("B10_LOGGER_DESTINATION");
const string dest((destination == NULL) ? DEVNULL : destination);
// Prepare the objects to define the logging specification
LoggerSpecification spec(getRootLoggerName(),
b10LoggerSeverity(isc::log::DEBUG),
b10LoggerDbglevel(isc::log::MAX_DEBUG_LEVEL));
OutputOption option;
// Set up output option according to destination specification
if (dest == STDOUT) {
option.destination = OutputOption::DEST_CONSOLE;
option.stream = OutputOption::STR_STDOUT;
} else if (dest == STDERR) {
option.destination = OutputOption::DEST_CONSOLE;
option.stream = OutputOption::STR_STDERR;
} else if (dest == SYSLOG) {
option.destination = OutputOption::DEST_SYSLOG;
// Use default specified in OutputOption constructor for the
// syslog destination
} else if (dest.find(SYSLOG_COLON) == 0) {
option.destination = OutputOption::DEST_SYSLOG;
// Must take account of the string actually being "syslog:"
if (dest == SYSLOG_COLON) {
cerr << "**ERROR** value for B10_LOGGER_DESTINATION of " <<
SYSLOG_COLON << " is invalid, " << SYSLOG <<
" will be used instead\n";
// Use default for logging facility
} else {
// Everything else in the string is the facility name
option.facility = dest.substr(SYSLOG_COLON.size());
}
} else {
// Not a recognised destination, assume a file.
option.destination = OutputOption::DEST_FILE;
option.filename = dest;
}
// ... and set the destination
spec.addOutputOption(option);
LoggerManager manager;
manager.process(spec);
}
// Logger Run-Time Initialization via Environment Variables
void initLogger(isc::log::Severity severity, int dbglevel) {
// Root logger name is defined by the environment variable B10_LOGGER_ROOT.
// If not present, the name is "bind10".
const char* DEFAULT_ROOT = "bind10";
const char* root = getenv("B10_LOGGER_ROOT");
if (! root) {
root = DEFAULT_ROOT;
}
// Set the local message file
const char* localfile = getenv("B10_LOGGER_LOCALMSG");
// Initialize logging
initLogger(root, isc::log::DEBUG, isc::log::MAX_DEBUG_LEVEL, localfile);
// Now set reset the output destination of the root logger, overriding
// the default severity, debug level and destination with those specified
// in the environment variables. (The two-step approach is used as the
// setUnitTestRootLoggerCharacteristics() function is used in several
// places in the BIND 10 tests, and it avoid duplicating code.)
setUnitTestRootLoggerCharacteristics();
}
} // 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_UNITTEST_SUPPORT_H
#define __LOGGER_UNITTEST_SUPPORT_H
#include <string>
#include <log/logger.h>
// Note: this file holds logging functions used by unit tests.
namespace isc {
namespace log {
/// \brief Run-Time Initialization for Unit Tests from Environment
///
/// Performs run-time initialization of the logger via the setting of
/// environment variables. These are:
///
/// - B10_LOGGER_ROOT\n
/// Name of the root logger. If not given, the string "bind10" will be used.
///
/// - B10_LOGGER_SEVERITY\n
/// Severity of messages that will be logged. This must be one of the strings
/// "DEBUG", "INFO", "WARN", "ERROR", "FATAL" or "NONE". (Must be upper case
/// and must not contain leading or trailing spaces.) If not specified (or if
/// specified but incorrect), the default passed as argument to this function
/// (currently DEBUG) will be used.
///
/// - B10_LOGGER_DBGLEVEL\n
/// Ignored if the level is not DEBUG, this should be a number between 0 and
/// 99 indicating the logging severity. The default is 0. If outside these
/// limits or if not a number, The value passed to this function (default
/// of MAX_DEBUG_LEVEL) is used.
///
/// - B10_LOGGER_LOCALMSG\n
/// If defined, the path specification of a file that contains message
/// definitions replacing ones in the default dictionary.
///
/// - B10_LOGGER_DESTINATION\n
/// If defined, the destination of the logging output. This can be one of:
/// - \c stdout Send output to stdout.
/// - \c stderr Send output to stderr
/// - \c syslog Send output to syslog using the facility local0.
/// - \c syslog:xxx Send output to syslog, using the facility xxx. ("xxx"
/// should be one of the syslog facilities such as "local0".) There must
/// be a colon between "syslog" and "xxx
/// - \c other Anything else is interpreted as the name of a file to which
/// output is appended. If the file does not exist, it is created.
///
/// Any errors in the settings cause messages to be output to stderr.
///
/// This function is aimed at test programs, allowing the default settings to
/// be overridden by the tester. It is not intended for use in production
/// code.
///
/// TODO: Rename. This function overloads the initLogger() function that can
/// be used to initialize production programs. This may lead to confusion.
void initLogger(isc::log::Severity severity = isc::log::DEBUG,
int dbglevel = isc::log::MAX_DEBUG_LEVEL);
/// \brief Logging Severity from B10_LOGGER_SEVERITY
///
/// Support function called by the unit test logging initialization code.
/// It returns the logging severity defined by B10_LOGGER_SEVERITY. If
/// not defined it returns the default passed to it.
///
/// \param defseverity Default severity used if B10_LOGGER_SEVERITY is not
// defined.
///
/// \return Severity to use for the logging.
isc::log::Severity b10LoggerSeverity(isc::log::Severity defseverity);
/// \brief Logging Debug Level from B10_LOGGER_DBGLEVEL
///
/// Support function called by the unit test logging initialization code.
/// It returns the logging debug level defined by B10_LOGGER_DBGLEVEL. If
/// not defined, it returns the default passed to it.
///
/// N.B. If there is an error, a message is written to stderr and a value
/// related to the error is used. (This is because (a) logging is not yet
/// initialized, hence only the error stream is known to exist, and (b) this
/// function is only used in unit test logging initialization, so incorrect
/// selection of a level is not really an issue.)
///
/// \param defdbglevel Default debug level to be used if B10_LOGGER_DBGLEVEL
/// is not defined.
///
/// \return Debug level to use.
int b10LoggerDbglevel(int defdbglevel);
/// \brief Reset Logger Characteristics
///
/// This is a simplified interface into the setting of the characteristics
/// of the root logger. It is aimed for use in unit tests and resets the
/// characteristics of the root logger to use a severity, debug level and
/// destination set by the environment variables B10_LOGGER_SEVERITY,
/// B10_LOGGER_DBGLEVEL and B10_LOGGER_DESTINATION.
void
setUnitTestRootLoggerCharacteristics();
} // namespace log
} // namespace isc
#endif // __LOGGER_UNITTEST_SUPPORT_H
......@@ -20,6 +20,7 @@
#include <boost/lexical_cast.hpp>
#include <log/logger_level_impl.h>
#include <log/logger_support.h>
#include <log4cplus/logger.h>
using namespace isc::log;
......@@ -27,8 +28,10 @@ using namespace std;
class LoggerLevelImplTest : public ::testing::Test {
protected:
LoggerLevelImplTest()
{}
LoggerLevelImplTest() {
// Ensure logging set to default for unit tests
setUnitTestRootLoggerCharacteristics();
}
~LoggerLevelImplTest()
{}
......
......@@ -20,7 +20,7 @@
#include <log/logger.h>
#include <log/logger_manager.h>
#include <log/log_messages.h>
#include <log/logger_name.h>
#include <log/logger_support.h>
using namespace isc;
using namespace isc::log;
......@@ -29,7 +29,9 @@ using namespace std;
class LoggerLevelTest : public ::testing::Test {
protected:
LoggerLevelTest() {
// Logger initialization is done in main()
// Logger initialization is done in main(). As logging tests may
// alter the default logging output, it is reset here.
setUnitTestRootLoggerCharacteristics();
}
~LoggerLevelTest() {
LoggerManager::reset();
......@@ -57,7 +59,7 @@ TEST_F(LoggerLevelTest, Creation) {
EXPECT_EQ(42, level3.dbglevel);
}
TEST(LoggerLevel, getSeverity) {
TEST_F(LoggerLevelTest, getSeverity) {
EXPECT_EQ(DEBUG, getSeverity("DEBUG"));
EXPECT_EQ(DEBUG, getSeverity("debug"));
EXPECT_EQ(DEBUG, getSeverity("DeBuG"));
......
......@@ -18,12 +18,23 @@
using namespace isc::log;
class LoggerSupportTest : public ::testing::Test {
protected:
LoggerSupportTest() {
// Logger initialization is done in main(). As logging tests may
// alter the default logging output, it is reset here.
setUnitTestRootLoggerCharacteristics();
}
~LoggerSupportTest() {
}
};
// Check that the initialized flag can be manipulated. This is a bit chicken-
// -and-egg: we want to reset to the flag to the original value at the end
// of the test, so use the functions to do that. But we are trying to check
// that these functions in fact work.
TEST(LoggerSupportTest, InitializedFlag) {
TEST_F(LoggerSupportTest, InitializedFlag) {