Parcourir la source

[3427] Logging configuration implemented.

Tomek Mrugalski il y a 11 ans
Parent
commit
4af6fc124b

+ 23 - 0
src/bin/d2/d_controller.cc

@@ -18,6 +18,7 @@
 #include <d2/d_controller.h>
 #include <d2/d_controller.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 #include <log/logger_support.h>
 #include <log/logger_support.h>
+#include <dhcpsrv/configuration.h>
 
 
 #include <sstream>
 #include <sstream>
 
 
@@ -217,6 +218,28 @@ DControllerBase::configFromFile() {
         isc::data::ConstElementPtr whole_config =
         isc::data::ConstElementPtr whole_config =
             isc::data::Element::fromJSONFile(config_file, true);
             isc::data::Element::fromJSONFile(config_file, true);
 
 
+        // Let's configure logging before applying the configuration,
+        // so we can log things during configuration process.
+
+        // 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);
+        }
+
         // Extract derivation-specific portion of the configuration.
         // Extract derivation-specific portion of the configuration.
         module_config = whole_config->get(getAppName());
         module_config = whole_config->get(getAppName());
         if (!module_config) {
         if (!module_config) {

+ 19 - 0
src/bin/dhcp4/kea_controller.cc

@@ -17,6 +17,7 @@
 #include <dhcp4/json_config_parser.h>
 #include <dhcp4/json_config_parser.h>
 #include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp4/dhcp4_log.h>
+#include <dhcpsrv/cfgmgr.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 
 
 #include <string>
 #include <string>
@@ -42,6 +43,7 @@ void configure(const std::string& file_name) {
 
 
     isc::data::ConstElementPtr json;
     isc::data::ConstElementPtr json;
     isc::data::ConstElementPtr dhcp4;
     isc::data::ConstElementPtr dhcp4;
+    isc::data::ConstElementPtr logger;
     isc::data::ConstElementPtr result;
     isc::data::ConstElementPtr result;
 
 
     // Basic sanity check: file name must not be empty.
     // Basic sanity check: file name must not be empty.
@@ -62,6 +64,23 @@ void configure(const std::string& file_name) {
                       " file: " << file_name);
                       " file: " << 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());
+        }
+
         // Get Dhcp4 component from the config
         // Get Dhcp4 component from the config
         dhcp4 = json->get("Dhcp4");
         dhcp4 = json->get("Dhcp4");
 
 

+ 17 - 0
src/bin/dhcp6/kea_controller.cc

@@ -47,6 +47,7 @@ void configure(const std::string& file_name) {
 
 
     isc::data::ConstElementPtr json;
     isc::data::ConstElementPtr json;
     isc::data::ConstElementPtr dhcp6;
     isc::data::ConstElementPtr dhcp6;
+    isc::data::ConstElementPtr logger;
     isc::data::ConstElementPtr result;
     isc::data::ConstElementPtr result;
 
 
     // Basic sanity check: file name must not be empty.
     // Basic sanity check: file name must not be empty.
@@ -67,6 +68,22 @@ void configure(const std::string& file_name) {
                       + file_name);
                       + 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());
+        }
+
         // Get Dhcp6 component from the config
         // Get Dhcp6 component from the config
         dhcp6 = json->get("Dhcp6");
         dhcp6 = json->get("Dhcp6");
 
 

+ 2 - 0
src/lib/dhcpsrv/Makefile.am

@@ -59,6 +59,8 @@ libkea_dhcpsrv_la_SOURCES += key_from_key.h
 libkea_dhcpsrv_la_SOURCES += lease.cc lease.h
 libkea_dhcpsrv_la_SOURCES += lease.cc lease.h
 libkea_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
 libkea_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
 libkea_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
 libkea_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
+libkea_dhcpsrv_la_SOURCES += logging.cc logging.h
+libkea_dhcpsrv_la_SOURCES += configuration.h
 libkea_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h
 libkea_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h
 
 
 if HAVE_MYSQL
 if HAVE_MYSQL

+ 6 - 1
src/lib/dhcpsrv/cfgmgr.cc

@@ -437,10 +437,15 @@ CfgMgr::getD2ClientMgr() {
     return (d2_client_mgr_);
     return (d2_client_mgr_);
 }
 }
 
 
+ConfigurationPtr
+CfgMgr::getConfiguration() {
+    return (configuration_);
+}
+
 CfgMgr::CfgMgr()
 CfgMgr::CfgMgr()
     : datadir_(DHCP_DATA_DIR),
     : datadir_(DHCP_DATA_DIR),
       all_ifaces_active_(false), echo_v4_client_id_(true),
       all_ifaces_active_(false), echo_v4_client_id_(true),
-      d2_client_mgr_() {
+      d2_client_mgr_(), configuration_(new Configuration()) {
     // DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
     // DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
     // Note: the definition of DHCP_DATA_DIR needs to include quotation marks
     // Note: the definition of DHCP_DATA_DIR needs to include quotation marks
     // See AM_CPPFLAGS definition in Makefile.am
     // See AM_CPPFLAGS definition in Makefile.am

+ 15 - 0
src/lib/dhcpsrv/cfgmgr.h

@@ -24,6 +24,7 @@
 #include <dhcpsrv/option_space_container.h>
 #include <dhcpsrv/option_space_container.h>
 #include <dhcpsrv/pool.h>
 #include <dhcpsrv/pool.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/subnet.h>
+#include <dhcpsrv/configuration.h>
 #include <util/buffer.h>
 #include <util/buffer.h>
 
 
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
@@ -420,6 +421,12 @@ public:
     /// @return a reference to the DHCP-DDNS manager.
     /// @return a reference to the DHCP-DDNS manager.
     D2ClientMgr& getD2ClientMgr();
     D2ClientMgr& getD2ClientMgr();
 
 
+
+    /// @brief Returns the current configuration.
+    ///
+    /// @return a pointer to the current configuration.
+    ConfigurationPtr getConfiguration();
+
 protected:
 protected:
 
 
     /// @brief Protected constructor.
     /// @brief Protected constructor.
@@ -516,6 +523,14 @@ private:
 
 
     /// @brief Manages the DHCP-DDNS client and its configuration.
     /// @brief Manages the DHCP-DDNS client and its configuration.
     D2ClientMgr d2_client_mgr_;
     D2ClientMgr d2_client_mgr_;
+
+    /// @brief Configuration
+    ///
+    /// This is a structure that will hold all configuration.
+    /// @todo: migrate all other parameters to that structure.
+    /// @todo: maybe this should be a vector<Configuration>, so we could keep
+    ///        previous configurations and do a rollback if needed?
+    ConfigurationPtr configuration_;
 };
 };
 
 
 } // namespace isc::dhcp
 } // namespace isc::dhcp

+ 94 - 0
src/lib/dhcpsrv/configuration.h

@@ -0,0 +1,94 @@
+// Copyright (C) 2014 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 DHCPSRV_CONFIG_H
+#define DHCPSRV_CONFIG_H
+
+#include <log/logger_level.h>
+#include <boost/shared_ptr.hpp>
+
+namespace isc {
+namespace dhcp {
+
+
+/// @brief Defines single logging destination
+///
+/// This structure is used to keep log4cplus configuration parameters.
+struct LoggingDestination {
+
+    /// @brief defines logging destination output
+    ///
+    /// Values accepted are: stdout, stderr, syslog, syslog:name.
+    /// Any other destination will be considered a file name.
+    std::string output_;
+    
+    /// @brief Maximum number of log files in rotation
+    int maxver_;
+
+    /// @brief Maximum log file size
+    uint64_t maxsize_;
+};
+
+/// @brief structure that describes one logging entry
+///
+/// This is a structure that conveys one logger entry configuration.
+/// The structure in JSON form has the following syntax:
+///        {
+///            "name": "*",
+///            "output_options": [
+///                {
+///                    "output": "/path/to/the/logfile.log",
+///                    "maxver": 8,
+///                    "maxsize": 204800
+///                }
+///            ], 
+///            "severity": "WARN",
+///            "debuglevel": 99
+///        }, 
+struct LoggingInfo {
+
+    /// @brief logging name
+    std::string name_;
+
+    /// @brief describes logging severity
+    isc::log::Severity severity_;
+
+    /// @brief debuglevel (used when severity_ == DEBUG)
+    ///
+    /// We use range 0(least verbose)..99(most verbose)
+    int debuglevel_;
+
+    /// @brief specific logging destinations
+    std::vector<LoggingDestination> destinations_;
+};
+
+/// @brief storage for logging information in log4cplus format
+typedef std::vector<isc::dhcp::LoggingInfo> LoggingInfoStorage;
+
+/// @brief Specifies current DHCP configuration
+///
+/// @todo Migrate all other configuration parameters from cfgmgr.h here
+struct Configuration {
+
+    /// @brief logging specific information
+    LoggingInfoStorage logging_info_;
+};
+
+/// @brief pointer to the configuration
+typedef boost::shared_ptr<Configuration> ConfigurationPtr;
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif

+ 38 - 1
src/lib/dhcpsrv/daemon.cc

@@ -15,11 +15,13 @@
 #include <config.h>
 #include <config.h>
 #include <dhcpsrv/daemon.h>
 #include <dhcpsrv/daemon.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
+#include <cc/data.h>
 #include <boost/bind.hpp>
 #include <boost/bind.hpp>
+#include <logging.h>
 #include <errno.h>
 #include <errno.h>
 
 
 /// @brief provides default implementation for basic daemon operations
 /// @brief provides default implementation for basic daemon operations
-/// 
+///
 /// This file provides stub implementations that are expected to be redefined
 /// This file provides stub implementations that are expected to be redefined
 /// in derived classes (e.g. ControlledDhcpv6Srv)
 /// in derived classes (e.g. ControlledDhcpv6Srv)
 namespace isc {
 namespace isc {
@@ -53,6 +55,41 @@ void Daemon::handleSignal() {
     }
     }
 }
 }
 
 
+void Daemon::configureLogger(isc::data::ConstElementPtr log_config,
+                             const ConfigurationPtr& storage) {
+
+    // This is utility class that translates JSON structures into formats
+    // understandable by log4cplus.
+    LogConfigParser parser(storage);
+
+    if (!log_config) {
+        // There was no logger configuration. Let's clear any config
+        // and revert to the default.
+
+        parser.defaultLogging(); // Set up default logging
+        return;
+    }
+
+    isc::data::ConstElementPtr loggers;
+    loggers = log_config->get("loggers");
+    if (!loggers) {
+        // There is Logging structure, but it doesn't have loggers
+        // array in it. Let's clear any old logging configuration
+        // we may have and revert to the default.
+
+        parser.defaultLogging(); // Set up default logging
+        return;
+    }
+
+    // Translate JSON structures into log4cplus formats
+    parser.parseConfiguration(loggers);
+
+    // Apply the configuration
+
+    /// @todo: Once configuration unrolling is implemented,
+    /// this call will be moved to a separate method.
+    parser.applyConfiguration();
+}
 
 
 };
 };
 };
 };

+ 21 - 2
src/lib/dhcpsrv/daemon.h

@@ -12,12 +12,16 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#ifndef DAEMON_H
+#define DAEMON_H
+
 #include <config.h>
 #include <config.h>
+#include <cc/data.h>
+#include <dhcpsrv/configuration.h>
 #include <util/signal_set.h>
 #include <util/signal_set.h>
 #include <boost/noncopyable.hpp>
 #include <boost/noncopyable.hpp>
 #include <string>
 #include <string>
 
 
-
 namespace isc {
 namespace isc {
 namespace dhcp {
 namespace dhcp {
 
 
@@ -105,7 +109,7 @@ public:
         return (config_file_);
         return (config_file_);
     }
     }
 
 
-    /// Initializes logger
+    /// @brief Initializes logger
     ///
     ///
     /// This method initializes logger. Currently its implementation is specific
     /// This method initializes logger. Currently its implementation is specific
     /// to each configuration backend.
     /// to each configuration backend.
@@ -114,6 +118,19 @@ public:
     /// @param verbose verbose mode (true usually enables DEBUG messages)
     /// @param verbose verbose mode (true usually enables DEBUG messages)
     static void loggerInit(const char* log_name, bool verbose);
     static void loggerInit(const char* log_name, bool verbose);
 
 
+    /// @brief Configures logger
+    ///
+    /// Applies configuration stored in "Logging" structure in the
+    /// configuration file. This structure has a "loggers" array that
+    /// contains 0 or more entries, each configuring one logging source
+    /// (name, severity, debuglevel), each with zero or more outputs (file,
+    /// maxsize, maximum number of files).
+    ///
+    /// @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);
+
 protected:
 protected:
 
 
     /// @brief Invokes handler for the next received signal.
     /// @brief Invokes handler for the next received signal.
@@ -150,3 +167,5 @@ private:
 
 
 }; // end of isc::dhcp namespace
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
 }; // end of isc namespace
+
+#endif

+ 220 - 0
src/lib/dhcpsrv/logging.cc

@@ -0,0 +1,220 @@
+// Copyright (C) 2014 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 <cc/data.h>
+#include <dhcpsrv/logging.h>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <log/logger_specification.h>
+#include <log/logger_manager.h>
+
+using namespace isc::data;
+using namespace isc::log;
+
+namespace isc {
+namespace dhcp {
+
+static const char* DEFAULT_SYSLOG_NAME = "kea";
+
+LogConfigParser::LogConfigParser(const ConfigurationPtr& storage)
+    :config_(storage) {
+    if (!storage) {
+        isc_throw(InvalidOperation, "LogConfigParser needs a pointer to the "
+                  "configuration, so parsed data can be stored there");
+    }
+}
+
+void LogConfigParser::parseConfiguration(isc::data::ConstElementPtr loggers) {
+
+    // Iterate over all entries in "Logging/loggers" list
+    BOOST_FOREACH(ConstElementPtr logger, loggers->listValue()) {
+        parseConfigEntry(logger);
+    }
+}
+
+void LogConfigParser::parseConfigEntry(isc::data::ConstElementPtr entry) {
+    if (!entry) {
+        // This should not happen, but let's be on the safe side and check
+        return;
+    }
+
+    if (!config_) {
+        isc_throw(BadValue, "configuration storage not set, can't parse logger config.");
+    }
+
+    LoggingInfo info;
+
+    // Get a name
+    isc::data::ConstElementPtr name_ptr = entry->get("name");
+    if (!name_ptr) {
+        isc_throw(BadValue, "loggers entry does not have a mandatory 'name' "
+                  "element (" << entry->getPosition() << ")");
+    }
+    info.name_ = name_ptr->stringValue();
+
+    // Get severity
+    isc::data::ConstElementPtr severity_ptr = entry->get("severity");
+    if (!name_ptr) {
+        isc_throw(BadValue, "loggers entry does not have a mandatory "
+                  "'severity' element (" << entry->getPosition() << ")");
+    }
+    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()
+                  << ")");
+    }
+
+    // Get debug logging level
+    info.debuglevel_ = 0;
+    isc::data::ConstElementPtr debuglevel_ptr = entry->get("debuglevel");
+
+    // It's ok to not have debuglevel, we'll just assume its least verbose
+    // (0) level.
+    if (debuglevel_ptr) {
+        try {
+            info.debuglevel_ = boost::lexical_cast<int>(debuglevel_ptr->str());
+            if ( (info.debuglevel_ < 0) || (info.debuglevel_ > 99) ) {
+                // Comment doesn't matter, it is caught several lines below
+                isc_throw(BadValue, "");
+            }
+        } catch (...) {
+            isc_throw(BadValue, "Unable to convert '" << debuglevel_ptr->stringValue()
+                      << "' into allowed debuglevel range (0-99) ("
+                      << debuglevel_ptr->getPosition() << ")");
+        }
+    }
+
+    isc::data::ConstElementPtr output_options = entry->get("output_options");
+
+    if (output_options) {
+        parseOutputOptions(info.destinations_, output_options);
+    }
+    
+    config_->logging_info_.push_back(info);
+}
+
+void LogConfigParser::parseOutputOptions(std::vector<LoggingDestination>& destination,
+                                         isc::data::ConstElementPtr output_options) {
+    if (!output_options) {
+        isc_throw(BadValue, "Missing 'output_options' structure in 'loggers'");
+    }
+    BOOST_FOREACH(ConstElementPtr output_option, output_options->listValue()) {
+
+        LoggingDestination dest;
+
+        isc::data::ConstElementPtr output = output_option->get("output");
+        if (!output) {
+            isc_throw(BadValue, "output_options entry does not have a mandatory 'output' "
+                      "element (" << output_option->getPosition() << ")");
+        }
+        dest.output_ = output->stringValue();
+
+        isc::data::ConstElementPtr maxver_ptr = output_option->get("maxver");
+        if (maxver_ptr) {
+            dest.maxver_ = boost::lexical_cast<int>(maxver_ptr->str());
+        }
+
+        isc::data::ConstElementPtr maxsize_ptr = output_option->get("maxsize");
+        if (maxsize_ptr) {
+            dest.maxsize_ = boost::lexical_cast<uint64_t>(maxsize_ptr->str());
+        }
+
+        destination.push_back(dest);
+    }
+}
+
+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";
+    static const std::string SYSLOG_COLON = "syslog:";
+
+    // Set locking directory to /tmp
+    setenv("B10_LOCKFILE_DIR_FROM_BUILD", "/tmp", 1);
+
+    // Now iterate through all specified loggers
+    for (LoggingInfoStorage::const_iterator it = config_->logging_info_.begin();
+         it != config_->logging_info_.end(); ++it) {
+
+        // Prepare the objects to define the logging specification
+        LoggerSpecification spec(it->name_,
+                                 it->severity_,
+                                 it->debuglevel_);
+        OutputOption option;
+
+        for (std::vector<LoggingDestination>::const_iterator dest = it->destinations_.begin();
+             dest != it->destinations_.end(); ++dest) {
+            
+            // Set up output option according to destination specification
+            if (dest->output_ == STDOUT) {
+                option.destination = OutputOption::DEST_CONSOLE;
+                option.stream = OutputOption::STR_STDOUT;
+
+            } else if (dest->output_ == STDERR) {
+                option.destination = OutputOption::DEST_CONSOLE;
+                option.stream = OutputOption::STR_STDERR;
+
+            } else if (dest->output_ == SYSLOG) {
+                option.destination = OutputOption::DEST_SYSLOG;
+                // Use default specified in OutputOption constructor for the
+                // syslog destination
+
+            } else if (dest->output_.find(SYSLOG_COLON) == 0) {
+                option.destination = OutputOption::DEST_SYSLOG;
+                // 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;
+                    
+                } else {
+                    // Everything else in the string is the facility name
+                    option.facility = dest->output_.substr(SYSLOG_COLON.size());
+                }
+
+            } else {
+                // Not a recognised destination, assume a file.
+                option.destination = OutputOption::DEST_FILE;
+                option.filename = dest->output_;
+            }
+
+            // ... and set the destination
+            spec.addOutputOption(option);
+        }
+
+        LoggerManager manager;
+        manager.process(spec);
+    }
+}
+
+void LogConfigParser::defaultLogging() {
+    LoggerSpecification spec("kea", isc::log::INFO, 0);
+
+    OutputOption option;
+    option.destination = OutputOption::DEST_CONSOLE;
+    option.stream = OutputOption::STR_STDOUT;
+
+    spec.addOutputOption(option);
+
+    LoggerManager manager;
+    manager.process(spec);
+}
+
+} // namespace isc::dhcp
+} // namespace isc

+ 92 - 0
src/lib/dhcpsrv/logging.h

@@ -0,0 +1,92 @@
+// Copyright (C) 2014 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 DHCPSRV_LOGGING_H
+#define DHCPSRV_LOGGING_H
+
+#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
+///
+/// This parser iterates over provided JSON structures and translates them
+/// into values applicable to log4cplus.
+///
+/// This class uses Configuration structure to store logging configuration.
+class LogConfigParser {
+public:
+
+    /// @brief Constructor
+    ///
+    /// @param storage parsed logging configuration will be stored here
+    LogConfigParser(const ConfigurationPtr& storage);
+
+    /// @brief Parses specified configuration
+    ///
+    /// Walks over specified logging configuration JSON structures and store
+    /// parsed information in config_->logging_info_.
+    ///
+    /// @param log_config JSON structures to be parsed
+    void parseConfiguration(isc::data::ConstElementPtr log_config);
+
+    /// @brief Applies stored configuration
+    void applyConfiguration();
+
+    /// @brief Configures default logging
+    static void defaultLogging();
+
+protected:
+
+    /// @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
+    ///
+    /// @param destination parsed parameters will be stored here
+    /// @param output_options element to be parsed
+    void parseOutputOptions(std::vector<LoggingDestination>& destination,
+                            isc::data::ConstElementPtr output_options);
+
+    /// @brief Configuration is stored here
+    ///
+    /// LogConfigParser class uses only config_->logging_info_ field.
+    ConfigurationPtr config_;
+};
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif // CFGMGR_H