BIND 10 master, updated. ff69cf49ecc375485209da7caabea778b5ff1ca2 [trac555] Update ChangeLog
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Jun 3 09:36:22 UTC 2011
The branch, master has been updated
via ff69cf49ecc375485209da7caabea778b5ff1ca2 (commit)
via 38b3546867425bd64dbc5920111a843a3330646b (commit)
via 4e058c0c696584bac4b299f241ca5e74d7121b06 (commit)
via a61bc91e4109168327481710f17affe728af80d5 (commit)
via c58ee77ef68b2cf49db6af85ede886580ad2b6bc (commit)
via 601d7f0170b1f9f929acadd3c37d60c5876ca7be (commit)
via ef8b3f326fe9ab9aab0050071c6f8975b8ecd354 (commit)
via 51f6bda14d754aa6aea474300c8c51f15f32f0be (commit)
via 711a621387d48993712031be9164510de7b27054 (commit)
via 4948469dafe0a5ff130706ff2fb13676c417a538 (commit)
via 2626464bbbb35e29f01a7e5a532d06da8feef837 (commit)
via 83a82bdac7711760eed682b91f6be4435606a0dd (commit)
via 616019706c0101316835f85843c59439e20a1c8e (commit)
via cb6be8450ae82e705dc4c65ca4415b1ed77abd6b (commit)
via 99a107f4ab33c0791df351408c76c07f5820cde5 (commit)
via f843346fdfc748cb5b67d079958202c8d4e32e0c (commit)
via 39238e406f2e0cdd63a71f4b4b8700988e1dac9e (commit)
via 1a32f61cafb9f735815bf8f4abb0d8e1019269c3 (commit)
via f3395938a1ead66ef30ab1d261e3a38fea16faa4 (commit)
via 36e95aa1164d24b5b2c46d64958c709a9a02fd51 (commit)
via 0692e63e77ba5f6e1dd24619f215c06a53a48845 (commit)
via c9d69c549110808b6314bac44b357b4f0fb2b699 (commit)
via fd99c6922384541b484e5e3ac4422d8472011b42 (commit)
via 475624c79f83adc6befd4d631eeaf83d83fe89f9 (commit)
via 3d05a83e9466e6075dec6e4b7a1502989d9205e9 (commit)
via acfbd3b209c50aeff46fc09f9d792a457f51722d (commit)
via 9e48d735ae41dd79b6ff856ea4e5ba79112f440c (commit)
via cfa31a99243065c40dc3f5a6393bb8ec923d2bd2 (commit)
via fae2d0d5854141a9af7c1177c663a0910ab18ad0 (commit)
via 74402ae4cf3274fb20bc3183941c4099dc672b89 (commit)
via 58ec390c5c70c0c7625e3f52caf4c4f20b3bffa3 (commit)
via 34ebe17e3d731f19c6c44a8777b994241b5de7ee (commit)
via 67c6c4489b2daeb6001cf2f462cc189f2c841b5a (commit)
from ec4ebeb8ecfae6b0e3cc6fedabb7e2f84509c930 (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 ff69cf49ecc375485209da7caabea778b5ff1ca2
Author: Stephen Morris <stephen at isc.org>
Date: Fri Jun 3 10:33:32 2011 +0100
[trac555] Update ChangeLog
commit 38b3546867425bd64dbc5920111a843a3330646b
Merge: 4e058c0c696584bac4b299f241ca5e74d7121b06 ec4ebeb8ecfae6b0e3cc6fedabb7e2f84509c930
Author: Stephen Morris <stephen at isc.org>
Date: Fri Jun 3 10:29:19 2011 +0100
[trac555] Merge branch 'master' into trac555
Conflicts:
src/lib/log/tests/Makefile.am
src/lib/log/tests/logger_unittest.cc
src/lib/log/tests/run_unittests.cc
commit 4e058c0c696584bac4b299f241ca5e74d7121b06
Author: Stephen Morris <stephen at isc.org>
Date: Thu Jun 2 14:10:18 2011 +0100
[trac555] Header comment changes as a result of review
commit a61bc91e4109168327481710f17affe728af80d5
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 14:47:30 2011 +0100
[trac555] Remove redundant test class from OutputOption
... and convert from using TEST_F to TEST.
commit c58ee77ef68b2cf49db6af85ede886580ad2b6bc
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 14:43:44 2011 +0100
[trac555] Remove redundant test class from LoggerSpecification unit tests
... and correct error in previous commit.
commit 601d7f0170b1f9f929acadd3c37d60c5876ca7be
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 14:32:46 2011 +0100
[trac555] Don't automatically unlink temporary file after creation
commit ef8b3f326fe9ab9aab0050071c6f8975b8ecd354
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 14:18:48 2011 +0100
[trac555] Move definition of UnknownLoggingDestination to header file
commit 51f6bda14d754aa6aea474300c8c51f15f32f0be
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 13:33:15 2011 +0100
[trac555] Comment update.
commit 711a621387d48993712031be9164510de7b27054
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 13:28:48 2011 +0100
[trac555] Clarify comments
commit 4948469dafe0a5ff130706ff2fb13676c417a538
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 12:27:15 2011 +0100
[trac555] Simplfy and clarify header comment for process()
commit 2626464bbbb35e29f01a7e5a532d06da8feef837
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 12:14:50 2011 +0100
[trac555] Change to message formatting if catching MessageException
Also add test to check that an exception is generated if there is
a failure to access a local message file.
commit 83a82bdac7711760eed682b91f6be4435606a0dd
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 11:03:52 2011 +0100
[trac555] Updated comments concerining duplicate/unknown messages
commit 616019706c0101316835f85843c59439e20a1c8e
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 10:48:33 2011 +0100
[trac555] Move LoggerManagerImpl::processEnd() to the correct file
commit cb6be8450ae82e705dc4c65ca4415b1ed77abd6b
Author: Stephen Morris <stephen at isc.org>
Date: Wed Jun 1 10:39:28 2011 +0100
[trac555] Log message if error converting a DEBUG level from a string
commit 99a107f4ab33c0791df351408c76c07f5820cde5
Author: Stephen Morris <stephen at isc.org>
Date: Fri May 27 19:54:17 2011 +0100
[trac555] Expand comments in logger implementation header file
commit f843346fdfc748cb5b67d079958202c8d4e32e0c
Author: Stephen Morris <stephen at isc.org>
Date: Fri May 27 19:13:33 2011 +0100
[trac555] Get name of directory for temporary files at build time
The configure script now writes the name of the directory for
temporary files into a .h file at configure time (instead of /tmp
being assumed).
commit 39238e406f2e0cdd63a71f4b4b8700988e1dac9e
Author: Stephen Morris <stephen at isc.org>
Date: Fri May 27 16:24:50 2011 +0100
[trac555] Update tests
* Move reset() method to logger_manager (and _impl) and remove from the general
logger classes.
* Correct problem whereby some messages went to stdout and some to stderr.
* Split the shell file testing into separate files, each testing one aspect of
the logger.
commit 1a32f61cafb9f735815bf8f4abb0d8e1019269c3
Author: Stephen Morris <stephen at isc.org>
Date: Fri May 27 14:50:02 2011 +0100
[trac555] Ensure text of messages starts with lowercase character
commit f3395938a1ead66ef30ab1d261e3a38fea16faa4
Author: Stephen Morris <stephen at isc.org>
Date: Fri May 27 14:41:22 2011 +0100
[trac555] Reorganisation of stand-along logger tests
Renamed the logger_support_test program to the more descriptive
(and accurate) logger_example, and separated out the different
tests into different shell scripts.
commit 36e95aa1164d24b5b2c46d64958c709a9a02fd51
Author: Stephen Morris <stephen at isc.org>
Date: Fri May 27 14:13:34 2011 +0100
[trac555] Use getSeverity() instead of explicitly checking severity string
commit 0692e63e77ba5f6e1dd24619f215c06a53a48845
Author: Jelte Jansen <jelte at isc.org>
Date: Fri May 27 13:22:17 2011 +0200
[trac555] move getDestination to logger_level
commit c9d69c549110808b6314bac44b357b4f0fb2b699
Author: Jelte Jansen <jelte at isc.org>
Date: Fri May 27 12:41:59 2011 +0200
[trac555] added conversionfunctions from str to the different enums
commit fd99c6922384541b484e5e3ac4422d8472011b42
Author: Stephen Morris <stephen at isc.org>
Date: Fri May 27 09:56:39 2011 +0100
[trac555] Fix typo
commit 475624c79f83adc6befd4d631eeaf83d83fe89f9
Author: Stephen Morris <stephen at isc.org>
Date: Thu May 26 17:45:17 2011 +0100
[trac555] Added shell-based unit test for console appender
commit 3d05a83e9466e6075dec6e4b7a1502989d9205e9
Author: Stephen Morris <stephen at isc.org>
Date: Thu May 26 16:53:46 2011 +0100
[trac555] Add file appender
Added the file appender, which routes output to a file (appending
to a file if one exists).
commit acfbd3b209c50aeff46fc09f9d792a457f51722d
Author: Stephen Morris <stephen at isc.org>
Date: Thu May 26 16:08:24 2011 +0100
[trac555] Get root logger name from global setting
The root logger name is now obtained from the global variable
accessed by get/setRootLoggerName().
Also, the console appender now provides the correct pattern.
commit 9e48d735ae41dd79b6ff856ea4e5ba79112f440c
Author: Stephen Morris <stephen at isc.org>
Date: Thu May 26 15:50:30 2011 +0100
[trac555] Move logging initialization to LoggerManager
This is the global object that controls the logging system, so
it is logical that initialization is done here instead of in the
Logger class (which controls the operation of one logger).
commit cfa31a99243065c40dc3f5a6393bb8ec923d2bd2
Author: Stephen Morris <stephen at isc.org>
Date: Thu May 26 14:13:34 2011 +0100
[trac555] Checkpoint
Added basic logger manager and its implementation, plus an untested
console appender. Also modified logger_support_test to use that
appender and have got part way through creating a file logger test.
commit fae2d0d5854141a9af7c1177c663a0910ab18ad0
Author: Jelte Jansen <jelte at isc.org>
Date: Wed May 25 11:45:14 2011 +0200
[trac555] some fixes to make it compile
commit 74402ae4cf3274fb20bc3183941c4099dc672b89
Author: Jelte Jansen <jelte at isc.org>
Date: Wed May 25 10:45:34 2011 +0200
[trac555] fixed small header guard typo
commit 58ec390c5c70c0c7625e3f52caf4c4f20b3bffa3
Author: Stephen Morris <stephen at isc.org>
Date: Mon May 23 18:53:24 2011 +0100
[trac555] Checkpoint
Checkpoint of work at end of 23 May (so that code is copied down to
the BIND 10 server). Work is in progress on the logger manager
implementation class.
commit 34ebe17e3d731f19c6c44a8777b994241b5de7ee
Author: Stephen Morris <stephen at isc.org>
Date: Mon May 23 16:26:24 2011 +0100
[trac555] Add LoggerSpecification class and associated tests
commit 67c6c4489b2daeb6001cf2f462cc189f2c841b5a
Author: Stephen Morris <stephen at isc.org>
Date: Mon May 23 15:42:08 2011 +0100
[trac555] Added OutputOption structure and test
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 4 +
configure.ac | 9 +-
src/lib/log/Makefile.am | 8 +-
src/lib/log/impldef.cc | 29 ++
src/lib/log/impldef.h | 18 +
src/lib/log/impldef.mes | 38 +++
src/lib/log/log_formatter.h | 30 ++-
src/lib/log/logger.cc | 10 +-
src/lib/log/logger.h | 6 -
src/lib/log/logger_impl.cc | 82 +-----
src/lib/log/logger_impl.h | 24 --
.../log/{root_logger_name.cc => logger_level.cc} | 46 ++--
src/lib/log/logger_level.h | 14 +
src/lib/log/logger_level_impl.cc | 31 ++-
src/lib/log/logger_manager.cc | 155 ++++++++++
src/lib/log/logger_manager.h | 142 +++++++++
src/lib/log/logger_manager_impl.cc | 198 ++++++++++++
src/lib/log/logger_manager_impl.h | 158 ++++++++++
src/lib/log/logger_specification.h | 156 ++++++++++
src/lib/log/logger_support.cc | 106 +------
src/lib/log/logger_support.h | 7 +-
src/lib/log/messagedef.cc | 8 +-
src/lib/log/messagedef.h | 5 +-
src/lib/log/messagedef.mes | 12 +
src/lib/log/output_option.cc | 54 ++++
src/lib/log/output_option.h | 85 +++++
src/lib/log/tests/Makefile.am | 40 ++-
src/lib/log/tests/console_test.sh.in | 68 ++++
..._time_init_test.sh.in => local_file_test.sh.in} | 59 ++--
src/lib/log/tests/logger_example.cc | 176 +++++++++++
src/lib/log/tests/logger_level_unittest.cc | 45 +++-
src/lib/log/tests/logger_manager_unittest.cc | 325 ++++++++++++++++++++
src/lib/log/tests/logger_specification_unittest.cc | 96 ++++++
src/lib/log/tests/logger_support_test.cc | 106 -------
src/lib/log/tests/logger_unittest.cc | 48 +---
src/lib/log/tests/output_option_unittest.cc | 66 ++++
src/lib/log/tests/run_unittests.cc | 3 +
...un_time_init_test.sh.in => severity_test.sh.in} | 55 ++--
.../run_unittests.cc => log/tests/tempdir.h.in} | 20 +-
39 files changed, 2045 insertions(+), 497 deletions(-)
create mode 100644 src/lib/log/impldef.cc
create mode 100644 src/lib/log/impldef.h
create mode 100644 src/lib/log/impldef.mes
copy src/lib/log/{root_logger_name.cc => logger_level.cc} (52%)
create mode 100644 src/lib/log/logger_manager.cc
create mode 100644 src/lib/log/logger_manager.h
create mode 100644 src/lib/log/logger_manager_impl.cc
create mode 100644 src/lib/log/logger_manager_impl.h
create mode 100644 src/lib/log/logger_specification.h
create mode 100644 src/lib/log/output_option.cc
create mode 100644 src/lib/log/output_option.h
create mode 100755 src/lib/log/tests/console_test.sh.in
copy src/lib/log/tests/{run_time_init_test.sh.in => local_file_test.sh.in} (57%)
create mode 100644 src/lib/log/tests/logger_example.cc
create mode 100644 src/lib/log/tests/logger_manager_unittest.cc
create mode 100644 src/lib/log/tests/logger_specification_unittest.cc
delete mode 100644 src/lib/log/tests/logger_support_test.cc
create mode 100644 src/lib/log/tests/output_option_unittest.cc
rename src/lib/log/tests/{run_time_init_test.sh.in => severity_test.sh.in} (59%)
copy src/lib/{server_common/tests/run_unittests.cc => log/tests/tempdir.h.in} (74%)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index e916e1b..cc956eb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+248. [func] stephen
+ Add file and stderr as destinations for logging.
+ (Trac555, git 38b3546867425bd64dbc5920111a843a3330646b)
+
247. [func] jelte
Upstream queries from the resolver now set EDNS0 buffer size.
(Trac834, git 48e10c2530fe52c9bde6197db07674a851aa0f5d)
diff --git a/configure.ac b/configure.ac
index 1ec06c6..3d85931 100644
--- a/configure.ac
+++ b/configure.ac
@@ -890,7 +890,10 @@ AC_OUTPUT([doc/version.ent
src/lib/dns/tests/testdata/gen-wiredata.py
src/lib/cc/session_config.h.pre
src/lib/cc/tests/session_unittests_config.h
- src/lib/log/tests/run_time_init_test.sh
+ src/lib/log/tests/console_test.sh
+ src/lib/log/tests/local_file_test.sh
+ src/lib/log/tests/severity_test.sh
+ src/lib/log/tests/tempdir.h
src/lib/util/python/mkpywrapper.py
src/lib/server_common/tests/data_path.h
tests/system/conf.sh
@@ -917,7 +920,9 @@ AC_OUTPUT([doc/version.ent
chmod +x src/bin/msgq/tests/msgq_test
chmod +x src/lib/dns/gen-rdatacode.py
chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
- chmod +x src/lib/log/tests/run_time_init_test.sh
+ 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/severity_test.sh
chmod +x src/lib/util/python/mkpywrapper.py
chmod +x tests/system/conf.sh
])
diff --git a/src/lib/log/Makefile.am b/src/lib/log/Makefile.am
index cdc0642..c9e5173 100644
--- a/src/lib/log/Makefile.am
+++ b/src/lib/log/Makefile.am
@@ -8,12 +8,16 @@ CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = liblog.la
liblog_la_SOURCES =
liblog_la_SOURCES += dummylog.h dummylog.cc
+liblog_la_SOURCES += impldef.cc impldef.h
liblog_la_SOURCES += log_formatter.h log_formatter.cc
liblog_la_SOURCES += logger.cc logger.h
liblog_la_SOURCES += logger_impl.cc logger_impl.h
liblog_la_SOURCES += logger_level.h
-liblog_la_SOURCES += logger_level.h
+liblog_la_SOURCES += logger_level.cc logger_level.h
liblog_la_SOURCES += logger_level_impl.cc logger_level_impl.h
+liblog_la_SOURCES += logger_manager.cc logger_manager.h
+liblog_la_SOURCES += logger_manager_impl.cc logger_manager_impl.h
+liblog_la_SOURCES += logger_specification.h
liblog_la_SOURCES += logger_support.cc logger_support.h
liblog_la_SOURCES += macros.h
liblog_la_SOURCES += messagedef.cc messagedef.h
@@ -22,9 +26,11 @@ liblog_la_SOURCES += message_exception.h
liblog_la_SOURCES += message_initializer.cc message_initializer.h
liblog_la_SOURCES += message_reader.cc message_reader.h
liblog_la_SOURCES += message_types.h
+liblog_la_SOURCES += output_option.cc output_option.h
liblog_la_SOURCES += root_logger_name.cc root_logger_name.h
EXTRA_DIST = README
+EXTRA_DIST += impldef.mes
EXTRA_DIST += messagedef.mes
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
diff --git a/src/lib/log/impldef.cc b/src/lib/log/impldef.cc
new file mode 100644
index 0000000..087ebea
--- /dev/null
+++ b/src/lib/log/impldef.cc
@@ -0,0 +1,29 @@
+// File created from impldef.mes on Wed Jun 1 10:32:57 2011
+
+#include <cstddef>
+#include <log/message_types.h>
+#include <log/message_initializer.h>
+
+namespace isc {
+namespace log {
+
+extern const isc::log::MessageID LOGIMPL_ABOVEDBGMAX = "LOGIMPL_ABOVEDBGMAX";
+extern const isc::log::MessageID LOGIMPL_BADDEBUG = "LOGIMPL_BADDEBUG";
+extern const isc::log::MessageID LOGIMPL_BELOWDBGMIN = "LOGIMPL_BELOWDBGMIN";
+
+} // namespace log
+} // namespace isc
+
+namespace {
+
+const char* values[] = {
+ "LOGIMPL_ABOVEDBGMAX", "debug level of %1 is too high and will be set to the maximum of %2",
+ "LOGIMPL_BADDEBUG", "debug string is '%1': must be of the form DEBUGn",
+ "LOGIMPL_BELOWDBGMIN", "debug level of %1 is too low and will be set to the minimum of %2",
+ NULL
+};
+
+const isc::log::MessageInitializer initializer(values);
+
+} // Anonymous namespace
+
diff --git a/src/lib/log/impldef.h b/src/lib/log/impldef.h
new file mode 100644
index 0000000..7c70996
--- /dev/null
+++ b/src/lib/log/impldef.h
@@ -0,0 +1,18 @@
+// File created from impldef.mes on Wed Jun 1 10:32:57 2011
+
+#ifndef __IMPLDEF_H
+#define __IMPLDEF_H
+
+#include <log/message_types.h>
+
+namespace isc {
+namespace log {
+
+extern const isc::log::MessageID LOGIMPL_ABOVEDBGMAX;
+extern const isc::log::MessageID LOGIMPL_BADDEBUG;
+extern const isc::log::MessageID LOGIMPL_BELOWDBGMIN;
+
+} // namespace log
+} // namespace isc
+
+#endif // __IMPLDEF_H
diff --git a/src/lib/log/impldef.mes b/src/lib/log/impldef.mes
new file mode 100644
index 0000000..93e9fab
--- /dev/null
+++ b/src/lib/log/impldef.mes
@@ -0,0 +1,38 @@
+# 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 Logger Implementation Messages
+#
+# This holds messages generated by the underlying logger implementation. They
+# are likely to be specific to that implementation, and may well change if the
+# underlying implementation is changed. For that reason, they have been put
+# in a separate file.
+
+$PREFIX LOGIMPL_
+$NAMESPACE isc::log
+
+% ABOVEDBGMAX debug level of %1 is too high and will be set to the maximum of %2
+A message from the underlying logger implementation code, the debug level
+(as set by the string DEBGUGn) is above the maximum allowed value and has
+been reduced to that value.
+
+% BADDEBUG debug string is '%1': must be of the form DEBUGn
+The string indicating the extended logging level (used by the underlying
+logger implementation code) is not of the stated form. In particular,
+it starts DEBUG but does not end with an integer.
+
+% BELOWDBGMIN debug level of %1 is too low and will be set to the minimum of %2
+A message from the underlying logger implementation code, the debug level
+(as set by the string DEBGUGn) is below the minimum allowed value and has
+been increased to that value.
diff --git a/src/lib/log/log_formatter.h b/src/lib/log/log_formatter.h
index 3833a4b..c81d4ea 100644
--- a/src/lib/log/log_formatter.h
+++ b/src/lib/log/log_formatter.h
@@ -15,7 +15,9 @@
#ifndef __LOG_FORMATTER_H
#define __LOG_FORMMATER_H
+#include <cstddef>
#include <string>
+#include <iostream>
#include <boost/lexical_cast.hpp>
#include <log/logger_level.h>
@@ -84,7 +86,6 @@ private:
/// \brief Which will be the next placeholder to replace
unsigned nextPlaceholder_;
- Formatter& operator =(const Formatter& other);
public:
/// \brief Constructor of "active" formatter
@@ -108,12 +109,18 @@ public:
{
}
+ /// \brief Copy constructor
+ ///
+ /// "Control" is passed to the created object in that it is the created object
+ /// that will have responsibility for outputting the formatted message - the
+ /// object being copied relinquishes that responsibility.
Formatter(const Formatter& other) :
logger_(other.logger_), severity_(other.severity_),
message_(other.message_), nextPlaceholder_(other.nextPlaceholder_)
{
- other.logger_ = false;
+ other.logger_ = NULL;
}
+
/// \brief Destructor.
//
/// This is the place where output happens if the formatter is active.
@@ -123,6 +130,23 @@ public:
delete message_;
}
}
+
+ /// \brief Assignment operator
+ ///
+ /// Essentially the same function as the assignment operator - the object being
+ /// assigned to takes responsibility for outputting the message.
+ Formatter& operator =(const Formatter& other) {
+ if (&other != this) {
+ logger_ = other.logger_;
+ severity_ = other.severity_;
+ message_ = other.message_;
+ nextPlaceholder_ = other.nextPlaceholder_;
+ other.logger_ = NULL;
+ }
+
+ return *this;
+ }
+
/// \brief Replaces another placeholder
///
/// Replaces another placeholder and returns a new formatter with it.
@@ -137,6 +161,7 @@ public:
return (*this);
}
}
+
/// \brief String version of arg.
Formatter& arg(const std::string& arg) {
if (logger_) {
@@ -154,6 +179,7 @@ public:
}
return (*this);
}
+
};
}
diff --git a/src/lib/log/logger.cc b/src/lib/log/logger.cc
index fdca964..7495dcc 100644
--- a/src/lib/log/logger.cc
+++ b/src/lib/log/logger.cc
@@ -28,8 +28,7 @@ using namespace std;
namespace isc {
namespace log {
-// Initialize Logger implementation. Does not check whether the implementation
-// has already been initialized - that was done by the caller (getLoggerPtr()).
+// Initialize Logger.
void Logger::initLoggerImpl() {
loggerptr_ = new LoggerImpl(name_);
}
@@ -173,12 +172,5 @@ Logger::operator==(Logger& other) {
return (*getLoggerPtr() == *other.getLoggerPtr());
}
-// Reset (used in testing only). This is a static method.
-
-void
-Logger::reset() {
- LoggerImpl::reset();
-}
-
} // namespace log
} // namespace isc
diff --git a/src/lib/log/logger.h b/src/lib/log/logger.h
index 94c6c94..e2a1439 100644
--- a/src/lib/log/logger.h
+++ b/src/lib/log/logger.h
@@ -152,12 +152,6 @@ public:
/// \return true if the logger objects are instances of the same logger.
bool operator==(Logger& other);
-protected:
- /// \brief Clear logging hierachy
- ///
- /// This is for test use only, hence is protected.
- static void reset();
-
private:
friend class isc::log::Formatter<Logger>;
diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc
index 46a3a13..6ab7b2c 100644
--- a/src/lib/log/logger_impl.cc
+++ b/src/lib/log/logger_impl.cc
@@ -12,6 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE
+#include <iostream>
#include <iomanip>
#include <algorithm>
@@ -33,7 +34,7 @@
#include <util/strutil.h>
-// Note: as log4cplus and th3e BIND 10 logger have many concepts in common, and
+// Note: as log4cplus and the BIND 10 logger have many concepts in common, and
// thus many similar names, to disambiguate types we don't "use" the log4cplus
// namespace: instead, all log4cplus types are explicitly qualified.
@@ -49,9 +50,6 @@ namespace log {
LoggerImpl::LoggerImpl(const string& name) :
logger_(log4cplus::Logger::getRoot())
{
- // Initialize log4cplus if not already done
- initLog4cplus();
-
// Are we the root logger?
if (name == getRootLoggerName()) {
name_ = name;
@@ -137,81 +135,5 @@ LoggerImpl::outputRaw(const Severity& severity, const string& message) {
}
}
-// Initialization. This is one initialization for all loggers, so requires
-// a singleton to hold the initialization flag. The flag is held within a
-// static method to ensure that it is created (and initialized) when needed.
-// This avoids a static initialization fiasco.
-
-bool&
-LoggerImpl::initialized() {
- static bool initialized = false;
- return (initialized);
-}
-
-void
-LoggerImpl::initLog4cplus() {
-
- if (! initialized()) {
-
- // Set up basic configurator. This attaches a ConsoleAppender to the
- // root logger with suitable output. This is used until we we have
- // actually read the logging configuration, in which case the output
- // may well be changed.
- log4cplus::BasicConfigurator config;
- config.configure();
- setRootAppenderLayout();
-
- // Add additional debug levels
- LoggerLevelImpl::init();
-
- // All done.
- initialized() = true;
- }
-}
-
-void LoggerImpl::setRootAppenderLayout() {
-
- // 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");
-
- // Retrieve the appenders on the root instance and set the layout to
- // use that pattern.
- log4cplus::SharedAppenderPtrList list =
- log4cplus::Logger::getRoot().getAllAppenders();
-
- for (log4cplus::SharedAppenderPtrList::iterator i = list.begin();
- i != list.end(); ++i) {
- auto_ptr<log4cplus::Layout> layout(
- new log4cplus::PatternLayout(pattern));
- (*i)->setLayout(layout);
- }
-}
-
-// Reset. Just reset logger hierarchy to default settings (don't remove the
-// loggers - this appears awkward); this is effectively the same as removing
-// them.
-void
-LoggerImpl::reset() {
- log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
- initialized() = false;
-
- // N.B. The documentation is not clear, but it does not appear that the
- // methods used to format the new logging levels are removed from the
- // log4cxx LogLevelManager class - indeed, there appears to be no way
- // to do this. This would seem to suggest that a re-initialization may
- // well add another instance of the toString/fromString to the manager's
- // list of methods.
- //
- // We could get round this by making setting the LogManager a truly
- // one-shot process. However, apart from taking up memory there is little
- // overhead if multiple instances are added. The manager walks the list and
- // uses the first method that processes the argument, so multiple methods
- // doing the same think will not affect functionality. Besides, this
- // reset() method is only used in testing and not in the distributed
- // software.
-}
-
-
} // namespace log
} // namespace isc
diff --git a/src/lib/log/logger_impl.h b/src/lib/log/logger_impl.h
index f655c55..3c7c83d 100644
--- a/src/lib/log/logger_impl.h
+++ b/src/lib/log/logger_impl.h
@@ -184,31 +184,7 @@ public:
return (name_ == other.name_);
}
- /// \brief Reset logging
- ///
- /// Resets (clears) the log4cplus logging, requiring that an initialization
- /// call be performed again.
- static void reset();
-
-
private:
-
- /// \brief Initialize log4cplus
- ///
- /// Static method to perform initialization of the log4cplus system.
- static void initLog4cplus();
-
- /// \brief Initialization Flag
- ///
- /// Static method to access an initialization flag. Doing it this
- /// way means that there is no static initialization fiasco.
- static bool& initialized();
-
- /// \brief Set layout pattern
- ///
- /// Sets the layout for root logger appender(s)
- static void setRootAppenderLayout();
-
std::string name_; ///< Full name of this logger
log4cplus::Logger logger_; ///< Underlying log4cplus logger
};
diff --git a/src/lib/log/logger_level.cc b/src/lib/log/logger_level.cc
new file mode 100644
index 0000000..aa2b944
--- /dev/null
+++ b/src/lib/log/logger_level.cc
@@ -0,0 +1,46 @@
+// 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
+
+#include <log/logger_level.h>
+#include <log/macros.h>
+#include <log/messagedef.h>
+
+#include <boost/algorithm/string.hpp>
+
+
+namespace isc {
+namespace log {
+
+isc::log::Severity
+getSeverity(const std::string& sev_str) {
+ if (boost::iequals(sev_str, "DEBUG")) {
+ return isc::log::DEBUG;
+ } else if (boost::iequals(sev_str, "INFO")) {
+ return isc::log::INFO;
+ } else if (boost::iequals(sev_str, "WARN")) {
+ return isc::log::WARN;
+ } else if (boost::iequals(sev_str, "ERROR")) {
+ return isc::log::ERROR;
+ } else if (boost::iequals(sev_str, "FATAL")) {
+ return isc::log::FATAL;
+ } else {
+ Logger logger("log");
+ LOG_ERROR(logger, MSG_BADSEVERITY).arg(sev_str);
+ return isc::log::INFO;
+ }
+}
+
+
+} // namespace log
+} // namespace isc
diff --git a/src/lib/log/logger_level.h b/src/lib/log/logger_level.h
index 673fd87..dab8393 100644
--- a/src/lib/log/logger_level.h
+++ b/src/lib/log/logger_level.h
@@ -15,6 +15,8 @@
#ifndef __LOGGER_LEVEL_H
#define __LOGGER_LEVEL_H
+#include <string>
+
namespace isc {
namespace log {
@@ -56,6 +58,18 @@ struct Level {
// Default assignment and copy constructor is appropriate
};
+/// \brief Returns the isc::log::Severity value represented by the
+/// given string
+///
+/// If the string is not recognized, returns isc::log::DEBUG.
+/// This must be one of the strings "DEBUG", "INFO", "WARN", "ERROR",
+/// "FATAL". (Must be upper case and must not contain leading or
+/// trailing spaces.)
+///
+/// \param sev_str The string representing severity value
+/// \return The severity
+isc::log::Severity getSeverity(const std::string& sev_str);
+
} // namespace log
} // namespace isc
diff --git a/src/lib/log/logger_level_impl.cc b/src/lib/log/logger_level_impl.cc
index 7c98977..d6d8ed7 100644
--- a/src/lib/log/logger_level_impl.cc
+++ b/src/lib/log/logger_level_impl.cc
@@ -18,12 +18,19 @@
#include <boost/lexical_cast.hpp>
#include <log4cplus/logger.h>
+
+#include <log/impldef.h>
#include <log/logger_level.h>
#include <log/logger_level_impl.h>
+#include <log/macros.h>
using namespace log4cplus;
using namespace std;
+namespace {
+isc::log::Logger logger("log");
+}
+
namespace isc {
namespace log {
@@ -87,7 +94,8 @@ LoggerLevelImpl::convertToBindLevel(const log4cplus::LogLevel loglevel) {
} else if (loglevel <= log4cplus::DEBUG_LOG_LEVEL) {
// Debug severity, so extract the debug level from the numeric value.
- // If outside the limits, change the severity to the level above or below.
+ // If outside the limits, change the severity to the level above or
+ // below.
int dbglevel = MIN_DEBUG_LEVEL +
static_cast<int>(log4cplus::DEBUG_LOG_LEVEL) -
static_cast<int>(loglevel);
@@ -148,16 +156,28 @@ LoggerLevelImpl::logLevelFromString(const log4cplus::tstring& level) {
// if DEBUG99 has been specified.
try {
int dbglevel = boost::lexical_cast<int>(name.substr(5));
+ if (dbglevel < MIN_DEBUG_LEVEL) {
+ LOG_WARN(logger, LOGIMPL_BELOWDBGMIN).arg(dbglevel)
+ .arg(MIN_DEBUG_LEVEL);
+ dbglevel = MIN_DEBUG_LEVEL;
+
+ } else if (dbglevel > MAX_DEBUG_LEVEL) {
+ LOG_WARN(logger, LOGIMPL_ABOVEDBGMAX).arg(dbglevel)
+ .arg(MAX_DEBUG_LEVEL);
+ dbglevel = MAX_DEBUG_LEVEL;
+
+ }
return convertFromBindLevel(Level(DEBUG, dbglevel));
}
catch (boost::bad_lexical_cast&) {
+ LOG_ERROR(logger, LOGIMPL_BADDEBUG).arg(name);
return (NOT_SET_LOG_LEVEL);
}
}
- }
- else {
+ } else {
- // Unknown string - return default.
+ // Unknown string - return default. Log4cplus will call any other
+ // registered conversion functions to interpret it.
return (NOT_SET_LOG_LEVEL);
}
}
@@ -175,6 +195,9 @@ LoggerLevelImpl::logLevelToString(log4cplus::LogLevel level) {
((dbglevel >= MIN_DEBUG_LEVEL) && (dbglevel <= MAX_DEBUG_LEVEL))) {
return (tstring("DEBUG"));
}
+
+ // Unknown, so return empty string for log4cplus to try other conversion
+ // functions.
return (tstring());
}
diff --git a/src/lib/log/logger_manager.cc b/src/lib/log/logger_manager.cc
new file mode 100644
index 0000000..78bb7f1
--- /dev/null
+++ b/src/lib/log/logger_manager.cc
@@ -0,0 +1,155 @@
+// 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.
+
+#include <algorithm>
+#include <vector>
+
+#include <log/logger.h>
+#include <log/logger_manager_impl.h>
+#include <log/logger_manager.h>
+#include <log/messagedef.h>
+#include <log/message_dictionary.h>
+#include <log/message_exception.h>
+#include <log/message_initializer.h>
+#include <log/message_reader.h>
+#include <log/message_types.h>
+#include <log/root_logger_name.h>
+#include <log/macros.h>
+#include <log/messagedef.h>
+#include <log/message_initializer.h>
+
+using namespace std;
+
+namespace {
+
+// Logger used for logging messages within the logging code itself.
+isc::log::Logger logger("log");
+}
+
+namespace isc {
+namespace log {
+
+// Constructor - create the implementation class.
+LoggerManager::LoggerManager() {
+ impl_ = new LoggerManagerImpl();
+}
+
+// Destructor - get rid of the implementation class
+LoggerManager::~LoggerManager() {
+ delete impl_;
+}
+
+// Initialize processing
+void
+LoggerManager::processInit() {
+ impl_->processInit();
+}
+
+// Process logging specification
+void
+LoggerManager::processSpecification(const LoggerSpecification& spec) {
+ impl_->processSpecification(spec);
+}
+
+// End Processing
+void
+LoggerManager::processEnd() {
+ impl_->processEnd();
+}
+
+
+/// Logging system initialization
+
+void
+LoggerManager::init(const std::string& root, const char* file,
+ isc::log::Severity severity, int dbglevel)
+{
+ // Create the BIND 10 root logger and set the default severity and
+ // debug level. This is the logger that has the name of the application.
+ // All other loggers created in this application will be its children.
+ setRootLoggerName(root);
+
+ // Initialize the implementation logging. After this point, some basic
+ // logging has been set up and messages can be logged.
+ LoggerManagerImpl::init(severity, dbglevel);
+
+ // Check if there were any duplicate message IDs in the default dictionary
+ // and if so, log them. Log using the logging facility logger.
+ vector<string>& duplicates = MessageInitializer::getDuplicates();
+ if (!duplicates.empty()) {
+
+ // There are duplicates present. This will be listed in alphabetic
+ // order of message ID, so they need to be sorted. This list itself may
+ // contain duplicates; if so, the message ID is listed as many times as
+ // there are duplicates.
+ sort(duplicates.begin(), duplicates.end());
+ for (vector<string>::iterator i = duplicates.begin();
+ i != duplicates.end(); ++i) {
+ LOG_WARN(logger, MSG_DUPMSGID).arg(*i);
+ }
+
+ }
+
+ // Replace any messages with local ones (if given)
+ if (file) {
+ readLocalMessageFile(file);
+ }
+}
+
+
+// Read local message file
+// TODO This should be done after the configuration has been read so that
+// the file can be placed in the local configuration
+void
+LoggerManager::readLocalMessageFile(const char* file) {
+
+ MessageDictionary& dictionary = MessageDictionary::globalDictionary();
+ MessageReader reader(&dictionary);
+ try {
+
+ logger.info(MSG_RDLOCMES).arg(file);
+ reader.readFile(file, MessageReader::REPLACE);
+
+ // File successfully read. As each message in the file is supposed to
+ // replace one in the dictionary, any ID read that can't be located in
+ // the dictionary will not be used. To aid problem diagnosis, the
+ // unknown message IDs are listed.
+ MessageReader::MessageIDCollection unknown = reader.getNotAdded();
+ for (MessageReader::MessageIDCollection::const_iterator
+ i = unknown.begin(); i != unknown.end(); ++i) {
+ string message_id = boost::lexical_cast<string>(*i);
+ logger.warn(MSG_IDNOTFND).arg(message_id);
+ }
+ }
+ catch (MessageException& e) {
+ MessageID ident = e.id();
+ vector<string> args = e.arguments();
+
+ // Log the variable number of arguments. The actual message will be
+ // logged when the error_message variable is destroyed.
+ Formatter<isc::log::Logger> error_message = logger.error(ident);
+ for (int i = 0; i < args.size(); ++i) {
+ error_message = error_message.arg(args[i]);
+ }
+ }
+}
+
+// Reset logging
+void
+LoggerManager::reset() {
+ LoggerManagerImpl::reset();
+}
+
+} // namespace log
+} // namespace isc
diff --git a/src/lib/log/logger_manager.h b/src/lib/log/logger_manager.h
new file mode 100644
index 0000000..033de65
--- /dev/null
+++ b/src/lib/log/logger_manager.h
@@ -0,0 +1,142 @@
+// 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.
+
+#ifndef __LOGGER_MANAGER_H
+#define __LOGGER_MANAGER_H
+
+#include "exceptions/exceptions.h"
+#include <log/logger_specification.h>
+
+// Generated if, when updating the logging specification, an unknown
+// destination is encountered.
+class UnknownLoggingDestination : public isc::Exception {
+public:
+ UnknownLoggingDestination(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what)
+ {}
+};
+
+namespace isc {
+namespace log {
+
+class LoggerManagerImpl;
+
+/// \brief Logger Manager
+///
+/// The logger manager class exists to process the set of logger specifications
+/// and use them to set up the logging in the program appropriately.
+///
+/// To isolate the underlying implementation from basic processing, the
+/// LoggerManager is implemented using the "pimpl" idiom.
+
+class LoggerManager {
+public:
+ /// \brief Constructor
+ LoggerManager();
+
+ /// \brief Destructor
+ ~LoggerManager();
+
+ /// \brief Process Specifications
+ ///
+ /// Replaces the current logging configuration by the one given.
+ ///
+ /// \param start Iterator pointing to the start of the collection of
+ /// logging specifications.
+ /// \param finish Iterator pointing to the end of the collection of
+ /// logging specification.
+ template <typename T>
+ void process(T start, T finish) {
+ processInit();
+ for (T i = start; i != finish; ++i) {
+ processSpecification(*i);
+ }
+ processEnd();
+ }
+
+ /// \brief Process a single specification
+ ///
+ /// A convenience function for a single specification.
+ ///
+ /// \param spec Specification to process
+ void process(const LoggerSpecification& spec) {
+ processInit();
+ processSpecification(spec);
+ processEnd();
+ }
+
+ /// \brief Run-Time Initialization
+ ///
+ /// Performs run-time initialization of the logger system, in particular
+ /// supplying the root logger name and name of a replacement message file.
+ ///
+ /// This must be the first logging function called in the program. If
+ /// an attempt is made to log a message before this is function is called,
+ /// the results will be dependent on the underlying logging package.
+ ///
+ /// \param root Name of the root logger. This should be set to the name of
+ /// the program.
+ /// \param file Name of the local message file. This must be NULL if there
+ /// is no local message file.
+ /// \param severity Severity at which to log
+ /// \param dbglevel Debug severity (ignored if "severity" is not "DEBUG")
+ static void init(const std::string& root, const char* file = NULL,
+ isc::log::Severity severity = isc::log::INFO,
+ int dbglevel = 0);
+
+ /// \brief Reset logging
+ ///
+ /// Resets logging to default (just the root logger output INFO or above
+ /// messages to the console.
+ static void reset();
+
+ /// \brief Read local message file
+ ///
+ /// Reads the local message file into the global dictionary, overwriting
+ /// existing messages. If the file contained any message IDs not in the
+ /// dictionary, they are listed in a warning message.
+ ///
+ /// \param file Name of the local message file
+ static void readLocalMessageFile(const char* file);
+
+private:
+ /// \brief Initialize Processing
+ ///
+ /// Initializes the processing of a list of specifications by resetting all
+ /// loggers to their defaults, which is to pass the message to their
+ /// parent logger. (Except for the root logger, where the default action is
+ /// to output the message.)
+ void processInit();
+
+ /// \brief Process Logging Specification
+ ///
+ /// Processes the given specification. It is assumed at this point that
+ /// either the logger does not exist or has been made inactive.
+ void processSpecification(const LoggerSpecification& spec);
+
+ /// \brief End Processing
+ ///
+ /// Place holder for finish processing.
+ /// TODO: Check that the root logger has something enabled
+ void processEnd();
+
+ // Members
+ LoggerManagerImpl* impl_; ///< Pointer to implementation
+};
+
+} // namespace log
+} // namespace isc
+
+
+#endif // __LOGGER_MANAGER_H
diff --git a/src/lib/log/logger_manager_impl.cc b/src/lib/log/logger_manager_impl.cc
new file mode 100644
index 0000000..510ffe5
--- /dev/null
+++ b/src/lib/log/logger_manager_impl.cc
@@ -0,0 +1,198 @@
+// 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.
+
+#include <algorithm>
+#include <iostream>
+
+#include <log4cplus/logger.h>
+#include <log4cplus/configurator.h>
+#include <log4cplus/consoleappender.h>
+#include <log4cplus/fileappender.h>
+
+#include "log/logger_level_impl.h"
+#include "log/logger_manager.h"
+#include "log/logger_manager_impl.h"
+#include "log/logger_specification.h"
+#include "log/root_logger_name.h"
+
+#include "log/logger.h"
+#include "log/messagedef.h"
+
+using namespace std;
+
+namespace isc {
+namespace log {
+
+// Reset hierarchy of loggers back to default settings. This removes all
+// appenders from loggers, sets their severity to NOT_SET (so that events are
+// passed back to the parent) and resets the root logger to logging
+// informational messages. (This last is not a log4cplus default, so we have to
+// explicitly reset the logging severity.)
+
+void
+LoggerManagerImpl::processInit() {
+ log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
+ initRootLogger();
+}
+
+// Process logging specification. Set up the common states then dispatch to
+// add output specifications.
+
+void
+LoggerManagerImpl::processSpecification(const LoggerSpecification& spec) {
+
+ log4cplus::Logger logger = (spec.getName() == getRootLoggerName()) ?
+ log4cplus::Logger::getRoot() :
+ log4cplus::Logger::getInstance(spec.getName());
+
+ // Set severity level according to specification entry.
+ logger.setLogLevel(LoggerLevelImpl::convertFromBindLevel(
+ Level(spec.getSeverity(), spec.getDbglevel())));
+
+ // Set the additive flag.
+ logger.setAdditivity(spec.getAdditive());
+
+ // Output options given?
+ if (spec.optionCount() > 0) {
+
+ // Yes, so replace all appenders for this logger.
+ logger.removeAllAppenders();
+
+ // Now process output specifications.
+ for (LoggerSpecification::const_iterator i = spec.begin();
+ i != spec.end(); ++i) {
+ switch (i->destination) {
+ case OutputOption::DEST_CONSOLE:
+ createConsoleAppender(logger, *i);
+ break;
+
+ case OutputOption::DEST_FILE:
+ createFileAppender(logger, *i);
+ break;
+
+ case OutputOption::DEST_SYSLOG:
+ createSyslogAppender(logger, *i);
+ break;
+
+ default:
+ // Not a valid destination. As we are in the middle of updating
+ // logging destinations, we could be in the situation where
+ // there are no valid appenders. For this reason, throw an
+ // exception.
+ isc_throw(UnknownLoggingDestination,
+ "Unknown logging destination, code = " <<
+ i->destination);
+ }
+ }
+ }
+}
+
+// Console appender - log to either stdout or stderr.
+void
+LoggerManagerImpl::createConsoleAppender(log4cplus::Logger& logger,
+ const OutputOption& opt)
+{
+ log4cplus::SharedAppenderPtr console(
+ new log4cplus::ConsoleAppender(
+ (opt.stream == OutputOption::STR_STDERR), opt.flush));
+ setConsoleAppenderLayout(console);
+ logger.addAppender(console);
+}
+
+// File appender. Depending on whether a maximum size is given, either
+// a standard file appender or a rolling file appender will be created.
+void
+LoggerManagerImpl::createFileAppender(log4cplus::Logger& logger,
+ const OutputOption& opt)
+{
+ LOG4CPLUS_OPEN_MODE_TYPE mode =
+ LOG4CPLUS_FSTREAM_NAMESPACE::ios::app; // Append to existing file
+
+ log4cplus::SharedAppenderPtr fileapp;
+ if (opt.maxsize == 0) {
+ fileapp = log4cplus::SharedAppenderPtr(new log4cplus::FileAppender(
+ opt.filename, mode, opt.flush));
+ } else {
+ fileapp = log4cplus::SharedAppenderPtr(
+ new log4cplus::RollingFileAppender(opt.filename, opt.maxsize,
+ opt.maxver, opt.flush));
+ }
+
+ // use the same console layout for the files.
+ setConsoleAppenderLayout(fileapp);
+ logger.addAppender(fileapp);
+}
+
+
+// One-time initialization of the log4cplus system
+
+void
+LoggerManagerImpl::init(isc::log::Severity severity, int dbglevel) {
+
+ // Set up basic configurator. This attaches a ConsoleAppender to the
+ // root logger with suitable output. This is used until we we have
+ // actually read the logging configuration, in which case the output
+ // may well be changed.
+ log4cplus::BasicConfigurator config;
+ config.configure();
+
+ // Add the additional debug levels
+ LoggerLevelImpl::init();
+
+ reset();
+}
+
+// Reset logging to default configuration. This closes all appenders
+// and resets the root logger to output INFO messages to the console.
+// It is principally used in testing.
+void
+LoggerManagerImpl::reset() {
+
+ // Initialize the root logger
+ initRootLogger();
+}
+
+// Initialize the root logger
+void LoggerManagerImpl::initRootLogger(isc::log::Severity severity,
+ int dbglevel)
+{
+ log4cplus::Logger::getDefaultHierarchy().resetConfiguration();
+
+ // Set the severity for the root logger
+ log4cplus::Logger::getRoot().setLogLevel(
+ LoggerLevelImpl::convertFromBindLevel(Level(severity, dbglevel)));
+
+ // Set the root to use a console logger.
+ OutputOption opt;
+ log4cplus::Logger root = log4cplus::Logger::getRoot();
+ createConsoleAppender(root, opt);
+}
+
+// Set the the "console" layout for the given appenders. This layout includes
+// a date/time and the name of the logger.
+
+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");
+
+ // Finally the text of the message
+ auto_ptr<log4cplus::Layout> layout(new log4cplus::PatternLayout(pattern));
+ appender->setLayout(layout);
+}
+
+} // namespace log
+} // namespace isc
diff --git a/src/lib/log/logger_manager_impl.h b/src/lib/log/logger_manager_impl.h
new file mode 100644
index 0000000..e384112
--- /dev/null
+++ b/src/lib/log/logger_manager_impl.h
@@ -0,0 +1,158 @@
+// 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.
+
+#ifndef __LOGGER_MANAGER_IMPL_H
+#define __LOGGER_MANAGER_IMPL_H
+
+#include <string>
+
+#include <log4cplus/appender.h>
+#include <log/logger_level.h>
+
+// Forward declaration to avoid need to include log4cplus header file here.
+namespace log4cplus {
+class Logger;
+class Appender;
+}
+
+namespace isc {
+namespace log {
+
+// Forward declarations
+class LoggerSpecification;
+class OutputOption;
+
+/// \brief Logger Manager Implementation
+///
+/// This is the implementation of the logger manager for the log4cplus
+/// underlying logger.
+///
+/// As noted in logger_manager.h, the logger manager class exists to set up the
+/// logging given a set of specifications. This class handles the processing
+/// of those specifications.
+///
+/// Note: the logging has been implemented using a "pimpl" idiom to conceal
+/// the underlying implementation (log4cplus) from the BIND 10 interface.
+/// This requires that there be an implementation class, even though in this
+/// case, all the implementation class methods can be declared static.
+
+class LoggerManagerImpl {
+public:
+
+ /// \brief Constructor
+ LoggerManagerImpl()
+ {}
+
+ /// \brief Initialize Processing
+ ///
+ /// This resets the hierachy of loggers back to their defaults. This means
+ /// that all non-root loggers (if they exist) are set to NOT_SET, and the
+ /// root logger reset to logging informational messages.
+ ///
+ /// \param root_name BIND 10 name of the root logger
+ static void processInit();
+
+ /// \brief Process Specification
+ ///
+ /// Processes the specification for a single logger.
+ ///
+ /// \param spec Logging specification for this logger
+ static void processSpecification(const LoggerSpecification& spec);
+
+ /// \brief End Processing
+ ///
+ /// Terminates the processing of the logging specifications.
+ static void processEnd()
+ {}
+
+ /// \brief Implementation-specific initialization
+ ///
+ /// Sets the basic configuration for logging (the root logger has INFO and
+ /// more severe messages routed to stdout). Unless this function (or
+ /// process() with a valid specification for all loggers that will log
+ /// messages) is called before a message is logged, log4cplus will output
+ /// a message to stderr noting that logging has not been initialized.
+ ///
+ /// It is assumed here that the name of the BIND 10 root logger can be
+ /// obtained from the global function getRootLoggerName().
+ ///
+ /// \param severity Severity to be associated with this logger
+ /// \param dbglevel Debug level associated with the root logger
+ static void init(isc::log::Severity severity = isc::log::INFO,
+ int dbglevel = 0);
+
+ /// \brief Reset logging
+ ///
+ /// Resets to default configuration (root logger logging to the console
+ /// with INFO severity).
+ static void reset();
+
+private:
+ /// \brief Create console appender
+ ///
+ /// Creates an object that, when attached to a logger, will log to one
+ /// of the output streams (stdout or stderr).
+ ///
+ /// \param logger Log4cplus logger to which the appender must be attached.
+ /// \param opt Output options for this appender.
+ static void createConsoleAppender(log4cplus::Logger& logger,
+ const OutputOption& opt);
+
+ /// \brief Create file appender
+ ///
+ /// Creates an object that, when attached to a logger, will log to a
+ /// specified file. This also includes the ability to "roll" files when
+ /// they reach a specified size.
+ ///
+ /// \param logger Log4cplus logger to which the appender must be attached.
+ /// \param opt Output options for this appender.
+ static void createFileAppender(log4cplus::Logger& logger,
+ const OutputOption& opt);
+
+ /// \brief Create syslog appender
+ ///
+ /// Creates an object that, when attached to a logger, will log to the
+ /// syslog file.
+ ///
+ /// \param logger Log4cplus logger to which the appender must be attached.
+ /// \param opt Output options for this appender.
+ static void createSyslogAppender(log4cplus::Logger& logger,
+ const OutputOption& opt) {}
+
+ /// \brief Set default layout and severity for root logger
+ ///
+ /// Initializes the root logger to BIND 10 defaults - console output and
+ /// the passed severity/debug level.
+ ///
+ /// \param severity Severity of messages that the logger should output.
+ /// \param dbglevel Debug level if severity = DEBUG
+ static void initRootLogger(isc::log::Severity severity = isc::log::INFO,
+ int dbglevel = 0);
+
+ /// \brief Set layout for console appender
+ ///
+ /// Sets the layout of the specified appender to one suitable for file
+ /// or console output:
+ ///
+ /// YYYY-MM-DD HH:MM:SS.ssss <severity> [root.logger] message
+ ///
+ /// \param appender Appender for which this pattern is to be set.
+ /// \param root_name Name of the BIND 10 root logger.
+ static void setConsoleAppenderLayout(log4cplus::SharedAppenderPtr& appender);
+};
+
+} // namespace log
+} // namespace isc
+
+#endif // __LOGGER_MANAGER_IMPL_H
diff --git a/src/lib/log/logger_specification.h b/src/lib/log/logger_specification.h
new file mode 100644
index 0000000..35c879c
--- /dev/null
+++ b/src/lib/log/logger_specification.h
@@ -0,0 +1,156 @@
+// 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.
+
+#ifndef __LOGGER_SPECIFICATION_H
+#define __LOGGER_SPECIFICATION_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <log/logger_level.h>
+#include <log/output_option.h>
+
+/// \brief Logger Specification
+///
+/// The logging configuration options are a list of logger specifications, each
+/// of which represents a logger and the options for its appenders.
+///
+/// Unlike OutputOption (which is a struct), this contains a bit more
+/// structure and is concealed in a class.
+
+#include <vector>
+
+namespace isc {
+namespace log {
+
+class LoggerSpecification {
+public:
+ typedef std::vector<OutputOption>::iterator iterator;
+ typedef std::vector<OutputOption>::const_iterator const_iterator;
+
+ /// \brief Constructor
+ ///
+ /// \param name Name of the logger.
+ /// \param severity Severity at which this logger logs
+ /// \param dbglevel Debug level
+ /// \param additive true to cause message logged with this logger to be
+ /// passed to the parent for logging.
+ LoggerSpecification(const std::string& name = "",
+ isc::log::Severity severity = isc::log::INFO,
+ int dbglevel = 0, bool additive = false) :
+ name_(name), severity_(severity), dbglevel_(dbglevel),
+ additive_(additive)
+ {}
+
+ /// \brief Set the name of the logger.
+ ///
+ /// \param name Name of the logger.
+ void setName(const std::string& name) {
+ name_ = name;
+ }
+
+ /// \return Return logger name.
+ std::string getName() const {
+ return name_;
+ }
+
+ /// \brief Set the severity.
+ ///
+ /// \param severity New severity of the logger.
+ void setSeverity(isc::log::Severity severity) {
+ severity_ = severity;
+ }
+
+ /// \return Return logger severity.
+ isc::log::Severity getSeverity() const {
+ return severity_;
+ }
+
+ /// \brief Set the debug level.
+ ///
+ /// \param dbglevel New debug level of the logger.
+ void setDbglevel(int dbglevel) {
+ dbglevel_ = dbglevel;
+ }
+
+ /// \return Return logger debug level
+ int getDbglevel() const {
+ return dbglevel_;
+ }
+
+ /// \brief Set the additive flag.
+ ///
+ /// \param additive New value of the additive flag.
+ void setAdditive(bool additive) {
+ additive_ = additive;
+ }
+
+ /// \return Return additive flag.
+ int getAdditive() const {
+ return additive_;
+ }
+
+ /// \brief Add output option.
+ ///
+ /// \param Option to add to the list.
+ void addOutputOption(const OutputOption& option) {
+ options_.push_back(option);
+ }
+
+ /// \return Iterator to start of output options.
+ iterator begin() {
+ return options_.begin();
+ }
+
+ /// \return Iterator to start of output options.
+ const_iterator begin() const {
+ return options_.begin();
+ }
+
+ /// \return Iterator to end of output options.
+ iterator end() {
+ return options_.end();
+ }
+
+ /// \return Iterator to end of output options.
+ const_iterator end() const {
+ return options_.end();
+ }
+
+ /// \return Number of output specification options.
+ size_t optionCount() const {
+ return options_.size();
+ }
+
+ /// \brief Reset back to defaults.
+ void reset() {
+ name_ = "";
+ severity_ = isc::log::INFO;
+ dbglevel_ = 0;
+ additive_ = false;
+ options_.clear();
+ }
+
+private:
+ std::string name_; ///< Logger name
+ isc::log::Severity severity_; ///< Severity for this logger
+ int dbglevel_; ///< Debug level
+ bool additive_; ///< Chaining output
+ std::vector<OutputOption> options_; ///< Logger options
+};
+
+} // namespace log
+} // namespace isc
+
+#endif // __LOGGER_SPEC_IFICATIONH
diff --git a/src/lib/log/logger_support.cc b/src/lib/log/logger_support.cc
index 701cfef..41b87f3 100644
--- a/src/lib/log/logger_support.cc
+++ b/src/lib/log/logger_support.cc
@@ -28,18 +28,10 @@
#include <algorithm>
#include <iostream>
#include <string>
-#include <vector>
-#include <boost/lexical_cast.hpp>
#include <log/logger.h>
+#include <log/logger_manager.h>
#include <log/logger_support.h>
-#include <log/messagedef.h>
-#include <log/message_dictionary.h>
-#include <log/message_exception.h>
-#include <log/message_initializer.h>
-#include <log/message_reader.h>
-#include <log/message_types.h>
-#include <log/root_logger_name.h>
namespace isc {
namespace log {
@@ -50,88 +42,12 @@ using namespace std;
// root logger and is used in all functions in this file.
Logger logger("log");
-
-/// \brief Reads Local Message File
-///
-/// Reads the local message file into the global dictionary, overwriting
-/// existing messages. If the file contained any message IDs not in the
-/// dictionary, they are listed in a warning message.
-///
-/// \param file Name of the local message file
-static void
-readLocalMessageFile(const char* file) {
-
- MessageDictionary& dictionary = MessageDictionary::globalDictionary();
- MessageReader reader(&dictionary);
- try {
- logger.info(MSG_RDLOCMES).arg(file);
- reader.readFile(file, MessageReader::REPLACE);
-
- // File successfully read, list the duplicates
- MessageReader::MessageIDCollection unknown = reader.getNotAdded();
- for (MessageReader::MessageIDCollection::const_iterator
- i = unknown.begin(); i != unknown.end(); ++i) {
- string message_id = boost::lexical_cast<string>(*i);
- logger.warn(MSG_IDNOTFND).arg(message_id);
- }
- }
- catch (MessageException& e) {
- MessageID ident = e.id();
- vector<string> args = e.arguments();
- switch (args.size()) {
- case 0:
- logger.error(ident);
- break;
-
- case 1:
- logger.error(ident).arg(args[0]);
- break;
-
- case 2:
- logger.error(ident).arg(args[0]).arg(args[1]);
- break;
-
- default: // 3 or more (3 should be the maximum)
- logger.error(ident).arg(args[0]).arg(args[1]).arg(args[2]);
- }
- }
-}
-
/// Logger Run-Time Initialization
void
initLogger(const string& root, isc::log::Severity severity, int dbglevel,
const char* file) {
-
- // Create the application root logger and set the default severity and
- // debug level. This is the logger that has the name of the application.
- // All other loggers created in this application will be its children.
- setRootLoggerName(root);
- Logger root_logger(isc::log::getRootLoggerName());
-
- // Set the severity associated with it. If no other logger has a severity,
- // this will be the default.
- root_logger.setSeverity(severity, dbglevel);
-
- // Check if there were any duplicate message IDs in the default dictionary
- // and if so, log them. Log using the logging facility root logger.
- vector<string>& duplicates = MessageInitializer::getDuplicates();
- if (!duplicates.empty()) {
-
- // There are - sort and remove any duplicates.
- sort(duplicates.begin(), duplicates.end());
- vector<string>::iterator new_end =
- unique(duplicates.begin(), duplicates.end());
- for (vector<string>::iterator i = duplicates.begin(); i != new_end; ++i) {
- logger.warn(MSG_DUPMSGID).arg(*i);
- }
-
- }
-
- // Replace any messages with local ones (if given)
- if (file) {
- readLocalMessageFile(file);
- }
+ LoggerManager::init(root, file, severity, dbglevel);
}
/// Logger Run-Time Initialization via Environment Variables
@@ -149,24 +65,10 @@ void initLogger() {
// B10_LOGGER_SEVERITY, and can be one of "DEBUG", "INFO", "WARN", "ERROR"
// of "FATAL". Note that the string must be in upper case with no leading
// of trailing blanks.
- isc::log::Severity severity = isc::log::DEBUG;
+ isc::log::Severity severity = isc::log::INFO;
const char* sev_char = getenv("B10_LOGGER_SEVERITY");
if (sev_char) {
- string sev_string(sev_char);
- if (sev_string == "DEBUG") {
- severity = isc::log::DEBUG;
- } else if (sev_string == "INFO") {
- severity = isc::log::INFO;
- } else if (sev_string == "WARN") {
- severity = isc::log::WARN;
- } else if (sev_string == "ERROR") {
- severity = isc::log::ERROR;
- } else if (sev_string == "FATAL") {
- severity = isc::log::FATAL;
- } else {
- std::cerr << "**ERROR** unrecognised logger severity of '"
- << sev_string << "' - default severity will be used\n";
- }
+ severity = isc::log::getSeverity(sev_char);
}
// If the severity is debug, get the debug level (environment variable
diff --git a/src/lib/log/logger_support.h b/src/lib/log/logger_support.h
index f4861b2..7d70eff 100644
--- a/src/lib/log/logger_support.h
+++ b/src/lib/log/logger_support.h
@@ -15,6 +15,8 @@
#ifndef __LOGGER_SUPPORT_H
#define __LOGGER_SUPPORT_H
+#include <unistd.h>
+
#include <string>
#include <log/logger.h>
@@ -36,8 +38,9 @@ namespace log {
/// \param severity Severity at which to log
/// \param dbglevel Debug severity (ignored if "severity" is not "DEBUG")
/// \param file Name of the local message file.
-void initLogger(const std::string& root, isc::log::Severity severity,
- int dbglevel, const char* file);
+void initLogger(const std::string& root,
+ isc::log::Severity severity = isc::log::INFO,
+ int dbglevel = 0, const char* file = NULL);
/// \brief Run-Time Initialization from Environment
diff --git a/src/lib/log/messagedef.cc b/src/lib/log/messagedef.cc
index 5cc89b3..853722a 100644
--- a/src/lib/log/messagedef.cc
+++ b/src/lib/log/messagedef.cc
@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon May 9 13:52:54 2011
+// File created from messagedef.mes on Fri May 27 14:49:45 2011
#include <cstddef>
#include <log/message_types.h>
@@ -7,6 +7,9 @@
namespace isc {
namespace log {
+extern const isc::log::MessageID MSG_BADDESTINATION = "MSG_BADDESTINATION";
+extern const isc::log::MessageID MSG_BADSEVERITY = "MSG_BADSEVERITY";
+extern const isc::log::MessageID MSG_BADSTREAM = "MSG_BADSTREAM";
extern const isc::log::MessageID MSG_DUPLNS = "MSG_DUPLNS";
extern const isc::log::MessageID MSG_DUPMSGID = "MSG_DUPMSGID";
extern const isc::log::MessageID MSG_IDNOTFND = "MSG_IDNOTFND";
@@ -31,6 +34,9 @@ extern const isc::log::MessageID MSG_WRITERR = "MSG_WRITERR";
namespace {
const char* values[] = {
+ "MSG_BADDESTINATION", "unrecognized log destination: %1",
+ "MSG_BADSEVERITY", "unrecognized log severity: %1",
+ "MSG_BADSTREAM", "bad log console output stream: %1",
"MSG_DUPLNS", "line %1: duplicate $NAMESPACE directive found",
"MSG_DUPMSGID", "duplicate message ID (%1) in compiled code",
"MSG_IDNOTFND", "could not replace message text for '%1': no such message",
diff --git a/src/lib/log/messagedef.h b/src/lib/log/messagedef.h
index 79c8bab..bdb1075 100644
--- a/src/lib/log/messagedef.h
+++ b/src/lib/log/messagedef.h
@@ -1,4 +1,4 @@
-// File created from messagedef.mes on Mon May 9 13:52:54 2011
+// File created from messagedef.mes on Fri May 27 14:49:45 2011
#ifndef __MESSAGEDEF_H
#define __MESSAGEDEF_H
@@ -8,6 +8,9 @@
namespace isc {
namespace log {
+extern const isc::log::MessageID MSG_BADDESTINATION;
+extern const isc::log::MessageID MSG_BADSEVERITY;
+extern const isc::log::MessageID MSG_BADSTREAM;
extern const isc::log::MessageID MSG_DUPLNS;
extern const isc::log::MessageID MSG_DUPMSGID;
extern const isc::log::MessageID MSG_IDNOTFND;
diff --git a/src/lib/log/messagedef.mes b/src/lib/log/messagedef.mes
index 51c04fa..a54931b 100644
--- a/src/lib/log/messagedef.mes
+++ b/src/lib/log/messagedef.mes
@@ -117,3 +117,15 @@ the named output file.
% UNRECDIR line %1: unrecognised directive '%2'
A line starting with a dollar symbol was found, but the first word on the line
(shown in the message) was not a recognised message compiler directive.
+
+% BADSEVERITY unrecognized log severity: %1
+A logger severity value was given that was not recognized. The severity
+should be one of "DEBUG", "INFO", "WARN", "ERROR", or "FATAL".
+
+% BADDESTINATION unrecognized log destination: %1
+A logger destination value was given that was not recognized. The
+destination should be one of "console", "file", or "syslog".
+
+% BADSTREAM bad log console output stream: %1
+A log console output stream was given that was not recognized. The
+output stream should be one of "stdout", or "stderr"
diff --git a/src/lib/log/output_option.cc b/src/lib/log/output_option.cc
new file mode 100644
index 0000000..191631d
--- /dev/null
+++ b/src/lib/log/output_option.cc
@@ -0,0 +1,54 @@
+// 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.
+
+#include <string>
+#include <log/output_option.h>
+#include <log/macros.h>
+#include <log/messagedef.h>
+
+#include <boost/algorithm/string.hpp>
+
+namespace isc {
+namespace log {
+
+OutputOption::Destination
+getDestination(const std::string& dest_str) {
+ if (boost::iequals(dest_str, "console")) {
+ return OutputOption::DEST_CONSOLE;
+ } else if (boost::iequals(dest_str, "file")) {
+ return OutputOption::DEST_FILE;
+ } else if (boost::iequals(dest_str, "syslog")) {
+ return OutputOption::DEST_SYSLOG;
+ } else {
+ Logger logger("log");
+ LOG_ERROR(logger, MSG_BADDESTINATION).arg(dest_str);
+ return OutputOption::DEST_CONSOLE;
+ }
+}
+
+OutputOption::Stream
+getStream(const std::string& stream_str) {
+ if (boost::iequals(stream_str, "stderr")) {
+ return OutputOption::STR_STDERR;
+ } else if (boost::iequals(stream_str, "stdout")) {
+ return OutputOption::STR_STDOUT;
+ } else {
+ Logger logger("log");
+ LOG_ERROR(logger, MSG_BADSTREAM).arg(stream_str);
+ return OutputOption::STR_STDOUT;
+ }
+}
+
+} // namespace log
+} // namespace isc
diff --git a/src/lib/log/output_option.h b/src/lib/log/output_option.h
new file mode 100644
index 0000000..111ee76
--- /dev/null
+++ b/src/lib/log/output_option.h
@@ -0,0 +1,85 @@
+// 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.
+
+#ifndef __OUTPUT_OPTION_H
+#define __OUTPUT_OPTION_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string>
+
+/// \brief Logger Output Option
+///
+/// The logging configuration options are a list of logger specifications, each
+/// with one or more output options. This class represents an output option;
+/// one or more of these are attached to a LoggerSpecification object which is
+/// then passed to the LoggerManager to configure the logger.
+///
+/// Although there are three distinct output types (console, file, syslog) and
+/// the options for each do not really overlap. Although it is tempting to
+/// define a base OutputOption class and derive a class for each type
+/// (ConsoleOutputOptions etc.), it would be messy to use in practice. At
+/// some point the exact class would have to be known to get the class-specific
+/// options and the (pointer to) the base class cast to the appropriate type.
+/// Instead, this "struct" contains the union of all output options; it is up
+/// to the caller to cherry-pick the members it needs.
+///
+/// One final note: this object holds data and does no computation. For this
+/// reason, it is a "struct" and members are accessed directly instead of
+/// through methods.
+
+namespace isc {
+namespace log {
+
+struct OutputOption {
+
+ /// Destinations. Prefixed "DEST_" to avoid problems with the C stdio.h
+ /// FILE type.
+ typedef enum {
+ DEST_CONSOLE = 0,
+ DEST_FILE = 1,
+ DEST_SYSLOG = 2
+ } Destination;
+
+ /// If console, stream on which messages are output
+ typedef enum {
+ STR_STDOUT = 1,
+ STR_STDERR = 2
+ } Stream;
+
+ /// \brief Constructor
+ OutputOption() : destination(DEST_CONSOLE), stream(STR_STDERR),
+ flush(false), facility(""), filename(""), maxsize(0),
+ maxver(0)
+ {}
+
+ /// Members.
+
+ Destination destination; ///< Where the output should go
+ Stream stream; ///< stdout/stderr if console output
+ bool flush; ///< true to flush after each message
+ std::string facility; ///< syslog facility
+ std::string filename; ///< Filename if file output
+ size_t maxsize; ///< 0 if no maximum size
+ int maxver; ///< Maximum versions (none if <= 0)
+};
+
+OutputOption::Destination getDestination(const std::string& dest_str);
+OutputOption::Stream getStream(const std::string& stream_str);
+
+
+} // namespace log
+} // namespace isc
+
+#endif // __OUTPUT_OPTION_H
diff --git a/src/lib/log/tests/Makefile.am b/src/lib/log/tests/Makefile.am
index c9f389c..f9659e4 100644
--- a/src/lib/log/tests/Makefile.am
+++ b/src/lib/log/tests/Makefile.am
@@ -13,16 +13,19 @@ CLEANFILES = *.gcno *.gcda
TESTS =
if HAVE_GTEST
TESTS += run_unittests
-run_unittests_SOURCES = root_logger_name_unittest.cc
-run_unittests_SOURCES += logger_unittest.cc
-run_unittests_SOURCES += logger_level_unittest.cc
-run_unittests_SOURCES += logger_level_impl_unittest.cc
-run_unittests_SOURCES += message_dictionary_unittest.cc
-run_unittests_SOURCES += message_reader_unittest.cc
-run_unittests_SOURCES += message_initializer_unittest.cc
-run_unittests_SOURCES += message_initializer_unittest_2.cc
-run_unittests_SOURCES += run_unittests.cc
+run_unittests_SOURCES = run_unittests.cc
run_unittests_SOURCES += log_formatter_unittest.cc
+run_unittests_SOURCES += logger_level_impl_unittest.cc
+run_unittests_SOURCES += logger_level_unittest.cc
+run_unittests_SOURCES += logger_manager_unittest.cc
+run_unittests_SOURCES += logger_unittest.cc
+run_unittests_SOURCES += logger_specification_unittest.cc
+# run_unittests_SOURCES += message_dictionary_unittest.cc
+# run_unittests_SOURCES += message_initializer_unittest_2.cc
+# run_unittests_SOURCES += message_initializer_unittest.cc
+# run_unittests_SOURCES += message_reader_unittest.cc
+# run_unittests_SOURCES += output_option_unittest.cc
+# run_unittests_SOURCES += root_logger_name_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
@@ -35,18 +38,23 @@ run_unittests_CXXFLAGS += -Wno-unused-variable
endif
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
endif
-TESTS += logger_support_test
-logger_support_test_SOURCES = logger_support_test.cc
-logger_support_test_CPPFLAGS = $(AM_CPPFLAGS)
-logger_support_test_LDFLAGS = $(AM_LDFLAGS)
-logger_support_test_LDADD = $(top_builddir)/src/lib/log/liblog.la
+TESTS += logger_example
+logger_example_SOURCES = logger_example.cc
+logger_example_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+logger_example_LDFLAGS = $(AM_LDFLAGS) $(LOG4CPLUS_LDFLAGS)
+logger_example_LDADD = $(top_builddir)/src/lib/log/liblog.la
+logger_example_LDADD += $(top_builddir)/src/lib/util/libutil.la
noinst_PROGRAMS = $(TESTS)
# Additional test using the shell
-PYTESTS = run_time_init_test.sh
+PYTESTS = console_test.sh local_file_test.sh severity_test.sh
check-local:
- $(SHELL) $(abs_builddir)/run_time_init_test.sh
+ $(SHELL) $(abs_builddir)/console_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
new file mode 100755
index 0000000..f941121
--- /dev/null
+++ b/src/lib/log/tests/console_test.sh.in
@@ -0,0 +1,68 @@
+#!/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
+#
+# The logger supports the idea of a "console" logger than logs to either stdout
+# or stderr. This test checks that both these options work.
+
+testname="Console output test"
+echo $testname
+
+failcount=0
+tempfile=@abs_builddir@/console_test_tempfile_$$
+
+# Look at tempfile and check that the count equals the expected count
+passfail() {
+ count=`wc -l $tempfile | cut -f1 -d' '`
+ if [ $count -eq $1 ]; then
+ echo " -- pass"
+ else
+ echo " ** FAIL"
+ failcount=`expr $failcount + $1`
+ fi
+}
+
+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
+
+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
+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
+
+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
+passfail 0
+
+rm -f $tempfile
+
+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
new file mode 100755
index 0000000..f370c5b
--- /dev/null
+++ b/src/lib/log/tests/local_file_test.sh.in
@@ -0,0 +1,79 @@
+#!/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 Local message file test
+#
+# Checks that a local message file can override the definitions in the message
+# dictionary.
+
+testname="Local message file test"
+echo $testname
+
+failcount=0
+localmes=@abs_builddir@/localdef_mes_$$
+tempfile=@abs_builddir@/run_time_init_test_tempfile_$$
+
+passfail() {
+ if [ $1 -eq 0 ]; then
+ echo " -- pass"
+ else
+ echo " ** FAIL"
+ failcount=`expr $failcount + $1`
+ fi
+}
+
+# Create the local message file for testing
+
+cat > $localmes << .
+\$PREFIX MSG_
+% NOTHERE this message is not in the global dictionary
+% READERR replacement read error, parameters: '%1' and '%2'
+% RDLOCMES replacement read local message file, parameter is '%1'
+.
+
+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'
+.
+./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
+.
+rm -f $localmes
+./logger_example -c stdout -s warn $localmes | cut -d' ' -f3- | diff $tempfile -
+passfail $?
+
+# Tidy up.
+
+rm -f $tempfile
+
+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/logger_example.cc b/src/lib/log/tests/logger_example.cc
new file mode 100644
index 0000000..f1126f9
--- /dev/null
+++ b/src/lib/log/tests/logger_example.cc
@@ -0,0 +1,176 @@
+// 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 Example Program
+///
+/// Simple example program showing how to use the logger. The various
+/// command-line options let most aspects of the logger be exercised, so
+/// making this a useful tool for testing.
+///
+/// See the usage() method for details of use.
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+#include <string>
+
+#include <util/strutil.h>
+
+#include <log/logger.h>
+#include <log/logger_level.h>
+#include <log/logger_manager.h>
+#include <log/logger_specification.h>
+#include <log/macros.h>
+#include <log/root_logger_name.h>
+
+// Include a set of message definitions.
+#include <log/messagedef.h>
+
+using namespace isc::log;
+using namespace std;
+
+
+// Print usage information
+
+void usage() {
+ cout <<
+"logger_support_test [-h] [-c stream] [-d dbglevel] [-f file]\n"
+" [-s severity] [localfile]\n"
+"\n"
+" -h Print this message and exit\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 program sets the attributes on the root logger and logs a set of
+// messages. Looking at the output determines whether the program worked.
+
+int main(int argc, char** argv) {
+ const string ROOT_NAME = "alpha";
+
+ 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
+
+ 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) {
+ switch (option) {
+ case 'c':
+ if (f_found || l_found) {
+ cerr << "Cannot specify -c with -f or -l\n";
+ return (1);
+ }
+
+ c_found = true;
+ outopt.destination = OutputOption::DEST_CONSOLE;
+
+ if (strcmp(optarg, "stdout") == 0) {
+ outopt.stream = OutputOption::STR_STDOUT;
+
+ } else if (strcmp(optarg, "stderr") == 0) {
+ outopt.stream = OutputOption::STR_STDERR;
+
+ } else {
+ cerr << "Unrecognised console option: " << optarg << "\n";
+ return (1);
+ }
+ break;
+
+ case 'd':
+ 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);
+ }
+
+ f_found = true;
+
+ outopt.destination = OutputOption::DEST_FILE;
+ outopt.filename = optarg;
+ break;
+
+ case 'h':
+ usage();
+ return (0);
+
+ case 's':
+ {
+ string severity(optarg);
+ isc::util::str::uppercase(severity);
+ spec.setSeverity(getSeverity(severity));
+ }
+ break;
+
+ default:
+ std::cerr << "Unrecognised option: " <<
+ static_cast<char>(option) << "\n";
+ return (1);
+ }
+ }
+
+ // Update the logging parameters. If no output options
+ // were set, the defaults will be used.
+ spec.addOutputOption(outopt);
+
+ // Set the logging options for the root logger.
+ LoggerManager manager;
+ manager.process(spec);
+
+ // Set the local file
+ if (optind < argc) {
+ LoggerManager::readLocalMessageFile(argv[optind]);
+ }
+
+
+ // 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");
+
+ return (0);
+}
diff --git a/src/lib/log/tests/logger_level_unittest.cc b/src/lib/log/tests/logger_level_unittest.cc
index aa8809f..a3432ea 100644
--- a/src/lib/log/tests/logger_level_unittest.cc
+++ b/src/lib/log/tests/logger_level_unittest.cc
@@ -19,19 +19,25 @@
#include <log/root_logger_name.h>
#include <log/logger.h>
+#include <log/logger_manager.h>
#include <log/messagedef.h>
using namespace isc;
using namespace isc::log;
using namespace std;
+namespace {
+string ROOT_NAME("logleveltest");
+}
+
class LoggerLevelTest : public ::testing::Test {
protected:
- LoggerLevelTest()
- {}
-
- ~LoggerLevelTest()
- {}
+ LoggerLevelTest() {
+ LoggerManager::init(ROOT_NAME);
+ }
+ ~LoggerLevelTest() {
+ LoggerManager::reset();
+ }
};
@@ -54,3 +60,32 @@ TEST_F(LoggerLevelTest, Creation) {
EXPECT_EQ(isc::log::DEBUG, level3.severity);
EXPECT_EQ(42, level3.dbglevel);
}
+
+TEST(LoggerLevel, getSeverity) {
+ // Should initialize logger as getSeverity() may output
+ // a message. This gives a properly-qualified logger
+ // name.
+ LoggerManager::init(ROOT_NAME);
+
+ EXPECT_EQ(DEBUG, getSeverity("DEBUG"));
+ EXPECT_EQ(DEBUG, getSeverity("debug"));
+ EXPECT_EQ(DEBUG, getSeverity("DeBuG"));
+ EXPECT_EQ(INFO, getSeverity("INFO"));
+ EXPECT_EQ(INFO, getSeverity("info"));
+ EXPECT_EQ(INFO, getSeverity("iNfO"));
+ EXPECT_EQ(WARN, getSeverity("WARN"));
+ EXPECT_EQ(WARN, getSeverity("warn"));
+ EXPECT_EQ(WARN, getSeverity("wARn"));
+ EXPECT_EQ(ERROR, getSeverity("ERROR"));
+ EXPECT_EQ(ERROR, getSeverity("error"));
+ EXPECT_EQ(ERROR, getSeverity("ERRoR"));
+ EXPECT_EQ(FATAL, getSeverity("FATAL"));
+ EXPECT_EQ(FATAL, getSeverity("fatal"));
+ EXPECT_EQ(FATAL, getSeverity("FAtaL"));
+
+ // bad values should default to stdout
+ EXPECT_EQ(INFO, getSeverity("some bad value"));
+ EXPECT_EQ(INFO, getSeverity(""));
+
+ LoggerManager::reset();
+}
diff --git a/src/lib/log/tests/logger_manager_unittest.cc b/src/lib/log/tests/logger_manager_unittest.cc
new file mode 100644
index 0000000..a9a3a5e
--- /dev/null
+++ b/src/lib/log/tests/logger_manager_unittest.cc
@@ -0,0 +1,325 @@
+// 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.
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <boost/scoped_array.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include <log/macros.h>
+#include <log/messagedef.h>
+#include <log/logger.h>
+#include <log/logger_level.h>
+#include <log/logger_manager.h>
+#include <log/logger_specification.h>
+#include <log/output_option.h>
+
+#include "tempdir.h"
+
+using namespace isc;
+using namespace isc::log;
+using namespace std;
+
+namespace {
+string ROOT_NAME("logmgrtest");
+}
+
+/// \brief LoggerManager Test
+class LoggerManagerTest : public ::testing::Test {
+public:
+ LoggerManagerTest() {
+ LoggerManager::init(ROOT_NAME);
+ }
+
+ ~LoggerManagerTest() {
+ LoggerManager::reset();
+ }
+};
+
+
+
+// Convenience class to create the specification for the logger "filelogger",
+// which, as the name suggests, logs to a file. It remembers the file name and
+// deletes the file when instance of the class is destroyed.
+class SpecificationForFileLogger {
+public:
+
+ // Constructor - allocate file and create the specification object
+ SpecificationForFileLogger() : spec_(), name_(""), logname_("filelogger") {
+
+ // Set the output to a temporary file.
+ OutputOption option;
+ option.destination = OutputOption::DEST_FILE;
+ option.filename = name_ = createTempFilename();
+
+ // Set target output to the file logger. The defauls indicate
+ // INFO severity.
+ spec_.setName(logname_);
+ spec_.addOutputOption(option);
+ }
+
+ // Destructor, remove the file. This is only a test, so ignore failures
+ ~SpecificationForFileLogger() {
+ if (! name_.empty()) {
+ (void) unlink(name_.c_str());
+ }
+ }
+
+ // Return reference to the logging specification for this loggger
+ LoggerSpecification& getSpecification() {
+ return spec_;
+ }
+
+ // Return name of the logger
+ string getLoggerName() const {
+ return logname_;
+ }
+
+ // Return name of the file
+ string getFileName() const {
+ return name_;
+ }
+
+ // Create temporary filename
+ //
+ // The compiler warns against tmpnam() and suggests mkstemp instead.
+ // Unfortunately, this creates the filename and opens it. So we need to
+ // close and delete the file before returning the name. Also, the name
+ // is based on the template supplied and the name of the temporary
+ // directory may vary between systems. So translate TMPDIR and if that
+ // does not exist, use /tmp.
+ //
+ // \return Temporary file name
+ std::string createTempFilename() {
+ string filename = TEMP_DIR + "/bind10_logger_manager_test_XXXXXX";
+
+ // Copy into writeable storage for the call to mkstemp
+ boost::scoped_array<char> tname(new char[filename.size() + 1]);
+ strcpy(tname.get(), filename.c_str());
+
+ // Create file, close and delete it, and store the name for later.
+ // There is still a race condition here, albeit a small one.
+ int filenum = mkstemp(tname.get());
+ if (filenum == -1) {
+ isc_throw(Exception, "Unable to obtain unique filename");
+ }
+ close(filenum);
+
+ return (string(tname.get()));
+ }
+
+
+private:
+ LoggerSpecification spec_; // Specification for this file logger
+ string name_; // Name of the output file
+ string logname_; // Name of this logger
+};
+
+
+// Convenience function to read an output log file and check that each line
+// contains the expected message ID
+//
+// \param filename Name of the file to check
+// \param start Iterator pointing to first expected message ID
+// \param finish Iterator pointing to last expected message ID
+template <typename T>
+void checkFileContents(const std::string& filename, T start, T finish) {
+
+ // Access the file for input
+ ifstream infile(filename.c_str());
+ if (! infile.good()) {
+ FAIL() << "Unable to open the logging file " << filename;
+ }
+
+ // Iterate round the expected message IDs and check that they appear in
+ // the string.
+ string line; // Line read from the file
+
+ T i = start; // Iterator
+ getline(infile, line);
+ int lineno = 1;
+
+ while ((i != finish) && (infile.good())) {
+
+ // Check that the message ID appears in the line.
+ EXPECT_TRUE(line.find(string(*i)) != string::npos)
+ << "Expected to find " << string(*i) << " on line " << lineno
+ << " of logging file " << filename;
+
+ // Go for the next line
+ ++i;
+ getline(infile, line);
+ ++lineno;
+ }
+
+ // Why did the loop end?
+ EXPECT_TRUE(i == finish) << "Did not reach the end of the message ID list";
+ EXPECT_TRUE(infile.eof()) << "Did not reach the end of the logging file";
+
+ // File will close when the instream is deleted at the end of this
+ // function.
+}
+
+// Check that the logger correctly creates something logging to a file.
+TEST_F(LoggerManagerTest, FileLogger) {
+
+ // Create a specification for the file logger and use the manager to
+ // connect the "filelogger" logger to it.
+ SpecificationForFileLogger file_spec;
+
+ // For the first test, we want to check that the file is created
+ // if it does not already exist. So delete the temporary file before
+ // logging the first message.
+ unlink(file_spec.getFileName().c_str());
+
+ // Set up the file appenders.
+ LoggerManager manager;
+ manager.process(file_spec.getSpecification());
+
+ // Try logging to the file. Local scope is set to ensure that the logger
+ // is destroyed before we reset the global logging. We record what we
+ // put in the file for a later comparison.
+ vector<MessageID> ids;
+ {
+
+ // Scope-limit the logger to ensure it is destroyed after the brief
+ // check. This adds weight to the idea that the logger will not
+ // keep the file open.
+ Logger logger(file_spec.getLoggerName());
+
+ LOG_FATAL(logger, MSG_DUPMSGID).arg("test");
+ ids.push_back(MSG_DUPMSGID);
+
+ LOG_FATAL(logger, MSG_DUPLNS).arg("test");
+ ids.push_back(MSG_DUPLNS);
+ }
+ LoggerManager::reset();
+
+ // At this point, the output file should contain two lines with messages
+ // MSG_DUPMSGID and MSG_DUPLNS messages - test this.
+ checkFileContents(file_spec.getFileName(), ids.begin(), ids.end());
+
+ // Re-open the file (we have to assume that it was closed when we
+ // reset the logger - there is no easy way to check) and check that
+ // new messages are appended to it. We use the alternative
+ // invocation of process() here to check it works.
+ vector<LoggerSpecification> spec(1, file_spec.getSpecification());
+ manager.process(spec.begin(), spec.end());
+
+ // Create a new instance of the logger and log three more messages.
+ Logger logger(file_spec.getLoggerName());
+
+ LOG_FATAL(logger, MSG_IDNOTFND).arg("test");
+ ids.push_back(MSG_IDNOTFND);
+
+ LOG_FATAL(logger, MSG_INVMSGID).arg("test").arg("test2");
+ ids.push_back(MSG_INVMSGID);
+
+ LOG_FATAL(logger, MSG_NOMSGID).arg("42");
+ ids.push_back(MSG_NOMSGID);
+
+ // Close the file and check again
+ LoggerManager::reset();
+ checkFileContents(file_spec.getFileName(), ids.begin(), ids.end());
+}
+
+// Check if the file rolls over when it gets above a certain size.
+TEST_F(LoggerManagerTest, FileSizeRollover) {
+ // Set to a suitable minimum that log4cplus can copy with
+ static const size_t SIZE_LIMIT = 204800;
+
+ // Set up the name of the file.
+ SpecificationForFileLogger file_spec;
+ LoggerSpecification& spec = file_spec.getSpecification();
+
+ // Expand the option to ensure that a maximum version size is set.
+ LoggerSpecification::iterator opt = spec.begin();
+ EXPECT_TRUE(opt != spec.end());
+ opt->maxsize = SIZE_LIMIT; // Bytes
+ opt->maxver = 2;
+
+ // The current current output file does not exist (the creation of file_spec
+ // ensures that. Check that previous versions don't either.
+ vector<string> prev_name;
+ for (int i = 0; i < 3; ++i) {
+ prev_name.push_back(file_spec.getFileName() + "." +
+ boost::lexical_cast<string>(i + 1));
+ (void) unlink(prev_name[i].c_str());
+ }
+
+ // Generate an argument for a message that ensures that the message when
+ // logged will be over that size.
+ string big_arg(SIZE_LIMIT, 'x');
+
+ // Set up the file logger
+ LoggerManager manager;
+ manager.process(spec);
+
+ // Log the message twice using different message IDs. This should generate
+ // three files as for the log4cplus implementation, the files appear to
+ // be rolled after the message is logged.
+ {
+ Logger logger(file_spec.getLoggerName());
+ LOG_FATAL(logger, MSG_IDNOTFND).arg(big_arg);
+ LOG_FATAL(logger, MSG_DUPLNS).arg(big_arg);
+ }
+
+ // Check them.
+ LoggerManager::reset(); // Ensure files are closed
+
+ vector<MessageID> ids;
+ ids.push_back(MSG_IDNOTFND);
+ checkFileContents(prev_name[1], ids.begin(), ids.end());
+
+ ids.clear();
+ ids.push_back(MSG_DUPLNS);
+ checkFileContents(prev_name[0], ids.begin(), ids.end());
+
+ // Log another message and check that the files have rotated and that
+ // a .3 version does not exist.
+ manager.process(spec);
+ {
+ Logger logger(file_spec.getLoggerName());
+ LOG_FATAL(logger, MSG_NOMSGTXT).arg(big_arg);
+ }
+
+ LoggerManager::reset(); // Ensure files are closed
+
+ // Check that the files have moved.
+ ids.clear();
+ ids.push_back(MSG_DUPLNS);
+ checkFileContents(prev_name[1], ids.begin(), ids.end());
+
+ ids.clear();
+ ids.push_back(MSG_NOMSGTXT);
+ checkFileContents(prev_name[0], ids.begin(), ids.end());
+
+ // ... and check that the .3 version does not exist.
+ ifstream file3(prev_name[2].c_str(), ifstream::in);
+ EXPECT_FALSE(file3.good());
+
+ // Tidy up
+ for (int i = 0; i < prev_name.size(); ++i) {
+ (void) unlink(prev_name[i].c_str());
+ }
+}
diff --git a/src/lib/log/tests/logger_specification_unittest.cc b/src/lib/log/tests/logger_specification_unittest.cc
new file mode 100644
index 0000000..e416c32
--- /dev/null
+++ b/src/lib/log/tests/logger_specification_unittest.cc
@@ -0,0 +1,96 @@
+// 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.
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <log/logger_specification.h>
+#include <log/output_option.h>
+
+using namespace isc::log;
+using namespace std;
+
+// Check default initialization.
+TEST(LoggerSpecificationTest, DefaultInitialization) {
+ LoggerSpecification spec;
+
+ EXPECT_EQ(string(""), spec.getName());
+ EXPECT_EQ(isc::log::INFO, spec.getSeverity());
+ EXPECT_EQ(0, spec.getDbglevel());
+ EXPECT_FALSE(spec.getAdditive());
+ EXPECT_EQ(0, spec.optionCount());
+}
+
+// Non-default initialization
+TEST(LoggerSpecificationTest, Initialization) {
+ LoggerSpecification spec("alpha", isc::log::ERROR, 42, true);
+
+ EXPECT_EQ(string("alpha"), spec.getName());
+ EXPECT_EQ(isc::log::ERROR, spec.getSeverity());
+ EXPECT_EQ(42, spec.getDbglevel());
+ EXPECT_TRUE(spec.getAdditive());
+ EXPECT_EQ(0, spec.optionCount());
+}
+
+// Get/Set tests
+TEST(LoggerSpecificationTest, SetGet) {
+ LoggerSpecification spec;
+
+ spec.setName("gamma");
+ EXPECT_EQ(string("gamma"), spec.getName());
+
+ spec.setSeverity(isc::log::FATAL);
+ EXPECT_EQ(isc::log::FATAL, spec.getSeverity());
+
+ spec.setDbglevel(7);
+ EXPECT_EQ(7, spec.getDbglevel());
+
+ spec.setAdditive(true);
+ EXPECT_TRUE(spec.getAdditive());
+
+ // Should not affect option count
+ EXPECT_EQ(0, spec.optionCount());
+}
+
+// Check option setting
+TEST(LoggerSpecificationTest, AddOption) {
+ OutputOption option1;
+ option1.destination = OutputOption::DEST_FILE;
+ option1.filename = "/tmp/example.log";
+ option1.maxsize = 123456;
+
+ OutputOption option2;
+ option2.destination = OutputOption::DEST_SYSLOG;
+ option2.facility = "LOCAL7";
+
+ LoggerSpecification spec;
+ spec.addOutputOption(option1);
+ spec.addOutputOption(option2);
+ EXPECT_EQ(2, spec.optionCount());
+
+ // Iterate through them
+ LoggerSpecification::const_iterator i = spec.begin();
+
+ EXPECT_EQ(OutputOption::DEST_FILE, i->destination);
+ EXPECT_EQ(string("/tmp/example.log"), i->filename);
+ EXPECT_EQ(123456, i->maxsize);
+
+ ++i;
+ EXPECT_EQ(OutputOption::DEST_SYSLOG, i->destination);
+ EXPECT_EQ(string("LOCAL7"), i->facility);
+
+ ++i;
+ EXPECT_TRUE(i == spec.end());
+}
diff --git a/src/lib/log/tests/logger_support_test.cc b/src/lib/log/tests/logger_support_test.cc
deleted file mode 100644
index ab3b00e..0000000
--- a/src/lib/log/tests/logger_support_test.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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 Example Program
-///
-/// Simple example program showing how to use the logger.
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <iostream>
-
-#include <log/logger.h>
-#include <log/macros.h>
-#include <log/logger_support.h>
-#include <log/root_logger_name.h>
-
-// Include a set of message definitions.
-#include <log/messagedef.h>
-
-using namespace isc::log;
-
-// Declare logger to use an example.
-Logger logger_ex("example");
-
-// The program is invoked:
-//
-// logger_support_test [-s severity] [-d level ] [local_file]
-//
-// "severity" is one of "debug", "info", "warn", "error", "fatal"
-// "level" is the debug level, a number between 0 and 99
-// "local_file" is the name of a local file.
-//
-// The program sets the attributes on the root logger and logs a set of
-// messages. Looking at the output determines whether the program worked.
-
-int main(int argc, char** argv) {
-
- isc::log::Severity severity = isc::log::INFO; // Default logger severity
- int dbglevel = -1; // Logger debug level
- const char* localfile = NULL; // Local message file
- int option; // For getopt() processing
- Logger logger_dlm("dlm"); // Another example logger
-
- // Parse options
- while ((option = getopt(argc, argv, "s:d:")) != -1) {
- switch (option) {
- case 's':
- if (strcmp(optarg, "debug") == 0) {
- severity = isc::log::DEBUG;
- } else if (strcmp(optarg, "info") == 0) {
- severity = isc::log::INFO;
- } else if (strcmp(optarg, "warn") == 0) {
- severity = isc::log::WARN;
- } else if (strcmp(optarg, "error") == 0) {
- severity = isc::log::ERROR;
- } else if (strcmp(optarg, "fatal") == 0) {
- severity = isc::log::FATAL;
- } else {
- std::cout << "Unrecognised severity option: " <<
- optarg << "\n";
- exit(1);
- }
- break;
-
- case 'd':
- dbglevel = atoi(optarg);
- break;
-
- default:
- std::cout << "Unrecognised option: " <<
- static_cast<char>(option) << "\n";
- }
- }
-
- if (optind < argc) {
- localfile = argv[optind];
- }
-
- // Update the logging parameters
- initLogger("alpha", severity, dbglevel, localfile);
-
- // Log a few messages
- 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");
-
- return (0);
-}
diff --git a/src/lib/log/tests/logger_unittest.cc b/src/lib/log/tests/logger_unittest.cc
index 6a680ef..cb29a8f 100644
--- a/src/lib/log/tests/logger_unittest.cc
+++ b/src/lib/log/tests/logger_unittest.cc
@@ -19,27 +19,16 @@
#include <log/root_logger_name.h>
#include <log/logger.h>
+#include <log/logger_manager.h>
#include <log/messagedef.h>
using namespace isc;
using namespace isc::log;
using namespace std;
-/// \brief Derived logger
-///
-/// Only exists to make the protected static methods in Logger public for
-/// test purposes.
-
-class DerivedLogger : public isc::log::Logger {
-public:
- DerivedLogger(std::string name) : isc::log::Logger(name)
- {}
-
- static void reset() {
- isc::log::Logger::reset();
- }
-};
-
+namespace {
+string ROOT_NAME = "loggertest";
+}
/// \brief Logger Test
///
@@ -48,11 +37,11 @@ public:
class LoggerTest : public ::testing::Test {
public:
- LoggerTest()
- {}
- ~LoggerTest()
- {
- DerivedLogger::reset();
+ LoggerTest() {
+ LoggerManager::init(ROOT_NAME);
+ }
+ ~LoggerTest() {
+ LoggerManager::reset();
}
};
@@ -62,11 +51,10 @@ public:
TEST_F(LoggerTest, Name) {
// Create a logger
- setRootLoggerName("test1");
Logger logger("alpha");
// ... and check the name
- EXPECT_EQ(string("test1.alpha"), logger.getName());
+ EXPECT_EQ(ROOT_NAME + string(".alpha"), logger.getName());
}
// This test attempts to get two instances of a logger with the same name
@@ -74,10 +62,6 @@ TEST_F(LoggerTest, Name) {
TEST_F(LoggerTest, GetLogger) {
- // Set the root logger name (not strictly needed, but this will be the
- // case in the program(.
- setRootLoggerName("test2");
-
const string name1 = "alpha";
const string name2 = "beta";
@@ -98,7 +82,6 @@ TEST_F(LoggerTest, GetLogger) {
TEST_F(LoggerTest, Severity) {
// Create a logger
- setRootLoggerName("test3");
Logger logger("alpha");
// Now check the levels
@@ -129,7 +112,6 @@ TEST_F(LoggerTest, Severity) {
TEST_F(LoggerTest, DebugLevels) {
// Create a logger
- setRootLoggerName("test4");
Logger logger("alpha");
// Debug level should be 0 if not at debug severity
@@ -171,11 +153,9 @@ TEST_F(LoggerTest, DebugLevels) {
TEST_F(LoggerTest, SeverityInheritance) {
- // Create to loggers. We cheat here as we know that the underlying
+ // Create two loggers. We cheat here as we know that the underlying
// implementation (in this case log4cxx) will set a parent-child
// relationship if the loggers are named <parent> and <parent>.<child>.
-
- setRootLoggerName("test5");
Logger parent("alpha");
Logger child("alpha.beta");
@@ -203,11 +183,9 @@ TEST_F(LoggerTest, SeverityInheritance) {
TEST_F(LoggerTest, EffectiveSeverityInheritance) {
- // Create to loggers. We cheat here as we know that the underlying
+ // Create two loggers. We cheat here as we know that the underlying
// implementation (in this case log4cxx) will set a parent-child
// relationship if the loggers are named <parent> and <parent>.<child>.
-
- setRootLoggerName("test6");
Logger parent("test6");
Logger child("test6.beta");
@@ -242,7 +220,6 @@ TEST_F(LoggerTest, EffectiveSeverityInheritance) {
TEST_F(LoggerTest, IsXxxEnabled) {
- setRootLoggerName("test7");
Logger logger("test7");
logger.setSeverity(isc::log::INFO);
@@ -313,7 +290,6 @@ TEST_F(LoggerTest, IsXxxEnabled) {
TEST_F(LoggerTest, IsDebugEnabledLevel) {
- setRootLoggerName("test8");
Logger logger("test8");
int MID_LEVEL = (MIN_DEBUG_LEVEL + MAX_DEBUG_LEVEL) / 2;
diff --git a/src/lib/log/tests/output_option_unittest.cc b/src/lib/log/tests/output_option_unittest.cc
new file mode 100644
index 0000000..70dc4ba
--- /dev/null
+++ b/src/lib/log/tests/output_option_unittest.cc
@@ -0,0 +1,66 @@
+// 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.
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <log/output_option.h>
+
+using namespace isc::log;
+using namespace std;
+
+// As OutputOption is a struct, the only meaningful test is to check that it
+// initializes correctly.
+
+TEST(OutputOptionTest, Initialization) {
+ OutputOption option;
+
+ EXPECT_EQ(OutputOption::DEST_CONSOLE, option.destination);
+ EXPECT_EQ(OutputOption::STR_STDERR, option.stream);
+ EXPECT_FALSE(option.flush);
+ EXPECT_EQ(string(""), option.facility);
+ EXPECT_EQ(string(""), option.filename);
+ EXPECT_EQ(0, option.maxsize);
+ EXPECT_EQ(0, option.maxver);
+}
+
+TEST(OutputOption, getDestination) {
+ EXPECT_EQ(OutputOption::DEST_CONSOLE, getDestination("console"));
+ EXPECT_EQ(OutputOption::DEST_CONSOLE, getDestination("CONSOLE"));
+ EXPECT_EQ(OutputOption::DEST_CONSOLE, getDestination("CoNSoLE"));
+ EXPECT_EQ(OutputOption::DEST_FILE, getDestination("file"));
+ EXPECT_EQ(OutputOption::DEST_FILE, getDestination("FILE"));
+ EXPECT_EQ(OutputOption::DEST_FILE, getDestination("fIlE"));
+ EXPECT_EQ(OutputOption::DEST_SYSLOG, getDestination("syslog"));
+ EXPECT_EQ(OutputOption::DEST_SYSLOG, getDestination("SYSLOG"));
+ EXPECT_EQ(OutputOption::DEST_SYSLOG, getDestination("SYSlog"));
+
+ // bad values should default to DEST_CONSOLE
+ EXPECT_EQ(OutputOption::DEST_CONSOLE, getDestination("SOME_BAD_VALUE"));
+}
+
+TEST(OutputOption, getStream) {
+ EXPECT_EQ(OutputOption::STR_STDOUT, getStream("stdout"));
+ EXPECT_EQ(OutputOption::STR_STDOUT, getStream("STDOUT"));
+ EXPECT_EQ(OutputOption::STR_STDOUT, getStream("STdouT"));
+ EXPECT_EQ(OutputOption::STR_STDERR, getStream("stderr"));
+ EXPECT_EQ(OutputOption::STR_STDERR, getStream("STDERR"));
+ EXPECT_EQ(OutputOption::STR_STDERR, getStream("StDeRR"));
+
+ // bad values should default to stdout
+ EXPECT_EQ(OutputOption::STR_STDOUT, getStream("some bad value"));
+ EXPECT_EQ(OutputOption::STR_STDOUT, getStream(""));
+}
+
diff --git a/src/lib/log/tests/run_time_init_test.sh.in b/src/lib/log/tests/run_time_init_test.sh.in
deleted file mode 100755
index e48a781..0000000
--- a/src/lib/log/tests/run_time_init_test.sh.in
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/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.
-
-failcount=0
-localmes=@abs_builddir@/localdef_mes_$$
-tempfile=@abs_builddir@/run_time_init_test_tempfile_$$
-
-passfail() {
- if [ $1 -eq 0 ]; then
- echo "pass"
- else
- echo "FAIL"
- fi
- failcount=`expr $failcount + $1`
-}
-
-# Create the local message file for testing
-
-cat > $localmes << .
-\$PREFIX MSG_
-% NOTHERE this message is not in the global dictionary
-% READERR replacement read error, parameters: '%1' and '%2'
-% RDLOCMES replacement read local message file, parameter is '%1'
-.
-
-echo -n "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
-.
-./logger_support_test | cut -d' ' -f3- | diff $tempfile -
-passfail $?
-
-echo -n "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
-.
-./logger_support_test -s error | cut -d' ' -f3- | diff $tempfile -
-passfail $?
-
-echo -n "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
-.
-./logger_support_test -s debug -d 25 | cut -d' ' -f3- | diff $tempfile -
-passfail $?
-
-echo -n "4. 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'
-.
-./logger_support_test -s warn $localmes | cut -d' ' -f3- | diff $tempfile -
-passfail $?
-
-rm -f $localmes
-rm -f $tempfile
-
-if [ $failcount -eq 0 ]; then
- echo "PASS: run_time_init_test"
-elif [ $failcount -eq 1 ]; then
- echo "FAIL: run_time_init_test - 1 test failed"
-else
- echo "FAIL: run_time_init_test - $failcount tests failed"
-fi
-
-exit $failcount
diff --git a/src/lib/log/tests/run_unittests.cc b/src/lib/log/tests/run_unittests.cc
index e84ae5f..8a9d1e5 100644
--- a/src/lib/log/tests/run_unittests.cc
+++ b/src/lib/log/tests/run_unittests.cc
@@ -15,8 +15,11 @@
#include <gtest/gtest.h>
#include <util/unittests/run_all.h>
+#include <log/logger_support.h>
+
int
main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
+ isc::log::initLogger();
return (isc::util::unittests::run_all());
}
diff --git a/src/lib/log/tests/severity_test.sh.in b/src/lib/log/tests/severity_test.sh.in
new file mode 100755
index 0000000..cd8c1b9
--- /dev/null
+++ b/src/lib/log/tests/severity_test.sh.in
@@ -0,0 +1,77 @@
+#!/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="Severity test"
+echo $testname
+
+failcount=0
+tempfile=@abs_builddir@/severity_test_tempfile_$$
+
+passfail() {
+ if [ $1 -eq 0 ]; then
+ echo " -- pass"
+ else
+ echo " ** FAIL"
+ failcount=`expr $failcount + $1`
+ fi
+}
+
+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
+.
+./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
+.
+./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
+.
+./logger_example -c stdout -s debug -d 25 | cut -d' ' -f3- | diff $tempfile -
+passfail $?
+
+rm -f $tempfile
+
+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/tempdir.h.in b/src/lib/log/tests/tempdir.h.in
new file mode 100644
index 0000000..366fea3
--- /dev/null
+++ b/src/lib/log/tests/tempdir.h.in
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef __TEMPDIR_H
+#define __TEMPDIR_H
+
+/// \brief Define temporary directory
+///
+/// Defines the temporary directory in which temporary files used by the
+/// unit tests are created.
+
+#include <string>
+
+namespace {
+std::string TEMP_DIR("@builddir@");
+}
+
+#endif // __TEMPDIR_H
More information about the bind10-changes
mailing list