Commit d26a4945 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[3427] Changes after review:

 - Kea ARM updated
 - shell tests for Kea4,Kea6 and D2 are now passing
 - kea.conf updated with logging info
 - Various improvements in Daemon and LogConfigParser
 - DEFAULT_SYSLOG_NAME removed
 - Copyright years fixed
 - Couple additional tests written
parent 9c707375
......@@ -55,13 +55,14 @@
<title>name (string)</title>
<para>
Each logger in the system has a name, the name being that
of the component using it to log messages. For instance,
if you want to configure logging for the Dhcp4 module,
you add an entry for a logger named <quote>Dhcp4</quote>. This
configuration will then be used by the loggers in the
Dhcp4 module, and all the libraries used by it.
</para>
Each logger in the system has a name, the name being that
of the component using it to log messages. For instance,
if you want to configure logging for the Dhcp4 module,
you add an entry for a logger named <quote>Dhcp4</quote>. This
configuration will then be used by the loggers in the
Dhcp4 module, and all the libraries used by it (unless
a library defines its own logger).
</para>
<!-- TODO: later we will have a way to know names of all modules
......@@ -78,7 +79,6 @@ Right now you can only see what their names are if they are running
has the full name of <quote>Dhcp4.dhcpsrv</quote>. If
there is no entry in Logging for a particular library,
it will use the configuration given for the module.
</para>
<para>
......@@ -138,6 +138,24 @@ Right now you can only see what their names are if they are running
</para>
<para>
Currently defined loggers are:
</para>
<itemizedlist>
<listitem>
<simpara>kea.dhcp4</simpara>
</listitem>
<listitem>
<simpara>kea.dhcp6</simpara>
</listitem>
<listitem>
<simpara>kea-dhcp-ddns.dhcpddns</simpara>
</listitem>
<listitem>
<simpara>kea.dhcpsrv</simpara>
</listitem>
</itemizedlist>
</section>
<section>
......
......@@ -224,21 +224,9 @@ DControllerBase::configFromFile() {
// Temporary storage for logging configuration
isc::dhcp::ConfigurationPtr storage(new isc::dhcp::Configuration());
// Get 'Logging' element from the config
isc::data::ConstElementPtr logger = whole_config->get("Logging");
if (logger) {
// Configure logger first, so it can be applied to DHCPv6
// configuration. If we don't have a logger, just pass
// empty configuration.
Daemon::configureLogger(logger, storage);
} else {
// There was no Logging element defined in the config file.
// Let's pass an empty pointer that will remove any current
// configuration.
Daemon::configureLogger(isc::data::ConstElementPtr(),
storage);
}
// Get 'Logging' element from the config and use it to set up
// logging. If there's no such element, we'll just pass NULL.
Daemon::configureLogger(whole_config->get("Logging"), storage, verbose_);
// Extract derivation-specific portion of the configuration.
module_config = whole_config->get(getAppName());
......
......@@ -25,6 +25,20 @@ CONFIG="{
\"tsig_keys\": [],
\"forward_ddns\" : {},
\"reverse_ddns\" : {}
},
\"Logging\":
{
\"loggers\": [
{
\"name\": \"kea-dhcp-ddns\",
\"output_options\": [
{
\"output\": \"$LOG_FILE\"
}
],
\"severity\": \"DEBUG\"
}
]
}
}"
......@@ -38,6 +52,20 @@ CONFIG_INVALID="{
\"tsig_keys\": [],
\"forward_ddns\" : {},
\"reverse_ddns\" : {}
},
\"Logging\":
{
\"loggers\": [
{
\"name\": \"kea-dhcp-ddns\",
\"output_options\": [
{
\"output\": \"$LOG_FILE\"
}
],
\"severity\": \"INFO\"
}
]
}
}"
......
......@@ -66,20 +66,12 @@ void configure(const std::string& file_name) {
// Let's configure logging before applying the configuration,
// so we can log things during configuration process.
logger = json->get("Logging");
if (logger) {
// Configure logger first, so it can be applied to DHCPv6
// configuration. If we don't have a logger, just pass
// empty configuration.
Daemon::configureLogger(logger, CfgMgr::instance().getConfiguration());
} else {
// There was no Logging element defined in the config file.
// Let's pass an empty pointer that will remove any current
// configuration.
Daemon::configureLogger(isc::data::ConstElementPtr(),
CfgMgr::instance().getConfiguration());
}
// If there's no logging element, we'll just pass NULL pointer,
// which will be handled by configureLogger().
Daemon::configureLogger(json->get("Logging"),
CfgMgr::instance().getConfiguration(),
ControlledDhcpv4Srv::getInstance()->getVerbose());
// Get Dhcp4 component from the config
dhcp4 = json->get("Dhcp4");
......
......@@ -111,6 +111,9 @@ main(int argc, char* argv[]) {
// Create the server instance.
ControlledDhcpv4Srv server(port_number);
// Remember verbose-mode
server.setVerbose(verbose_mode);
try {
// Initialize the server.
server.init(config_file);
......
......@@ -34,6 +34,21 @@ CONFIG="{
\"subnet\": \"10.0.0.0/8\",
\"pool\": [ \"10.0.0.10-10.0.0.100\" ]
} ]
},
\"Logging\":
{
\"loggers\": [
{
\"name\": \"kea\",
\"output_options\": [
{
\"output\": \"$LOG_FILE\"
}
],
\"severity\": \"INFO\"
}
]
}
}"
# Invalid configuration (negative valid-lifetime) to check that Kea
......@@ -55,6 +70,21 @@ CONFIG_INVALID="{
\"subnet\": \"10.0.0.0/8\",
\"pool\": [ \"10.0.0.10-10.0.0.100\" ]
} ]
},
\"Logging\":
{
\"loggers\": [
{
\"name\": \"kea\",
\"output_options\": [
{
\"output\": \"$LOG_FILE\"
}
],
\"severity\": \"INFO\"
}
]
}
}"
......
......@@ -70,19 +70,11 @@ void configure(const std::string& file_name) {
// Let's configure logging before applying the configuration,
// so we can log things during configuration process.
logger = json->get("Logging");
if (logger) {
// Configure logger first, so it can be applied to DHCPv6
// configuration. If we don't have a logger, just pass
// empty configuration.
Daemon::configureLogger(logger, CfgMgr::instance().getConfiguration());
} else {
// There was no Logging element defined in the config file.
// Let's pass an empty pointer that will remove any current
// configuration.
Daemon::configureLogger(isc::data::ConstElementPtr(),
CfgMgr::instance().getConfiguration());
}
// If there's no logging element, we'll just pass NULL pointer,
// which will be handled by configureLogger().
Daemon::configureLogger(json->get("Logging"),
CfgMgr::instance().getConfiguration(),
ControlledDhcpv6Srv::getInstance()->getVerbose());
// Get Dhcp6 component from the config
dhcp6 = json->get("Dhcp6");
......
......@@ -111,6 +111,9 @@ main(int argc, char* argv[]) {
// Create the server instance.
ControlledDhcpv6Srv server(port_number);
// Remember verbose-mode
server.setVerbose(verbose_mode);
try {
// Initialize the server, i.e. establish control session
// if BIND10 backend is used or read a configuration file
......
......@@ -35,6 +35,21 @@ CONFIG="{
\"subnet\": \"2001:db8:1::/64\",
\"pool\": [ \"2001:db8:1::10-2001:db8:1::100\" ]
} ]
},
\"Logging\":
{
\"loggers\": [
{
\"name\": \"kea\",
\"output_options\": [
{
\"output\": \"$LOG_FILE\"
}
],
\"severity\": \"INFO\"
}
]
}
}"
# Invalid configuration (negative preferred-lifetime) to check that Kea
......@@ -57,6 +72,21 @@ CONFIG_INVALID="{
\"subnet\": \"2001:db8:1::/64\",
\"pool\": [ \"2001:db8:1::10-2001:db8:1::100\" ]
} ]
},
\"Logging\":
{
\"loggers\": [
{
\"name\": \"kea\",
\"output_options\": [
{
\"output\": \"$LOG_FILE\"
}
],
\"severity\": \"INFO\"
}
]
}
}"
......
......@@ -65,6 +65,25 @@
"tsig_keys": [],
"forward_ddns" : {},
"reverse_ddns" : {}
},
# Logging configuration starts here. It tells Kea servers to store
# all log messages (on severity INFO or more) in a file.
# debuglevel variable is used on DEBUG level only.
"Logging":
{
"loggers": [
{
"name": "kea",
"output_options": [
{
"output": "@localstatedir@/log/kea.log"
}
],
"severity": "INFO",
"debuglevel": 0
}
]
}
}
......@@ -12,8 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef DHCPSRV_CONFIG_H
#define DHCPSRV_CONFIG_H
#ifndef DHCPSRV_CONFIGURATION_H
#define DHCPSRV_CONFIGURATION_H
#include <log/logger_level.h>
#include <boost/shared_ptr.hpp>
......@@ -23,7 +23,6 @@
namespace isc {
namespace dhcp {
/// @brief Defines single logging destination
///
/// This structure is used to keep log4cplus configuration parameters.
......@@ -93,4 +92,4 @@ typedef boost::shared_ptr<Configuration> ConfigurationPtr;
} // namespace isc::dhcp
} // namespace isc
#endif
#endif // DHCPSRV_CONFIGURATION_H
......@@ -31,7 +31,7 @@ namespace dhcp {
std::string Daemon::config_file_ = "";
Daemon::Daemon()
: signal_set_(), signal_handler_() {
: signal_set_(), signal_handler_(), verbose_(false) {
}
Daemon::~Daemon() {
......@@ -55,8 +55,9 @@ void Daemon::handleSignal() {
}
}
void Daemon::configureLogger(isc::data::ConstElementPtr log_config,
const ConfigurationPtr& storage) {
void Daemon::configureLogger(const isc::data::ConstElementPtr& log_config,
const ConfigurationPtr& storage,
bool verbose) {
// This is utility class that translates JSON structures into formats
// understandable by log4cplus.
......@@ -66,7 +67,7 @@ void Daemon::configureLogger(isc::data::ConstElementPtr log_config,
// There was no logger configuration. Let's clear any config
// and revert to the default.
parser.defaultLogging(); // Set up default logging
parser.applyDefaultConfiguration(verbose); // Set up default logging
return;
}
......@@ -77,12 +78,12 @@ void Daemon::configureLogger(isc::data::ConstElementPtr log_config,
// array in it. Let's clear any old logging configuration
// we may have and revert to the default.
parser.defaultLogging(); // Set up default logging
parser.applyDefaultConfiguration(verbose); // Set up default logging
return;
}
// Translate JSON structures into log4cplus formats
parser.parseConfiguration(loggers);
parser.parseConfiguration(loggers, verbose);
// Apply the configuration
......
......@@ -128,8 +128,26 @@ public:
///
/// @param log_config JSON structures that describe logging
/// @param storage configuration will be stored here
static void configureLogger(isc::data::ConstElementPtr log_config,
const isc::dhcp::ConfigurationPtr& storage);
/// @param verbose specifies if verbose mode should be enabled
static void configureLogger(const isc::data::ConstElementPtr& log_config,
const isc::dhcp::ConfigurationPtr& storage,
bool verbose);
/// @brief Sets or clears verbose mode
///
/// Verbose mode (-v in command-line) triggers loggers to log everythin
/// (sets severity to DEBUG and debuglevel to 99). Values specified in the
/// config file are ignored.
void setVerbose(bool verbose) {
verbose_ = verbose;
}
/// @brief Returns if running in verbose mode
///
/// @return verbose mode
bool getVerbose() {
return (verbose_);
}
protected:
......@@ -163,6 +181,9 @@ private:
/// @brief Config file name or empty if config file not used.
static std::string config_file_;
/// @brief Verbose mode
bool verbose_;
};
}; // end of isc::dhcp namespace
......
......@@ -18,6 +18,7 @@
#include <boost/lexical_cast.hpp>
#include <log/logger_specification.h>
#include <log/logger_manager.h>
#include <log/logger_name.h>
using namespace isc::data;
using namespace isc::log;
......@@ -25,17 +26,17 @@ using namespace isc::log;
namespace isc {
namespace dhcp {
static const char* DEFAULT_SYSLOG_NAME = "kea";
LogConfigParser::LogConfigParser(const ConfigurationPtr& storage)
:config_(storage) {
:config_(storage), verbose_(false) {
if (!storage) {
isc_throw(InvalidOperation, "LogConfigParser needs a pointer to the "
isc_throw(BadValue, "LogConfigParser needs a pointer to the "
"configuration, so parsed data can be stored there");
}
}
void LogConfigParser::parseConfiguration(isc::data::ConstElementPtr loggers) {
void LogConfigParser::parseConfiguration(isc::data::ConstElementPtr loggers,
bool verbose) {
verbose_ = verbose;
// Iterate over all entries in "Logging/loggers" list
BOOST_FOREACH(ConstElementPtr logger, loggers->listValue()) {
......@@ -72,9 +73,9 @@ void LogConfigParser::parseConfigEntry(isc::data::ConstElementPtr entry) {
try {
info.severity_ = isc::log::getSeverity(severity_ptr->stringValue().c_str());
} catch (const std::exception& ex) {
isc_throw(BadValue, "Unable to convert '" << severity_ptr->stringValue()
<< "' into allowed severity (" << severity_ptr->getPosition()
<< ")");
isc_throw(BadValue, "Unsupported severity value '"
<< severity_ptr->stringValue() << "' ("
<< severity_ptr->getPosition() << ")");
}
// Get debug logging level
......@@ -91,12 +92,21 @@ void LogConfigParser::parseConfigEntry(isc::data::ConstElementPtr entry) {
isc_throw(BadValue, "");
}
} catch (...) {
isc_throw(BadValue, "Unable to convert '" << debuglevel_ptr->stringValue()
<< "' into allowed debuglevel range (0-99) ("
isc_throw(BadValue, "Unsupported debuglevel value '"
<< debuglevel_ptr->stringValue()
<< "', expected 0-99 ("
<< debuglevel_ptr->getPosition() << ")");
}
}
// We want to follow the normal path, so it could catch parsing errors even
// when verbose mode is enabled. If it is, just override whatever was parsed
// in the config file.
if (verbose_) {
info.severity_ = isc::log::DEBUG;
info.debuglevel_ = 99;
}
isc::data::ConstElementPtr output_options = entry->get("output_options");
if (output_options) {
......@@ -138,8 +148,6 @@ void LogConfigParser::parseOutputOptions(std::vector<LoggingDestination>& destin
void LogConfigParser::applyConfiguration() {
// Constants: not declared static as this is function is expected to be
// called once only
static const std::string STDOUT = "stdout";
static const std::string STDERR = "stderr";
static const std::string SYSLOG = "syslog";
......@@ -180,8 +188,8 @@ void LogConfigParser::applyConfiguration() {
// Must take account of the string actually being "syslog:"
if (dest->output_ == SYSLOG_COLON) {
// The expected syntax is syslog:facility. User skipped
// the logging name, so we'll just use DEFAULT_SYSLOG_NAME.
option.facility = DEFAULT_SYSLOG_NAME;
// the logging name, so we'll just use the default ("kea")
option.facility = isc::log::getDefaultRootLoggerName();
} else {
// Everything else in the string is the facility name
......@@ -203,8 +211,9 @@ void LogConfigParser::applyConfiguration() {
}
}
void LogConfigParser::defaultLogging() {
LoggerSpecification spec("kea", isc::log::INFO, 0);
void LogConfigParser::applyDefaultConfiguration(bool verbose) {
LoggerSpecification spec("kea", (verbose?isc::log::DEBUG : isc::log::INFO),
(verbose?99:0));
OutputOption option;
option.destination = OutputOption::DEST_CONSOLE;
......
......@@ -17,18 +17,34 @@
#include <cc/data.h>
#include <dhcpsrv/configuration.h>
#include <dhcpsrv/cfgmgr.h>
#include <stdint.h>
#include <vector>
namespace isc {
namespace dhcp {
/// @brief Interprets JSON structures and translates them to log4cplus
/// @brief Configures log4cplus by translating Kea configuration structures
///
/// This parser iterates over provided JSON structures and translates them
/// This parser iterates over provided data elements and translates them
/// into values applicable to log4cplus.
///
/// The data structures converted to JSON format have the following syntax:
/// {
/// "name": "kea",
/// "output_options": [
/// {
/// "output": "/home/thomson/kea-inst/kea-warn.log",
/// "maxver": 8,
/// "maxsize": 204800
/// }
/// ],
/// "severity": "WARN"
/// }
///
/// This is only an example and actual values may be different.
///
/// The data structures don't have to originate from JSON. JSON is just a
/// convenient presentation syntax.
///
/// This class uses Configuration structure to store logging configuration.
class LogConfigParser {
public:
......@@ -44,37 +60,39 @@ public:
/// parsed information in config_->logging_info_.
///
/// @param log_config JSON structures to be parsed (loggers list)
void parseConfiguration(isc::data::ConstElementPtr log_config);
/// @param verbose specifies verbose mode (true forces DEBUG, debuglevel = 99)
void parseConfiguration(isc::data::ConstElementPtr log_config,
bool verbose = false);
/// @brief Applies stored configuration
void applyConfiguration();
/// @brief Configures default logging
static void defaultLogging();
///
/// This method is static,
///
/// @param verbose specifies verbose mode (true forces DEBUG, debuglevel = 99)
void applyDefaultConfiguration(bool verbose = false);
protected:
private:
/// @brief Parses one JSON structure in Logging/loggers" array
///
/// The structure has the following syntax:
/// {
/// "name": "*",
/// "output_options": [
/// {
/// "output": "/home/thomson/kea-inst/kea-warn.log",
/// "maxver": 8,
/// "maxsize": 204800
/// }
/// ],
/// "severity": "WARN"
/// }
///
/// @param entry JSON structure to be parsed
/// @brief parses one structure in Logging/loggers.
void parseConfigEntry(isc::data::ConstElementPtr entry);
/// @brief Parses output_options structure
///
/// An example data structure that holds output_options in JSON format
/// looks like this:
/// "output_options": [
/// {
/// "output": "/var/log/kea-warn.log",
/// "maxver": 8,
/// "maxsize": 204800
/// }
/// ],
/// @param destination parsed parameters will be stored here
/// @param output_options element to be parsed
void parseOutputOptions(std::vector<LoggingDestination>& destination,
......@@ -84,9 +102,15 @@ protected:
///
/// LogConfigParser class uses only config_->logging_info_ field.
ConfigurationPtr config_;
/// @brief Verbose mode
///
/// When verbose mode is enabled, logging severity is overridden to DEBUG,
/// and debuglevel is always 99.
bool verbose_;
};
} // namespace isc::dhcp
} // namespace isc
#endif // CFGMGR_H
#endif // DHCPSRV_LOGGING_H
......@@ -778,4 +778,4 @@ typedef std::vector<Subnet6Ptr> Subnet6Collection;
} // end of isc::dhcp namespace