mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-04 16:05:17 +00:00
[#2537] add inheritance of output_options
Unlike severity and debug level that have inheritance support embedded in log4cplus, output_options do not. This commit adds support for this inheritance by storing a copy of the root logger's specification and using it on child loggers if they don't have a specification themselves.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC")
|
// Copyright (C) 2011-2022 Internet Systems Consortium, Inc. ("ISC")
|
||||||
//
|
//
|
||||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
// 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
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -62,8 +62,10 @@ LoggerManagerImpl::processEnd() {
|
|||||||
// add output specifications.
|
// add output specifications.
|
||||||
void
|
void
|
||||||
LoggerManagerImpl::processSpecification(const LoggerSpecification& spec) {
|
LoggerManagerImpl::processSpecification(const LoggerSpecification& spec) {
|
||||||
log4cplus::Logger logger = log4cplus::Logger::getInstance(
|
string const& name(spec.getName());
|
||||||
expandLoggerName(spec.getName()));
|
string const& root_logger_name(getRootLoggerName());
|
||||||
|
|
||||||
|
log4cplus::Logger logger = log4cplus::Logger::getInstance(expandLoggerName(name));
|
||||||
|
|
||||||
// Set severity level according to specification entry.
|
// Set severity level according to specification entry.
|
||||||
logger.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
|
logger.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
|
||||||
@@ -72,36 +74,48 @@ LoggerManagerImpl::processSpecification(const LoggerSpecification& spec) {
|
|||||||
// Set the additive flag.
|
// Set the additive flag.
|
||||||
logger.setAdditivity(spec.getAdditive());
|
logger.setAdditivity(spec.getAdditive());
|
||||||
|
|
||||||
|
// Replace all appenders for this logger.
|
||||||
|
logger.removeAllAppenders();
|
||||||
|
|
||||||
|
if (name == root_logger_name) {
|
||||||
|
// Store a copy of the root specification. It might be required later.
|
||||||
|
root_spec_ = spec;
|
||||||
|
}
|
||||||
|
|
||||||
// Output options given?
|
// Output options given?
|
||||||
if (spec.optionCount() > 0) {
|
if (spec.optionCount() > 0) {
|
||||||
// Replace all appenders for this logger.
|
// If there are output options provided, continue with the given spec.
|
||||||
logger.removeAllAppenders();
|
appenderFactory(logger, spec);
|
||||||
|
} else {
|
||||||
|
// If there are no output options, inherit them from the root logger.
|
||||||
|
appenderFactory(logger, root_spec_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Now process output specifications.
|
void
|
||||||
for (LoggerSpecification::const_iterator i = spec.begin();
|
LoggerManagerImpl::appenderFactory(log4cplus::Logger& logger,
|
||||||
i != spec.end(); ++i) {
|
LoggerSpecification const& spec) {
|
||||||
switch (i->destination) {
|
for (OutputOption const& i : spec) {
|
||||||
case OutputOption::DEST_CONSOLE:
|
switch (i.destination) {
|
||||||
createConsoleAppender(logger, *i);
|
case OutputOption::DEST_CONSOLE:
|
||||||
break;
|
createConsoleAppender(logger, i);
|
||||||
|
break;
|
||||||
|
|
||||||
case OutputOption::DEST_FILE:
|
case OutputOption::DEST_FILE:
|
||||||
createFileAppender(logger, *i);
|
createFileAppender(logger, i);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OutputOption::DEST_SYSLOG:
|
case OutputOption::DEST_SYSLOG:
|
||||||
createSyslogAppender(logger, *i);
|
createSyslogAppender(logger, i);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Not a valid destination. As we are in the middle of updating
|
// Not a valid destination. As we are in the middle of updating
|
||||||
// logging destinations, we could be in the situation where
|
// logging destinations, we could be in the situation where
|
||||||
// there are no valid appenders. For this reason, throw an
|
// there are no valid appenders. For this reason, throw an
|
||||||
// exception.
|
// exception.
|
||||||
isc_throw(UnknownLoggingDestination,
|
isc_throw(UnknownLoggingDestination,
|
||||||
"Unknown logging destination, code = " <<
|
"Unknown logging destination, code = " << i.destination);
|
||||||
i->destination);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2011-2019 Internet Systems Consortium, Inc. ("ISC")
|
// Copyright (C) 2011-2022 Internet Systems Consortium, Inc. ("ISC")
|
||||||
//
|
//
|
||||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
// 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
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <log4cplus/appender.h>
|
#include <log4cplus/appender.h>
|
||||||
#include <log/logger_level.h>
|
#include <log/logger_level.h>
|
||||||
|
#include <log/logger_specification.h>
|
||||||
|
|
||||||
// Forward declaration to avoid need to include log4cplus header file here.
|
// Forward declaration to avoid need to include log4cplus header file here.
|
||||||
namespace log4cplus {
|
namespace log4cplus {
|
||||||
@@ -22,7 +23,6 @@ namespace isc {
|
|||||||
namespace log {
|
namespace log {
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
class LoggerSpecification;
|
|
||||||
struct OutputOption;
|
struct OutputOption;
|
||||||
|
|
||||||
/// \brief Logger Manager Implementation
|
/// \brief Logger Manager Implementation
|
||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
/// Processes the specification for a single logger.
|
/// Processes the specification for a single logger.
|
||||||
///
|
///
|
||||||
/// \param spec Logging specification for this logger
|
/// \param spec Logging specification for this logger
|
||||||
static void processSpecification(const LoggerSpecification& spec);
|
void processSpecification(const LoggerSpecification& spec);
|
||||||
|
|
||||||
/// \brief End Processing
|
/// \brief End Processing
|
||||||
///
|
///
|
||||||
@@ -94,6 +94,16 @@ public:
|
|||||||
int dbglevel = 0);
|
int dbglevel = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// @brief Decides what appender to create.
|
||||||
|
///
|
||||||
|
/// Delegates to the other functions that create appenders based on what's
|
||||||
|
/// in spec.
|
||||||
|
///
|
||||||
|
/// @param logger log4cplus logger to which the appender must be attached
|
||||||
|
/// @param spec the configured specification consisting of output options
|
||||||
|
static void appenderFactory(log4cplus::Logger& logger,
|
||||||
|
LoggerSpecification const& spec);
|
||||||
|
|
||||||
/// \brief Create console appender
|
/// \brief Create console appender
|
||||||
///
|
///
|
||||||
/// Creates an object that, when attached to a logger, will log to one
|
/// Creates an object that, when attached to a logger, will log to one
|
||||||
@@ -171,10 +181,14 @@ private:
|
|||||||
/// \c storeBufferAppenders(), and clears it
|
/// \c storeBufferAppenders(), and clears it
|
||||||
void flushBufferAppenders();
|
void flushBufferAppenders();
|
||||||
|
|
||||||
/// Only used between processInit() and processEnd(), to temporarily
|
/// @brief Only used between processInit() and processEnd(), to temporarily
|
||||||
/// store the buffer appenders in order to flush them after
|
/// store the buffer appenders in order to flush them after
|
||||||
/// processSpecification() calls have been completed
|
/// processSpecification() calls have been completed
|
||||||
std::vector<log4cplus::SharedAppenderPtr> buffer_appender_store_;
|
std::vector<log4cplus::SharedAppenderPtr> buffer_appender_store_;
|
||||||
|
|
||||||
|
/// @brief A hard copy of the specification for the root logger used for
|
||||||
|
/// inheritance by child loggers.
|
||||||
|
LoggerSpecification root_spec_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace log
|
} // namespace log
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2011-2021 Internet Systems Consortium, Inc. ("ISC")
|
// Copyright (C) 2011-2022 Internet Systems Consortium, Inc. ("ISC")
|
||||||
//
|
//
|
||||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
// 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
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <log/logger.h>
|
#include <log/logger.h>
|
||||||
#include <log/logger_level.h>
|
#include <log/logger_level.h>
|
||||||
#include <log/logger_manager.h>
|
#include <log/logger_manager.h>
|
||||||
|
#include <log/logger_name.h>
|
||||||
#include <log/logger_specification.h>
|
#include <log/logger_specification.h>
|
||||||
#include <log/message_initializer.h>
|
#include <log/message_initializer.h>
|
||||||
#include <log/output_option.h>
|
#include <log/output_option.h>
|
||||||
@@ -444,3 +445,67 @@ TEST_F(LoggerManagerTest, logDuplicatedMessages) {
|
|||||||
LoggerManager::logDuplicatedMessages();
|
LoggerManager::logDuplicatedMessages();
|
||||||
ASSERT_EQ(0, MessageInitializer::getDuplicates().size());
|
ASSERT_EQ(0, MessageInitializer::getDuplicates().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that output options can be inherited.
|
||||||
|
TEST_F(LoggerManagerTest, outputOptionsInheritance) {
|
||||||
|
LoggerManager manager;
|
||||||
|
SpecificationForFileLogger file_spec;
|
||||||
|
vector<LoggerSpecification> specs;
|
||||||
|
|
||||||
|
// Create the root logger configuration with a file output option.
|
||||||
|
string root_name(getRootLoggerName());
|
||||||
|
LoggerSpecification root_spec(root_name);
|
||||||
|
OutputOption root_option;
|
||||||
|
root_option.destination = OutputOption::DEST_FILE;
|
||||||
|
root_option.filename = file_spec.getFileName();
|
||||||
|
root_option.pattern = "%p %m\n";
|
||||||
|
root_spec.addOutputOption(root_option);
|
||||||
|
specs.push_back(root_spec);
|
||||||
|
|
||||||
|
// Create a child logger configuration without any output options.
|
||||||
|
// It should inherit the output option from the root logger.
|
||||||
|
string foo_name(root_name + ".foo");
|
||||||
|
LoggerSpecification foo_spec(foo_name);
|
||||||
|
specs.push_back(foo_spec);
|
||||||
|
|
||||||
|
// Create another child logger configuration with a console output option.
|
||||||
|
string bar_name(root_name + ".bar");
|
||||||
|
LoggerSpecification bar_spec(bar_name);
|
||||||
|
OutputOption bar_option;
|
||||||
|
bar_option.destination = OutputOption::DEST_CONSOLE;
|
||||||
|
bar_option.pattern = "%p %m\n";
|
||||||
|
bar_spec.addOutputOption(bar_option);
|
||||||
|
specs.push_back(bar_spec);
|
||||||
|
|
||||||
|
// Check the number of output options for each specification.
|
||||||
|
EXPECT_EQ(root_spec.optionCount(), 1);
|
||||||
|
EXPECT_EQ(foo_spec.optionCount(), 0);
|
||||||
|
EXPECT_EQ(bar_spec.optionCount(), 1);
|
||||||
|
|
||||||
|
// Process all the specifications.
|
||||||
|
manager.process(specs.begin(), specs.end());
|
||||||
|
|
||||||
|
// Log two messages each.
|
||||||
|
Logger root_logger(root_name.c_str());
|
||||||
|
Logger foo_logger(foo_name.c_str());
|
||||||
|
Logger bar_logger(bar_name.c_str());
|
||||||
|
LOG_INFO(root_logger, "from root logger 1");
|
||||||
|
LOG_INFO(foo_logger, "from foo logger 1");
|
||||||
|
LOG_INFO(bar_logger, "from bar logger 1");
|
||||||
|
LOG_INFO(root_logger, "from root logger 2");
|
||||||
|
LOG_INFO(foo_logger, "from foo logger 2");
|
||||||
|
LOG_INFO(bar_logger, "from bar logger 2");
|
||||||
|
|
||||||
|
// Check that root and foo were logged to file and that bar which
|
||||||
|
// had an explicit console configuration did not.
|
||||||
|
std::ifstream ifs(file_spec.getFileName());
|
||||||
|
std::stringstream s;
|
||||||
|
s << ifs.rdbuf();
|
||||||
|
std::string const result(s.str());
|
||||||
|
EXPECT_NE(result.find("INFO from root logger 1"), string::npos);
|
||||||
|
EXPECT_NE(result.find("INFO from foo logger 1"), string::npos);
|
||||||
|
EXPECT_EQ(result.find("INFO from bar logger 1"), string::npos);
|
||||||
|
EXPECT_NE(result.find("INFO from root logger 2"), string::npos);
|
||||||
|
EXPECT_NE(result.find("INFO from foo logger 2"), string::npos);
|
||||||
|
EXPECT_EQ(result.find("INFO from bar logger 2"), string::npos);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user