Commit 7b148c2d authored by Marcin Siodelski's avatar Marcin Siodelski

[master] Merge branch 'trac3806'

# Conflicts:
#	doc/guide/logging.xml
parents 642d01fd 012a2dd1
......@@ -85,25 +85,46 @@
</para>
<para>
If you want to specify logging for one specific library within a
daemon, you set the name to
<replaceable>daemon.library</replaceable>. For example, the logger
used by the code from libdhcpsrv used in kea-dhcp4 binary has the
full name of <quote>kea-dhcp4.dhcpsrv</quote>. If there is no entry
in Logging for a particular library, it will use the configuration
given for the whole daemon.
When diagnosing the problem with the server's operation it is often
desired to use the DEBUG logging level to obtain the verbose output
from the server and libraries it uses. However, high verbosity may
be an overkill for the logging system in cases when the server
is processing high volume traffic. To mitigate this problem, Kea
is using multiple loggers, which can be configured independently
and which are responsible for logging messages from different
functional parts of the server. If the user, trying to diagnose the
problem, has a reasonably high confidence that the problem origins
in a specific function of the server, or the problem is related
to the specific type of operation, he may enable high verbosity
only for the relevant logger, thus limiting the debug messages
to the required minimum.
</para>
<para>
To illustrate this, suppose you want the dhcpsrv library
to log messages of severity DEBUG, and the rest of the
DHCPv4 server code to log messages of severity INFO. To achieve
this you specify two loggers, one with the name
<quote>kea-dhcp4</quote> and severity INFO, and one with
the name <quote>kea-dhcp4.dhcpsrv</quote> with severity
DEBUG. As there are no entries for other libraries,
they will use the configuration for the daemon
(<quote>kea-dhcp4</quote>), so giving the desired behavior.
The loggers are associated with a particular library or binary
of Kea. However, each library or binary may (and usually does)
include multiple loggers. For example, the DHCPv4 server binary
contains separate loggers for: packet parsing, for dropped packets,
for callouts etc. Each logger "derives" its configuration from the
root logger. In the typical case, the root logger configuration
is the only logging configuration specified in the configuration
file. Creating a specific configuration for the selected logger,
thus overriding the configuration settings specified in the
root logger configuration, requires putting its configuration
aside of the root logger's configuration with some of the
parameters modified.
</para>
<para>
To illustrate this, suppose you are using the DHCPv4 server
with the root logger <quote>kea-dhcp4</quote> logging at the
INFO level. In order to enable DEBUG verbosity for the DHCPv4
packet drops, you must create configuration entry for the
logger called <quote>kea-dhcp4.bad_packet</quote> and specify
severity DEBUG for this logger. All other configuration
parameters may be omited for this logger if the logger should
use the default values specified in the root logger's
configuration.
</para>
<!-- we don't support asterisk anymore.
......@@ -128,21 +149,6 @@
(<quote>kea-dhcp4</quote>).
</para>
<para>
One final note about the naming. When specifying the daemon name
within a logger, use the name of the binary file,
e.g. <quote>kea-dhcp4</quote> for the DHCPv4 server,
<quote>kea-dhcp6</quote> for the DHCPv6 server, etc. When the
message is logged, the message will include the name of the process
(e.g. <quote>kea-dhcp4</quote>) followed by the specific component
in that process, e.g. <quote>hooks</quote>. It is possible to
specify either just the process name (<quote>kea-dhcp4</quote>, will
apply to everything logged within that process) or process name
followed by specific logger,
e.g. <quote>kea-dhcp4.hooks</quote>. That will apply only to
messages originating from that component.
</para>
<para>
Currently defined loggers are:
</para>
......@@ -158,7 +164,7 @@
<simpara><command>kea-dhcp4.bad_packet</command> - this is the
logger used by the DHCPv4 server deamon for logging inbound client
packets that were dropped or to which the server responded with a
NAK. The allows adminstrators to configure a separate log
DHCPNAK. The allows adminstrators to configure a separate log
output that contains only packet drop and reject entries.</simpara>
</listitem>
<listitem>
......@@ -175,7 +181,9 @@
<listitem>
<simpara><command>kea-dhcp4.hooks</command> - this logger is used
to log messages related to management of hooks libraries, e.g.
registration and deregistration of the libraries.</simpara>
registration and deregistration of the libraries, and to the
initialization of the callouts execution for various hook points
within the DHCPv4 server.</simpara>
</listitem>
<listitem>
<simpara><command>kea-dhcp4.callouts</command> - this logger is used
......@@ -183,12 +191,44 @@
for the particular hook point.
</simpara>
</listitem>
<listitem>
<simpara><command>kea-dhcp4.ddns</command> - this logger is used by
the DHCPv4 server to log messages related to the Client FQDN and
Hostname option processing. It also includes log messages
related to the relevant DNS updates.</simpara>
</listitem>
<listitem>
<simpara><command>kea-dhcp4.hosts</command> - this logger is used
within the libdhcpsrv and it logs messages related to the management
of the DHCPv4 host reservations, i.e. retrieval of the resevations
and adding new reservations.</simpara>
</listitem>
<listitem>
<simpara><command>kea-dhcp4.leases</command> - this logger is used
by the DHCPv4 server to log messages related to the lease allocation.
The messages include detailed information about the allocated or
offered leases, errors during the lease allocation etc.
</simpara>
</listitem>
<listitem>
<simpara><command>kea-dhcp4.options</command> - this logger is
used by the DHCPv4 server to log messages related to processing
of the options in the DHCPv4 messages, i.e. parsing options,
encoding options into on-wire format and packet classification
using options contained in the received packets.</simpara>
</listitem>
<listitem>
<simpara><command>kea-dhcp4.packets</command> - this logger
is mostly used to log messages related to transmission of the DHCPv4
packets, i.e. packet reception and sending a response. Such messages
include the information about the source and destination IP addresses
and interfaces used to transmit packets. This logger is also used
to log messages related to subnet selection, as this selection is
usually based on the IP addresses and/or interface names, which can
be retrieved from the received packet, even before the DHCPv4 message
carried in the packet is parsed.
</simpara>
</listitem>
<listitem>
<simpara><command>kea-dhcp6</command> - this is the root logger for
the DHCPv6 server. All components used by the DHCPv6 server inherit
......@@ -208,7 +248,7 @@
</listitem>
<listitem>
<simpara><command>kea-dhcp6.hooks</command> - this logger is used
to log messages related to management of hooks libraries, e.g.
during DHCPv6 hooks operation, i.e. anything related to user
registration and deregistration of the libraries.</simpara>
</listitem>
<listitem>
......
......@@ -12,7 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
/// Defines the logger used by the top-level component of kea-dhcp4.
/// @file dhcp4_log.cc
/// Contains the loggers used by the DHCPv4 server component.
#include <dhcp4/dhcp4_log.h>
......@@ -21,10 +22,18 @@ namespace dhcp {
const char* DHCP4_ROOT_LOGGER_NAME = "kea-dhcp4";
const char* DHCP4_APP_LOGGER_NAME = "dhcp4";
const char* DHCP4_BAD_PACKET_LOGGER_NAME = "bad-packet";
const char* DHCP4_BAD_PACKET_LOGGER_NAME = "bad-packets";
const char* DHCP4_PACKET_LOGGER_NAME = "packets";
const char* DHCP4_OPTIONS_LOGGER_NAME = "options";
const char* DHCP4_DDNS_LOGGER_NAME = "ddns";
const char* DHCP4_LEASE_LOGGER_NAME = "leases";
isc::log::Logger dhcp4_logger(DHCP4_APP_LOGGER_NAME);
isc::log::Logger bad_packet_logger(DHCP4_BAD_PACKET_LOGGER_NAME);
isc::log::Logger packet_logger(DHCP4_PACKET_LOGGER_NAME);
isc::log::Logger options_logger(DHCP4_OPTIONS_LOGGER_NAME);
isc::log::Logger ddns_logger(DHCP4_DDNS_LOGGER_NAME);
isc::log::Logger lease_logger(DHCP4_LEASE_LOGGER_NAME);
} // namespace dhcp
} // namespace isc
......
......@@ -12,6 +12,9 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
/// @file dhcp4_log.h
/// Contains declarations for loggers used by the DHCPv4 server component.
#ifndef DHCP4_LOG_H
#define DHCP4_LOG_H
......@@ -22,52 +25,110 @@
namespace isc {
namespace dhcp {
/// Defines the name of the root level "default" logger for kea dhcp4 server.
extern const char* DHCP4_ROOT_LOGGER_NAME;
/// \brief DHCP4 Logging
///
/// Defines the levels used to output debug messages in the non-library part of
/// the kea-dhcp4 program. Higher numbers equate to more verbose (and detailed)
/// output.
/// @name Constants defining debug levels for logging in DHCPv4 server.
//@{
// Debug levels used to log information during startup and shutdown.
/// @brief Debug level used to log information during server startup.
const int DBG_DHCP4_START = DBGLVL_START_SHUT;
/// @brief Debug level used to log information during server shutdown.
const int DBG_DHCP4_SHUT = DBGLVL_START_SHUT;
// Debug level used to log setting information (such as configuration changes).
/// @brief Debug level used to log receiving commands.
const int DBG_DHCP4_COMMAND = DBGLVL_COMMAND;
// Trace basic operations within the code.
/// @brief Debug level used to trace basic operations within the code.
const int DBG_DHCP4_BASIC = DBGLVL_TRACE_BASIC;
// Trace hook related operations
/// @brief Debug level used to trace hook related operations
const int DBG_DHCP4_HOOKS = DBGLVL_TRACE_BASIC;
// Trace detailed operations, including errors raised when processing invalid
// packets. (These are not logged at severities of WARN or higher for fear
// that a set of deliberately invalid packets set to the server could overwhelm
// the logging.)
/// @brief Debug level used to log the traces with some basic data.
///
/// The basic data includes summary information, e.g. summary of the
/// information returned by a particular function. It may also include
/// more detailed information in cases when it is warranted and the
/// extraction of the data doesn't impact the server's performance
/// significantly.
const int DBG_DHCP4_BASIC_DATA = DBGLVL_TRACE_BASIC_DATA;
/// @brief Debug level used to trace detailed errors.
///
/// Trace detailed operations, including errors raised when processing invalid
/// packets. (These are not logged at severities of WARN or higher for fear
/// that a set of deliberately invalid packets set to the server could overwhelm
/// the logging.)
const int DBG_DHCP4_DETAIL = DBGLVL_TRACE_DETAIL;
// This level is used to log the contents of packets received and sent.
/// @brief This level is used to log the contents of packets received and sent.
const int DBG_DHCP4_DETAIL_DATA = DBGLVL_TRACE_DETAIL_DATA;
/// Define the logger for the "dhcp4" module part of kea-dhcp4. We could define
/// a logger in each file, but we would want to define a common name to avoid
/// spelling mistakes, so it is just one small step from there to define a
/// module-common logger.
//@}
/// @name Constants holding names of loggers for the DHCPv4 server.
//@{
/// @brief Defines the name of the root level (default) logger.
extern const char* DHCP4_ROOT_LOGGER_NAME;
/// @brief Name of the base logger for DHCPv4 server.
extern const char* DHCP4_APP_LOGGER_NAME;
extern isc::log::Logger dhcp4_logger;
/// Define a separate logger to which bad packets are logged. This allows
/// users to segregate them into a separate log destination for easy monitoring
/// and diagnostics. Here "bad packet" are packets that are either dropped
/// (i.e malformed, unsupported types) or packets that are rejected and NAKed
/// for logical reasons.
/// @brief Name of the logger for rejected packets.
extern const char* DHCP4_BAD_PACKET_LOGGER_NAME;
/// @brief Name of the logger for processed packets.
extern const char* DHCP4_PACKET_LOGGER_NAME;
/// @brief Name of the logger for options parser.
extern const char* DHCP4_OPTIONS_LOGGER_NAME;
/// @brief Name of the logger for hostname or FQDN processing.
extern const char* DHCP4_DDNS_LOGGER_NAME;
/// @brief Name of the logger for lease allocation logic.
extern const char* DHCP4_LEASE_LOGGER_NAME;
//@}
/// @name Loggers used by the DHCPv4 server
//@{
/// @brief Base logger for DHCPv4 server.
extern isc::log::Logger dhcp4_logger;
/// @brief Logger for rejected packets.
///
/// Here "bad packets" are packets that are either dropped (i.e malformed,
/// unsupported types) or packets that are rejected and NAKed for logical
/// reasons.
extern isc::log::Logger bad_packet_logger;
/// @brief Logger for processed packets.
///
/// This logger is used to issue log messages related to the reception and
/// sending DHCP packets.
extern isc::log::Logger packet_logger;
/// @brief Logger for options parser.
///
/// This logger is used to issue log messages related to processing of the
/// DHCP options
extern isc::log::Logger options_logger;
/// @brief Logger for Hostname or FQDN processing.
///
/// This logger is used to issue log messages related to processing the
/// hostnames, FQDNs and sending name change requests to D2.
extern isc::log::Logger ddns_logger;
/// @brief Logger for lease allocation logic.
///
/// This logger is used to issue log messages related to lease allocation.
extern isc::log::Logger lease_logger;
//@}
} // namespace dhcp4
} // namespace isc
......
This diff is collapsed.
This diff is collapsed.
......@@ -199,25 +199,6 @@ public:
/// @brief Instructs the server to shut down.
void shutdown();
/// @brief Return textual type of packet received by server
///
/// Returns the name of valid packet received by the server (e.g. DISCOVER).
/// If the packet is unknown - or if it is a valid DHCP packet but not one
/// expected to be received by the server (such as an OFFER), the string
/// "UNKNOWN" is returned. This method is used in debug messages.
///
/// As the operation of the method does not depend on any server state, it
/// is declared static.
///
/// @todo: This should be named static Pkt4::getName()
///
/// @param type DHCPv4 packet type
///
/// @return Pointer to "const" string containing the packet name.
/// Note that this string is statically allocated and MUST NOT
/// be freed by the caller.
static const char* serverReceivedPacketName(uint8_t type);
///
/// @name Public accessors returning values required to (re)open sockets.
///
......
......@@ -436,38 +436,6 @@ TEST_F(Dhcpv4SrvTest, processDecline) {
EXPECT_NO_THROW(srv.processDecline(pkt));
}
TEST_F(Dhcpv4SrvTest, serverReceivedPacketName) {
// Check all possible packet types
for (int itype = 0; itype < 256; ++itype) {
uint8_t type = itype;
switch (type) {
case DHCPDECLINE:
EXPECT_STREQ("DECLINE", Dhcpv4Srv::serverReceivedPacketName(type));
break;
case DHCPDISCOVER:
EXPECT_STREQ("DISCOVER", Dhcpv4Srv::serverReceivedPacketName(type));
break;
case DHCPINFORM:
EXPECT_STREQ("INFORM", Dhcpv4Srv::serverReceivedPacketName(type));
break;
case DHCPRELEASE:
EXPECT_STREQ("RELEASE", Dhcpv4Srv::serverReceivedPacketName(type));
break;
case DHCPREQUEST:
EXPECT_STREQ("REQUEST", Dhcpv4Srv::serverReceivedPacketName(type));
break;
default:
EXPECT_STREQ("UNKNOWN", Dhcpv4Srv::serverReceivedPacketName(type));
}
}
}
// This test verifies that incoming DISCOVER can be handled properly, that an
// OFFER is generated, that the response has an address and that address
// really belongs to the configured pool.
......
......@@ -195,29 +195,50 @@ bool Option::delOption(uint16_t opt_type) {
}
std::string Option::toText(int indent /* =0 */ ) {
std::stringstream tmp;
for (int i = 0; i < indent; i++)
tmp << " ";
tmp << "type=" << type_ << ", len=" << len()-getHeaderLen() << ": ";
std::string Option::toText(int indent) {
std::stringstream output;
output << headerToText(indent) << ": ";
for (unsigned int i = 0; i < data_.size(); i++) {
if (i) {
tmp << ":";
output << ":";
}
tmp << setfill('0') << setw(2) << hex
output << setfill('0') << setw(2) << hex
<< static_cast<unsigned short>(data_[i]);
}
// print suboptions
for (OptionCollection::const_iterator opt = options_.begin();
opt != options_.end();
++opt) {
tmp << (*opt).second->toText(indent+2);
// Append suboptions.
output << suboptionsToText(indent + 2);
return (output.str());
}
std::string
Option::headerToText(const int indent) {
std::stringstream output;
for (int i = 0; i < indent; i++)
output << " ";
int field_len = (getUniverse() == V4 ? 3 : 5);
output << "type=" << std::setw(field_len) << std::setfill('0')
<< type_ << ", len=" << std::setw(field_len) << std::setfill('0')
<< len()-getHeaderLen();
return (output.str());
}
std::string
Option::suboptionsToText(const int indent) const {
std::stringstream output;
if (!options_.empty()) {
output << "," << std::endl << "options:";
for (OptionCollection::const_iterator opt = options_.begin();
opt != options_.end(); ++opt) {
output << std::endl << (*opt).second->toText(indent);
}
}
return tmp.str();
return (output.str());
}
uint16_t
......
// Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2015 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
......@@ -423,7 +423,31 @@ protected:
/// those into one exception which can be documented here.
void unpackOptions(const OptionBuffer& buf);
/// @brief A private method used for option correctness.
/// @brief Returns option header in the textual format.
///
/// This protected method should be called by the derived classes in
/// their respective @c toText implementations.
///
/// @param indent Number of spaces to insert before the text.
///
/// @return Option header in the textual format.
std::string headerToText(const int indent = 0);
/// @brief Returns collection of suboptions in the textual format.
///
/// This protected method should be called by the derived classes
/// in their respective @c toText implementations to append the
/// suboptions held by this option. Note that there are some
/// option types which don't have suboptions because they contain
/// variable length fields. For such options this method is not
/// called.
///
/// @param indent Number of spaces to insert before the text.
///
//// @return Suboptions in the textual format.
std::string suboptionsToText(const int indent = 0) const;
/// @brief A protected method used for option correctness.
///
/// It is used in constructors. In there are any problems detected
/// (like specifying type > 255 for DHCPv4 option), it will throw
......
// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2012,2015 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
......@@ -120,21 +120,16 @@ uint16_t Option4AddrLst::len() {
return (getHeaderLen() + addrs_.size() * V4ADDRESS_LEN);
}
std::string Option4AddrLst::toText(int indent /* =0 */ ) {
std::stringstream tmp;
for (int i = 0; i < indent; i++) {
tmp << " ";
}
tmp << "type=" << type_ << ", len=" << len()-getHeaderLen() << ":";
std::string Option4AddrLst::toText(int indent) {
std::stringstream output;
output << headerToText(indent) << ":";
for (AddressContainer::const_iterator addr = addrs_.begin();
addr != addrs_.end(); ++addr) {
tmp << " " << (*addr);
output << " " << (*addr);
}
return tmp.str();
return (output.str());
}
} // end of isc::dhcp namespace
......
// Copyright (C) 2011-2012, 2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2012,2015 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
......@@ -97,18 +97,15 @@ void Option6AddrLst::unpack(OptionBufferConstIter begin,
}
}
std::string Option6AddrLst::toText(int indent /* =0 */) {
stringstream tmp;
for (int i = 0; i < indent; i++)
tmp << " ";
tmp << "type=" << type_ << " " << addrs_.size() << "addr(s): ";
std::string Option6AddrLst::toText(int indent) {
stringstream output;
output << headerToText(indent) << ":";
for (AddressContainer::const_iterator addr = addrs_.begin();
addr != addrs_.end(); ++addr) {
tmp << *addr << " ";
output << " " << *addr;
}
return tmp.str();
return (output.str());
}
uint16_t Option6AddrLst::len() {
......
// Copyright (C) 2012-2013, 2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2013,2015 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
......@@ -349,17 +349,17 @@ OptionCustom::dataFieldToText(const OptionDataType data_type,
text << readAddress(index);
break;
case OPT_FQDN_TYPE:
text << readFqdn(index);
text << "\"" << readFqdn(index) << "\"";
break;
case OPT_STRING_TYPE:
text << readString(index);
text << "\"" << readString(index) << "\"";
break;
default:
;
}
// Append data field type in brackets.
text << " ( " << OptionDataTypeUtil::getDataTypeName(data_type) << " ) ";
text << " (" << OptionDataTypeUtil::getDataTypeName(data_type) << ")";
return (text.str());
}
......@@ -532,13 +532,9 @@ void OptionCustom::initialize(const OptionBufferConstIter first,
}
std::string OptionCustom::toText(int indent) {
std::stringstream tmp;
std::stringstream output;
for (int i = 0; i < indent; ++i)
tmp << " ";
tmp << "type=" << type_ << ", len=" << len()-getHeaderLen()
<< ", data fields:" << std::endl;
output << headerToText(indent) << ":";
OptionDataType data_type = definition_.getType();
if (data_type == OPT_RECORD_TYPE) {
......@@ -550,13 +546,8 @@ std::string OptionCustom::toText(int indent) {
// with them.
for (OptionDefinition::RecordFieldsConstIter field = fields.begin();
field != fields.end(); ++field) {
for (int j = 0; j < indent + 2; ++j) {
tmp << " ";
}
tmp << "#" << std::distance(fields.begin(), field) << " "
<< dataFieldToText(*field, std::distance(fields.begin(),
field))
<< std::endl;
output << " " << dataFieldToText(*field, std::distance(fields.begin(),
field));
}
} else {
// For non-record types we iterate over all buffers
......@@ -565,22 +556,14 @@ std::string OptionCustom::toText(int indent) {
// and non-arrays as they only differ in such a way that
// non-arrays have just single data field.
for (unsigned int i = 0; i < getDataFieldsNum(); ++i) {
for (int j = 0; j < indent + 2; ++j) {
tmp << " ";
}
tmp << "#" << i << " "
<< dataFieldToText(definition_.getType(), i)
<< std::endl;
output << " " << dataFieldToText(definition_.getType(), i);
}
}