BIND 10 trac976, updated. a86e015d7c5fd0b0d8286523aa5d7e3b036f8589 [trac976] Add additional tests for different destinations
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Jun 6 13:26:06 UTC 2011
The branch, trac976 has been updated
via a86e015d7c5fd0b0d8286523aa5d7e3b036f8589 (commit)
via 92113f50b12c221ca1db5dbccd51d762be5d4f6e (commit)
from 7855203ec77dd6165607297f90d0be20734fe692 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit a86e015d7c5fd0b0d8286523aa5d7e3b036f8589
Author: Stephen Morris <stephen at isc.org>
Date: Mon Jun 6 14:11:27 2011 +0100
[trac976] Add additional tests for different destinations
commit 92113f50b12c221ca1db5dbccd51d762be5d4f6e
Author: Stephen Morris <stephen at isc.org>
Date: Mon Jun 6 11:36:59 2011 +0100
[trac976] Ignore log4cplus root logger
Create BIND 10 root logger as child of the (unused) log4cplus
root logger and create other loggers as children of that. This
simplifies the inclusion of logger name in output messages.
Also, enhance documentation.
-----------------------------------------------------------------------
Summary of changes:
configure.ac | 2 +
src/lib/log/logger.h | 75 +++++++--
src/lib/log/logger_impl.cc | 26 +---
src/lib/log/logger_impl.h | 21 +--
src/lib/log/logger_manager_impl.cc | 28 ++--
src/lib/log/tests/Makefile.am | 1 +
src/lib/log/tests/console_test.sh.in | 12 +-
src/lib/log/tests/destination_test.sh.in | 85 ++++++++++
src/lib/log/tests/local_file_test.sh.in | 24 ++-
src/lib/log/tests/logger_example.cc | 247 +++++++++++++++++++++++-------
src/lib/log/tests/severity_test.sh.in | 39 +++--
11 files changed, 412 insertions(+), 148 deletions(-)
create mode 100755 src/lib/log/tests/destination_test.sh.in
-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 3d85931..c0d21fa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -891,6 +891,7 @@ AC_OUTPUT([doc/version.ent
src/lib/cc/session_config.h.pre
src/lib/cc/tests/session_unittests_config.h
src/lib/log/tests/console_test.sh
+ src/lib/log/tests/destination_test.sh
src/lib/log/tests/local_file_test.sh
src/lib/log/tests/severity_test.sh
src/lib/log/tests/tempdir.h
@@ -922,6 +923,7 @@ AC_OUTPUT([doc/version.ent
chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
chmod +x src/lib/log/tests/local_file_test.sh
chmod +x src/lib/log/tests/console_test.sh
+ chmod +x src/lib/log/tests/destination_test.sh
chmod +x src/lib/log/tests/severity_test.sh
chmod +x src/lib/util/python/mkpywrapper.py
chmod +x tests/system/conf.sh
diff --git a/src/lib/log/logger.h b/src/lib/log/logger.h
index e2a1439..9a4be6d 100644
--- a/src/lib/log/logger.h
+++ b/src/lib/log/logger.h
@@ -25,26 +25,67 @@
namespace isc {
namespace log {
-/// \brief Logging API
-///
-/// This module forms the interface into the logging subsystem. Features of the
-/// system and its implementation are:
-///
-/// # Multiple logging objects can be created, each given a name; those with the
-/// same name share characteristics (like destination, level being logged
-/// etc.)
-/// # Messages can be logged at severity levels of FATAL, ERROR, WARN, INFO or
-/// DEBUG. The DEBUG level has further sub-levels numbered 0 (least
-/// informative) to 99 (most informative).
-/// # Each logger has a severity level set associated with it. When a message
-/// is logged, it is output only if it is logged at a level equal to the
-/// logger severity level or greater, e.g. if the logger's severity is WARN,
-/// only messages logged at WARN, ERROR or FATAL will be output.
-/// # Messages are identified by message identifiers, which are keys into a
-/// message dictionary.
+/// \page LoggingApi Logging API
+/// \section LoggingApiOverview Overview
+/// BIND 10 logging uses the concepts of the widely-used Java logging
+/// package log4j (http://logging.apache.log/log4j), albeit implemented
+/// in C++ using an open-source port. Features of the system are:
+///
+/// - Within the code objects - known as loggers - can be created and
+/// used to log messages. These loggers have names; those with the
+/// same name share characteristics (such as output destination).
+/// - Loggers have a hierarchical relationship, with each logger being
+/// the child of another logger, except for the top of the hierarchy, the
+/// root logger. If a logger does not log a message, it is passed to the
+/// parent logger.
+/// - Messages can be logged at severity levels of FATAL, ERROR, WARN, INFO
+/// or DEBUG. The DEBUG level has further sub-levels numbered 0 (least
+/// informative) to 99 (most informative).
+/// - Each logger has a severity level set associated with it. When a
+/// message is logged, it is output only if it is logged at a level equal
+/// to the logger severity level or greater, e.g. if the logger's severity
+/// is WARN, only messages logged at WARN, ERROR or FATAL will be output.
+///
+/// \section LoggingApiLoggerNames BIND 10 Logger Names
+/// Within BIND 10, the root logger root logger is given the name of the
+/// program (via the stand-along function setRootLoggerName()). Other loggers
+/// are children of the root logger and are named "<program>.<sublogger>".
+/// This name appears in logging output, allowing users to identify both
+/// the BIND 10 program and the component within the program that generated
+/// the message.
+///
+/// When creating a logger, the abbreviated name "<sublogger>" can be used;
+/// the program name will be prepended to it when the logger is created.
+/// In this way, individual libraries can have their own loggers without
+/// worrying about the program in which they are used, but:
+/// - The origin of the message will be clearly identified.
+/// - The same component can have different options (e.g. logging severity)
+/// in different programs at the same time.
+///
+/// \section LoggingApiLoggingMessages Logging Messages
+/// Instead of embedding the text of messages within the code, each message
+/// is referred to using a symbolic name. The logging code uses this name as
+/// a key in a dictionary from which the message text is obtained. Such a
+/// system allows for the optional replacement of message text at run time.
+/// More details about the message disction (and the compiler used to create
+/// the symbol definitions) can be found in other modules in the src/lib/log
+/// directory.
class LoggerImpl; // Forward declaration of the implementation class
+/// \brief Logger Class
+///
+/// This class is the main class used for logging. Use comprises:
+///
+/// 1. Constructing a logger by instantiating it with a specific name. As
+/// well as instantiating it when needed, the logger can also be declared
+/// outside a program using.
+///
+/// 2. Using the error(), info() etc. methods to log an error. (Although it is
+/// recommended to use the LOG_ERROR, LOG_INFO etc. macros defined in macros.h.
+/// These will avoid the potentially-expensive evaluation of arguments if the
+/// severity is such that the message will be suppressed.)
+
class Logger {
public:
diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc
index fad5490..cbf2f1f 100644
--- a/src/lib/log/logger_impl.cc
+++ b/src/lib/log/logger_impl.cc
@@ -42,26 +42,14 @@ using namespace std;
namespace isc {
namespace log {
-// Constructor. Although it may be immediately reset, logger_ is initialized to
-// the log4cplus root logger; at least one compiler requires that all member
-// variables be constructed before the constructor is run, but log4cplus::Logger
-// (the type of logger_) has no default constructor.
-LoggerImpl::LoggerImpl(const string& name) :
- logger_(log4cplus::Logger::getRoot())
+// Constructor. The setting of logger_ must be done when the variable is
+// constructed (instead of being left to the body of the function); at least
+// one compiler requires that all member variables be constructed before the
+// constructor is run, but log4cplus::Logger (the type of logger_) has no
+// default constructor.
+LoggerImpl::LoggerImpl(const string& name) : name_(expandLoggerName(name)),
+ logger_(log4cplus::Logger::getInstance(name_))
{
- // Are we the root logger, or does the logger name start with
- // the string "<root_logger_name>.". If so, use a logger
- // whose name is the one given.
- if ((name == getRootLoggerName()) ||
- (name.find(getRootLoggerName() + string(".")) == 0)) {
- name_ = name;
-
- } else {
- // Anything else is assumed to be a sub-logger of the
- // root logger.
- name_ = getRootLoggerName() + "." + name;
- }
- logger_ = log4cplus::Logger::getInstance(name);
}
// Destructor. (Here because of virtual declaration.)
diff --git a/src/lib/log/logger_impl.h b/src/lib/log/logger_impl.h
index 3c7c83d..90bd41a 100644
--- a/src/lib/log/logger_impl.h
+++ b/src/lib/log/logger_impl.h
@@ -50,21 +50,14 @@ namespace log {
/// documentation, but actually unnamed) and all loggers created are subloggers
/// if it.
///
-/// In this implementation, the name of the logger is checked. If it is the
-/// name of the program (as set in the call to isc::log::setRootLoggerName),
-/// the log4cplus root logger is used. Otherwise the name passed is used as
-/// the name of a logger when a log4cplus logger is created.
+/// In this implementation, the log4cplus root logger is unused. Instead, the
+/// BIND 10 root logger is created as a child of the log4cplus root logger,
+/// and all other loggers used in the program are created as sub-loggers of
+/// that. In this way, the logging system can just include the name of the
+/// logger in each message without the need to specially consider if the
+/// message is the root logger or not.
///
-/// To clarify: if the program is "b10auth" (and that is used to set the BIND 10
-/// root logger name via a call to isc::log::setRootLoggerName()), the BIND 10
-/// logger "b10auth" corresponds to the log4cplus root logger instance (returned
-/// by a call to log4cplus::Logger::getRoot()). The BIND 10 sub-logger "cache"
-/// corresponds to the log4cplus logger "cache", created by a call to
-/// log4cplus::Logger::getInstance("cache"). The distinction is, however,
-/// invisible to users as the logger reported in messages is always
-/// "programm.sublogger".
-///
-/// b) The idea of debug levels is implemented. Seee logger_level.h and
+/// b) The idea of debug levels is implemented. See logger_level.h and
/// logger_level_impl.h for more details on this.
class LoggerImpl {
diff --git a/src/lib/log/logger_manager_impl.cc b/src/lib/log/logger_manager_impl.cc
index bb4b06f..5438049 100644
--- a/src/lib/log/logger_manager_impl.cc
+++ b/src/lib/log/logger_manager_impl.cc
@@ -52,9 +52,8 @@ LoggerManagerImpl::processInit() {
void
LoggerManagerImpl::processSpecification(const LoggerSpecification& spec) {
- log4cplus::Logger logger = (spec.getName() == getRootLoggerName()) ?
- log4cplus::Logger::getRoot() :
- log4cplus::Logger::getInstance(spec.getName());
+ log4cplus::Logger logger = log4cplus::Logger::getInstance(
+ expandLoggerName(spec.getName()));
// Set severity level according to specification entry.
logger.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
@@ -180,14 +179,20 @@ void LoggerManagerImpl::initRootLogger(isc::log::Severity severity,
{
log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
- // Set the severity for the root logger
- log4cplus::Logger::getRoot().setLogLevel(
- LoggerLevelImpl::convertFromBindLevel(Level(severity, dbglevel)));
+ // Set the log4cplus root to not output anything - effectively we are
+ // ignoring it.
+ log4cplus::Logger::getRoot().setLogLevel(log4cplus::OFF_LOG_LEVEL);
- // Set the root to use a console logger.
+ // Set the level for the BIND 10 root logger to the given severity and
+ // debug level.
+ log4cplus::Logger b10root = log4cplus::Logger::getInstance(
+ getRootLoggerName());
+ b10root.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
+ Level(severity, dbglevel)));
+
+ // Set the BIND 10 root to use a console logger.
OutputOption opt;
- log4cplus::Logger root = log4cplus::Logger::getRoot();
- createConsoleAppender(root, opt);
+ createConsoleAppender(b10root, opt);
}
// Set the the "console" layout for the given appenders. This layout includes
@@ -197,8 +202,7 @@ void LoggerManagerImpl::setConsoleAppenderLayout(
log4cplus::SharedAppenderPtr& appender)
{
// Create the pattern we want for the output - local time.
- string pattern = "%D{%Y-%m-%d %H:%M:%S.%q} %-5p [";
- pattern += getRootLoggerName() + string(".%c] %m\n");
+ string pattern = "%D{%Y-%m-%d %H:%M:%S.%q} %-5p [%c] %m\n";
// Finally the text of the message
auto_ptr<log4cplus::Layout> layout(new log4cplus::PatternLayout(pattern));
@@ -213,7 +217,7 @@ void LoggerManagerImpl::setSysLogAppenderLayout(
log4cplus::SharedAppenderPtr& appender)
{
// Create the pattern we want for the output - local time.
- string pattern = "%-5p [" + getRootLoggerName() + string(".%c] %m\n");
+ string pattern = "%-5p [%c] %m\n";
// Finally the text of the message
auto_ptr<log4cplus::Layout> layout(new log4cplus::PatternLayout(pattern));
diff --git a/src/lib/log/tests/Makefile.am b/src/lib/log/tests/Makefile.am
index 5a5325a..b396e34 100644
--- a/src/lib/log/tests/Makefile.am
+++ b/src/lib/log/tests/Makefile.am
@@ -56,5 +56,6 @@ noinst_PROGRAMS = $(TESTS)
PYTESTS = console_test.sh local_file_test.sh severity_test.sh
check-local:
$(SHELL) $(abs_builddir)/console_test.sh
+ $(SHELL) $(abs_builddir)/destination_test.sh
$(SHELL) $(abs_builddir)/local_file_test.sh
$(SHELL) $(abs_builddir)/severity_test.sh
diff --git a/src/lib/log/tests/console_test.sh.in b/src/lib/log/tests/console_test.sh.in
index d6d97f6..67ff3a5 100755
--- a/src/lib/log/tests/console_test.sh.in
+++ b/src/lib/log/tests/console_test.sh.in
@@ -37,22 +37,22 @@ passfail() {
echo "1. Checking that console output to stdout goes to stdout:"
rm -f $tempfile
-./logger_example -c stdout -s error -c stdout 1> $tempfile
-passfail 2
+./logger_example -c stdout -s error 1> $tempfile
+passfail 4
echo "2. Checking that console output to stdout does not go to stderr:"
rm -f $tempfile
-./logger_example -c stdout -s error -c stdout 2> $tempfile
+./logger_example -c stdout -s error 2> $tempfile
passfail 0
echo "3. Checking that console output to stderr goes to stderr:"
rm -f $tempfile
-./logger_example -c stdout -s error -c stderr 2> $tempfile
-passfail 2
+./logger_example -c stderr -s error 2> $tempfile
+passfail 4
echo "4. Checking that console output to stderr does not go to stdout:"
rm -f $tempfile
-./logger_example -c stdout -s error -c stderr 1> $tempfile
+./logger_example -c stderr -s error 1> $tempfile
passfail 0
rm -f $tempfile
diff --git a/src/lib/log/tests/destination_test.sh.in b/src/lib/log/tests/destination_test.sh.in
new file mode 100755
index 0000000..4a7c2e6
--- /dev/null
+++ b/src/lib/log/tests/destination_test.sh.in
@@ -0,0 +1,85 @@
+#!/bin/sh
+# 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.
+
+# \brief Severity test
+#
+# Checks that the logger will limit the output of messages less severy than
+# the severity/debug setting.
+
+testname="Destination test"
+echo $testname
+
+failcount=0
+tempfile=@abs_builddir@/destination_test_tempfile_$$
+destfile1=@abs_builddir@/destination_test_destfile_1_$$
+destfile2=@abs_builddir@/destination_test_destfile_2_$$
+
+passfail() {
+ if [ $1 -eq 0 ]; then
+ echo " -- pass"
+ else
+ echo " ** FAIL"
+ failcount=`expr $failcount + $1`
+ fi
+}
+
+echo "1. One logger, multiple destinations"
+cat > $tempfile << .
+FATAL [example] MSG_WRITERR, error writing to test1: 42
+ERROR [example] MSG_RDLOCMES, reading local message file dummy/file
+FATAL [example.beta] MSG_BADSEVERITY, unrecognized log severity: beta_fatal
+ERROR [example.beta] MSG_BADDESTINATION, unrecognized log destination: beta_error
+.
+rm -f $destfile1 $destfile2
+./logger_example -s error -f $destfile1 -f $destfile2
+cut -d' ' -f3- $destfile1 | diff $tempfile -
+passfail $?
+cut -d' ' -f3- $destfile2 | diff $tempfile -
+passfail $?
+
+echo "2. Two loggers, different destinations and severities"
+rm -f $destfile1 $destfile2
+./logger_example -l example -s info -f $destfile1 -l alpha -s warn -f $destfile2
+
+# All output for example and example.beta should have gone to destfile1.
+# Output for example.alpha should have done to destfile2.
+
+cat > $tempfile << .
+FATAL [example] MSG_WRITERR, error writing to test1: 42
+ERROR [example] MSG_RDLOCMES, reading local message file dummy/file
+WARN [example] MSG_BADSTREAM, bad log console output stream: example
+FATAL [example.beta] MSG_BADSEVERITY, unrecognized log severity: beta_fatal
+ERROR [example.beta] MSG_BADDESTINATION, unrecognized log destination: beta_error
+WARN [example.beta] MSG_BADSTREAM, bad log console output stream: beta_warn
+INFO [example.beta] MSG_READERR, error reading from message file beta: info
+.
+cut -d' ' -f3- $destfile1 | diff $tempfile -
+passfail $?
+
+cat > $tempfile << .
+WARN [example.alpha] MSG_READERR, error reading from message file a.txt: dummy reason
+.
+cut -d' ' -f3- $destfile2 | diff $tempfile -
+passfail $?
+
+if [ $failcount -eq 0 ]; then
+ echo "PASS: $testname"
+elif [ $failcount -eq 1 ]; then
+ echo "FAIL: $testname - 1 test failed"
+else
+ echo "FAIL: $testname - $failcount tests failed"
+fi
+
+exit $failcount
diff --git a/src/lib/log/tests/local_file_test.sh.in b/src/lib/log/tests/local_file_test.sh.in
index f370c5b..9a388a9 100755
--- a/src/lib/log/tests/local_file_test.sh.in
+++ b/src/lib/log/tests/local_file_test.sh.in
@@ -45,20 +45,28 @@ cat > $localmes << .
echo "1. Local message replacement:"
cat > $tempfile << .
-WARN [alpha.log] MSG_IDNOTFND, could not replace message text for 'MSG_NOTHERE': no such message
-FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
-ERROR [alpha.example] MSG_RDLOCMES, replacement read local message file, parameter is 'dummy/file'
-WARN [alpha.dlm] MSG_READERR, replacement read error, parameters: 'a.txt' and 'dummy reason'
+WARN [example.log] MSG_IDNOTFND, could not replace message text for 'MSG_NOTHERE': no such message
+FATAL [example] MSG_WRITERR, error writing to test1: 42
+ERROR [example] MSG_RDLOCMES, replacement read local message file, parameter is 'dummy/file'
+WARN [example] MSG_BADSTREAM, bad log console output stream: example
+WARN [example.alpha] MSG_READERR, replacement read error, parameters: 'a.txt' and 'dummy reason'
+FATAL [example.beta] MSG_BADSEVERITY, unrecognized log severity: beta_fatal
+ERROR [example.beta] MSG_BADDESTINATION, unrecognized log destination: beta_error
+WARN [example.beta] MSG_BADSTREAM, bad log console output stream: beta_warn
.
./logger_example -c stdout -s warn $localmes | cut -d' ' -f3- | diff $tempfile -
passfail $?
echo "2. Report error if unable to read local message file:"
cat > $tempfile << .
-ERROR [alpha.log] MSG_OPENIN, unable to open message file $localmes for input: No such file or directory
-FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
-ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
-WARN [alpha.dlm] MSG_READERR, error reading from message file a.txt: dummy reason
+ERROR [example.log] MSG_OPENIN, unable to open message file $localmes for input: No such file or directory
+FATAL [example] MSG_WRITERR, error writing to test1: 42
+ERROR [example] MSG_RDLOCMES, reading local message file dummy/file
+WARN [example] MSG_BADSTREAM, bad log console output stream: example
+WARN [example.alpha] MSG_READERR, error reading from message file a.txt: dummy reason
+FATAL [example.beta] MSG_BADSEVERITY, unrecognized log severity: beta_fatal
+ERROR [example.beta] MSG_BADDESTINATION, unrecognized log destination: beta_error
+WARN [example.beta] MSG_BADSTREAM, bad log console output stream: beta_warn
.
rm -f $localmes
./logger_example -c stdout -s warn $localmes | cut -d' ' -f3- | diff $tempfile -
diff --git a/src/lib/log/tests/logger_example.cc b/src/lib/log/tests/logger_example.cc
index 3dbacfd..6b43c18 100644
--- a/src/lib/log/tests/logger_example.cc
+++ b/src/lib/log/tests/logger_example.cc
@@ -28,6 +28,7 @@
#include <iostream>
#include <string>
+#include <vector>
#include <util/strutil.h>
@@ -49,23 +50,54 @@ using namespace std;
void usage() {
cout <<
-"logger_support_test [-h] [-c stream] [-d dbglevel] [-f file]\n"
-" [-s severity] [localfile]\n"
+"logger_support_test [-h | [logger_spec] [[logger_spec]...]]\n"
"\n"
-" -h Print this message and exit\n"
+" -h Print this message and exit\n"
+"\n"
+"The rest of the command line comprises the set of logger specifications.\n"
+"Each specification is of the form:\n"
+"\n"
+" -l logger [-s severity] [-d dbglevel] output_spec] [[output_spec] ...\n"
+"\n"
+"where:\n"
+"\n"
+" -l logger Give the name of the logger to which the following\n"
+" output specifications will apply.\n"
+"\n"
+"Each logger is followed by the indication of the serverity it is logging\n"
+"and, if applicable, its debug level:\n"
"\n"
" -d dbglevel Debug level. Only interpreted if the severity is 'debug'\n"
" this is a number between 0 and 99.\n"
-" -c stream Send output to the console. 'stream' is one of 'stdout'\n"
-" of 'stderr'. The '-c' switch is incompatible with '-f'\n"
-" and '-l'\n"
-" -f file Send output to specified file, appending to existing file\n"
-" if one exists. Incompatible with -c and -l switches.\n"
" -s severity Set the severity of messages output. 'severity' is one\n"
" of 'debug', 'info', 'warn', 'error', 'fatal', the default\n"
" being 'info'.\n"
"\n"
-"If none of -c, -f or -l is given, by default, output is sent to stdout\n";
+"The output specifications - there may be more than one per logger - detail\n"
+"the output streams attached to the logger. These are of the form:\n"
+"\n"
+" -c stream | -f file [-m maxver] [-z maxsize] | -y facility\n"
+"\n"
+"These are:\n"
+"\n"
+" -c stream Send output to the console. 'stream' is one of 'stdout'\n"
+" of 'stderr'.\n"
+" -f file Send output to specified file, appending to existing file\n"
+" if one exists.\n"
+" -y facility Send output to the syslog file with the given facility\n"
+" name (e.g. local1, cron etc.)\n"
+"\n"
+"The following can be specified for the file logger:\n"
+"\n"
+" -m maxver If file rolling is selected (by the maximum file size being\n"
+" non-zero), the maximum number of versions to keep (defaults\n"
+" to 0)\n"
+" -z maxsize Maximum size of the file before the file is closed and a\n"
+" new one opened. The default of 0 means no maximum size.\n"
+"\n"
+"If none of -c, -f or -y is given, by default, output is sent to stdout. If no\n"
+"logger is specified, the default is the program's root logger ('example').\n";
+
}
@@ -73,37 +105,57 @@ void usage() {
// messages. Looking at the output determines whether the program worked.
int main(int argc, char** argv) {
- const string ROOT_NAME = "alpha";
+ const string ROOT_NAME = "example";
+ bool sw_found = false; // Set true if switch found
bool c_found = false; // Set true if "-c" found
bool f_found = false; // Set true if "-f" found
- bool l_found = false; // Set true if "-l" found
-
+ bool y_found = false; // Set true if "-y" found
int option; // For getopt() processing
-
- LoggerSpecification spec(ROOT_NAME); // Logger specification
- OutputOption outopt; // Logger output option
-
- // Initialize loggers (to set the root name and initialize logging);
- LoggerManager::init(ROOT_NAME);
-
- // Parse options
- while ((option = getopt(argc, argv, "hc:d:f:s:")) != -1) {
+ OutputOption def_opt; // Default output option - used
+ // for initialization
+ LoggerSpecification cur_spec(ROOT_NAME);// Current specification
+ OutputOption cur_opt; // Current output option
+ vector<LoggerSpecification> loggers; // Set of logger specifications
+ vector<OutputOption> options; // Output options for logger
+ std::string severity; // Severity set for logger
+
+ // Initialize logging system - set the root logger name.
+ LoggerManager manager;
+ manager.init(ROOT_NAME);
+
+ // In the parsing loop that follows, the construction of the logging
+ // specification is always "one behind". In other words, the parsing of
+ // command-line options updates thge current logging specification/output
+ // options. When the flag indicating a new logger or output specification
+ // is encountered, the previous one is added to the list.
+ //
+ // One complication is that there is deemed to be a default active when
+ // the parsing starts (console output for the BIND 10 root logger). This
+ // is included in the logging specifications UNLESS the first switch on
+ // the command line is a "-l" flag starting a new logger. To track this,
+ // the "sw_found" flag is set when a switch is completey processed. The
+ // processing of "-l" will only add information for a previous logger to
+ // the list if this flag is set.
+ while ((option = getopt(argc, argv, "hc:d:f:l:m:s:y:z:")) != -1) {
switch (option) {
- case 'c':
- if (f_found || l_found) {
- cerr << "Cannot specify -c with -f or -l\n";
- return (1);
+ case 'c': // Console output
+ // New output spec. If one was currently active, add it to the
+ // list and reset the current output option to the defaults.
+ if (c_found || f_found || y_found) {
+ cur_spec.addOutputOption(cur_opt);
+ cur_opt = def_opt;
+ c_found = f_found = y_found = false;
}
+ // Set the output option for this switch.
c_found = true;
- outopt.destination = OutputOption::DEST_CONSOLE;
-
+ cur_opt.destination = OutputOption::DEST_CONSOLE;
if (strcmp(optarg, "stdout") == 0) {
- outopt.stream = OutputOption::STR_STDOUT;
+ cur_opt.stream = OutputOption::STR_STDOUT;
} else if (strcmp(optarg, "stderr") == 0) {
- outopt.stream = OutputOption::STR_STDERR;
+ cur_opt.stream = OutputOption::STR_STDERR;
} else {
cerr << "Unrecognised console option: " << optarg << "\n";
@@ -111,66 +163,143 @@ int main(int argc, char** argv) {
}
break;
- case 'd':
- spec.setDbglevel(boost::lexical_cast<int>(optarg));
+ case 'd': // Debug level
+ cur_spec.setDbglevel(boost::lexical_cast<int>(optarg));
break;
- case 'f':
- if (c_found || l_found) {
- cerr << "Cannot specify -f with -c or -l\n";
- return (1);
+ case 'f': // File output specification
+ // New output spec. If one was currently active, add it to the
+ // list and reset the current output option to the defaults.
+ if (c_found || f_found || y_found) {
+ cur_spec.addOutputOption(cur_opt);
+ cur_opt = def_opt;
+ c_found = f_found = y_found = false;
}
+ // Set the output option for this switch.
f_found = true;
-
- outopt.destination = OutputOption::DEST_FILE;
- outopt.filename = optarg;
+ cur_opt.destination = OutputOption::DEST_FILE;
+ cur_opt.filename = optarg;
break;
- case 'h':
+ case 'h': // Help
usage();
return (0);
- case 's':
- {
- string severity(optarg);
- isc::util::str::uppercase(severity);
- spec.setSeverity(getSeverity(severity));
+ case 'l': // Logger
+ // If a current specification is active, add the last output option
+ // to it, add it to the list and reset. A specification is active
+ // if at least one switch has been previously found.
+ if (sw_found) {
+ cur_spec.addOutputOption(cur_opt);
+ loggers.push_back(cur_spec);
+ cur_spec.reset();
+ }
+
+ // Set the logger name
+ cur_spec.setName(std::string(optarg));
+
+ // Reset the output option to the default.
+ cur_opt = def_opt;
+
+ // Indicate nothing is found to prevent the console option (the
+ // default output option) being added to the output list if an
+ // output option is found.
+ c_found = f_found = y_found = false;
+ break;
+
+ case 'm': // Maximum file version
+ if (!f_found) {
+ std::cerr << "Attempt to set maximum version (-m) "
+ "outside of file output specification\n";
+ return (1);
+ }
+ try {
+ cur_opt.maxsize = boost::lexical_cast<unsigned int>(optarg);
+ } catch (boost::bad_lexical_cast&) {
+ std::cerr << "Maximum version (-m) argument must be a positive "
+ "integer\n";
+ return (1);
+ }
+ break;
+
+ case 's': // Severity
+ severity = optarg;
+ isc::util::str::uppercase(severity);
+ cur_spec.setSeverity(getSeverity(severity));
+ break;
+
+ case 'y': // Syslog output
+ // New output spec. If one was currently active, add it to the
+ // list and reset the current output option to the defaults.
+ if (c_found || f_found || y_found) {
+ cur_spec.addOutputOption(cur_opt);
+ cur_opt = def_opt;
+ c_found = f_found = y_found = false;
+ }
+ y_found = true;
+ cur_opt.destination = OutputOption::DEST_SYSLOG;
+ cur_opt.facility = optarg;
+ break;
+
+ case 'z': // Maximum size
+ if (! f_found) {
+ std::cerr << "Attempt to set file size (-z) "
+ "outside of file output specification\n";
+ return (1);
+ }
+ try {
+ cur_opt.maxsize = boost::lexical_cast<size_t>(optarg);
+ } catch (boost::bad_lexical_cast&) {
+ std::cerr << "File size (-z) argument must be a positive "
+ "integer\n";
+ return (1);
}
break;
+
default:
std::cerr << "Unrecognised option: " <<
static_cast<char>(option) << "\n";
return (1);
}
+
+ // Have found at least one command-line switch, so note the fact.
+ sw_found = true;
}
- // Update the logging parameters. If no output options
- // were set, the defaults will be used.
- spec.addOutputOption(outopt);
+ // Add the current (unfinished specification) to the list.
+ cur_spec.addOutputOption(cur_opt);
+ loggers.push_back(cur_spec);
- // Set the logging options for the root logger.
- LoggerManager manager;
- manager.process(spec);
+ // Set the logging options.
+ manager.process(loggers.begin(), loggers.end());
// Set the local file
if (optind < argc) {
LoggerManager::readLocalMessageFile(argv[optind]);
}
+ // Log a few messages to different loggers.
+ isc::log::Logger logger_ex(ROOT_NAME);
+ isc::log::Logger logger_alpha("alpha");
+ isc::log::Logger logger_beta("beta");
- // Log a few messages
- isc::log::Logger logger_dlm("dlm");
- isc::log::Logger logger_ex("example");
LOG_FATAL(logger_ex, MSG_WRITERR).arg("test1").arg("42");
LOG_ERROR(logger_ex, MSG_RDLOCMES).arg("dummy/file");
- LOG_WARN(logger_dlm, MSG_READERR).arg("a.txt").arg("dummy reason");
- LOG_INFO(logger_dlm, MSG_OPENIN).arg("example.msg").arg("dummy reason");
- LOG_DEBUG(logger_ex, 0, MSG_RDLOCMES).arg("dummy/0");
- LOG_DEBUG(logger_ex, 24, MSG_RDLOCMES).arg("dummy/24");
- LOG_DEBUG(logger_ex, 25, MSG_RDLOCMES).arg("dummy/25");
- LOG_DEBUG(logger_ex, 26, MSG_RDLOCMES).arg("dummy/26");
+ LOG_WARN(logger_ex, MSG_BADSTREAM).arg("example");
+ LOG_WARN(logger_alpha, MSG_READERR).arg("a.txt").arg("dummy reason");
+ LOG_INFO(logger_alpha, MSG_OPENIN).arg("example.msg").arg("dummy reason");
+ LOG_DEBUG(logger_ex, 0, MSG_RDLOCMES).arg("example/0");
+ LOG_DEBUG(logger_ex, 24, MSG_RDLOCMES).arg("example/24");
+ LOG_DEBUG(logger_ex, 25, MSG_RDLOCMES).arg("example/25");
+ LOG_DEBUG(logger_ex, 26, MSG_RDLOCMES).arg("example/26");
+ LOG_FATAL(logger_beta, MSG_BADSEVERITY).arg("beta_fatal");
+ LOG_ERROR(logger_beta, MSG_BADDESTINATION).arg("beta_error");
+ LOG_WARN(logger_beta, MSG_BADSTREAM).arg("beta_warn");
+ LOG_INFO(logger_beta, MSG_READERR).arg("beta").arg("info");
+ LOG_DEBUG(logger_beta, 25, MSG_BADSEVERITY).arg("beta/25");
+ LOG_DEBUG(logger_beta, 26, MSG_BADSEVERITY).arg("beta/26");
return (0);
}
diff --git a/src/lib/log/tests/severity_test.sh.in b/src/lib/log/tests/severity_test.sh.in
index cd8c1b9..8fe6cc4 100755
--- a/src/lib/log/tests/severity_test.sh.in
+++ b/src/lib/log/tests/severity_test.sh.in
@@ -35,31 +35,44 @@ passfail() {
echo "1. runInitTest default parameters: "
cat > $tempfile << .
-FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
-ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
-WARN [alpha.dlm] MSG_READERR, error reading from message file a.txt: dummy reason
-INFO [alpha.dlm] MSG_OPENIN, unable to open message file example.msg for input: dummy reason
+FATAL [example] MSG_WRITERR, error writing to test1: 42
+ERROR [example] MSG_RDLOCMES, reading local message file dummy/file
+WARN [example] MSG_BADSTREAM, bad log console output stream: example
+WARN [example.alpha] MSG_READERR, error reading from message file a.txt: dummy reason
+INFO [example.alpha] MSG_OPENIN, unable to open message file example.msg for input: dummy reason
+FATAL [example.beta] MSG_BADSEVERITY, unrecognized log severity: beta_fatal
+ERROR [example.beta] MSG_BADDESTINATION, unrecognized log destination: beta_error
+WARN [example.beta] MSG_BADSTREAM, bad log console output stream: beta_warn
+INFO [example.beta] MSG_READERR, error reading from message file beta: info
.
./logger_example -c stdout | cut -d' ' -f3- | diff $tempfile -
passfail $?
echo "2. Severity filter: "
cat > $tempfile << .
-FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
-ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
+FATAL [example] MSG_WRITERR, error writing to test1: 42
+ERROR [example] MSG_RDLOCMES, reading local message file dummy/file
+FATAL [example.beta] MSG_BADSEVERITY, unrecognized log severity: beta_fatal
+ERROR [example.beta] MSG_BADDESTINATION, unrecognized log destination: beta_error
.
./logger_example -c stdout -s error | cut -d' ' -f3- | diff $tempfile -
passfail $?
echo "3. Debug level: "
cat > $tempfile << .
-FATAL [alpha.example] MSG_WRITERR, error writing to test1: 42
-ERROR [alpha.example] MSG_RDLOCMES, reading local message file dummy/file
-WARN [alpha.dlm] MSG_READERR, error reading from message file a.txt: dummy reason
-INFO [alpha.dlm] MSG_OPENIN, unable to open message file example.msg for input: dummy reason
-DEBUG [alpha.example] MSG_RDLOCMES, reading local message file dummy/0
-DEBUG [alpha.example] MSG_RDLOCMES, reading local message file dummy/24
-DEBUG [alpha.example] MSG_RDLOCMES, reading local message file dummy/25
+FATAL [example] MSG_WRITERR, error writing to test1: 42
+ERROR [example] MSG_RDLOCMES, reading local message file dummy/file
+WARN [example] MSG_BADSTREAM, bad log console output stream: example
+WARN [example.alpha] MSG_READERR, error reading from message file a.txt: dummy reason
+INFO [example.alpha] MSG_OPENIN, unable to open message file example.msg for input: dummy reason
+DEBUG [example] MSG_RDLOCMES, reading local message file example/0
+DEBUG [example] MSG_RDLOCMES, reading local message file example/24
+DEBUG [example] MSG_RDLOCMES, reading local message file example/25
+FATAL [example.beta] MSG_BADSEVERITY, unrecognized log severity: beta_fatal
+ERROR [example.beta] MSG_BADDESTINATION, unrecognized log destination: beta_error
+WARN [example.beta] MSG_BADSTREAM, bad log console output stream: beta_warn
+INFO [example.beta] MSG_READERR, error reading from message file beta: info
+DEBUG [example.beta] MSG_BADSEVERITY, unrecognized log severity: beta/25
.
./logger_example -c stdout -s debug -d 25 | cut -d' ' -f3- | diff $tempfile -
passfail $?
More information about the bind10-changes
mailing list