Browse Source

[trac510] added a new library for statistics counters

  - added a library for statistics counters to hold counter items
  - added a library for statistics counters to hold a set of counters
    for per zone or per process counters
Yoshitaka Aharen 14 years ago
parent
commit
d23827556e

+ 2 - 0
configure.ac

@@ -873,6 +873,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/util/tests/Makefile
                  src/lib/acl/Makefile
                  src/lib/acl/tests/Makefile
+                 src/lib/statistics/Makefile
+                 src/lib/statistics/tests/Makefile
                  tests/Makefile
                  tests/system/Makefile
                  tests/tools/Makefile

+ 1 - 0
src/bin/auth/Makefile.am

@@ -64,6 +64,7 @@ b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 b10_auth_LDADD += $(top_builddir)/src/lib/log/liblog.la
 b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
 b10_auth_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
+b10_auth_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
 b10_auth_LDADD += $(SQLITE_LIBS)
 
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir

+ 3 - 3
src/bin/auth/auth_srv.cc

@@ -661,9 +661,9 @@ void
 AuthSrvImpl::incCounter(const int protocol) {
     // Increment query counter.
     if (protocol == IPPROTO_UDP) {
-        counters_.inc(AuthCounters::COUNTER_UDP_QUERY);
+        counters_.inc(AuthCounters::SERVER_UDP_QUERY);
     } else if (protocol == IPPROTO_TCP) {
-        counters_.inc(AuthCounters::COUNTER_TCP_QUERY);
+        counters_.inc(AuthCounters::SERVER_TCP_QUERY);
     } else {
         // unknown protocol
         isc_throw(Unexpected, "Unknown protocol: " << protocol);
@@ -740,7 +740,7 @@ bool AuthSrv::submitStatistics() const {
 }
 
 uint64_t
-AuthSrv::getCounter(const AuthCounters::CounterType type) const {
+AuthSrv::getCounter(const AuthCounters::ServerCounterType type) const {
     return (impl_->counters_.getCounter(type));
 }
 

+ 1 - 1
src/bin/auth/auth_srv.h

@@ -343,7 +343,7 @@ public:
     /// \param type Type of a counter to get the value of
     ///
     /// \return the value of the counter.
-    uint64_t getCounter(const AuthCounters::CounterType type) const;
+    uint64_t getCounter(const AuthCounters::ServerCounterType type) const;
 
     /**
      * \brief Set and get the addresses we listen on.

+ 1 - 0
src/bin/auth/benchmarks/Makefile.am

@@ -28,5 +28,6 @@ query_bench_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
 query_bench_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
 query_bench_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 query_bench_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
+query_bench_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
 query_bench_LDADD += $(SQLITE_LIBS)
 

+ 40 - 23
src/bin/auth/statistics.cc

@@ -18,45 +18,64 @@
 #include <cc/data.h>
 #include <cc/session.h>
 
+#include <statistics/counter.h>
+#include <statistics/counter_dict.h>
+
 #include <sstream>
 #include <iostream>
 
+#include <boost/noncopyable.hpp>
+
 using namespace isc::auth;
+using namespace isc::statistics;
 
 // TODO: We need a namespace ("auth_server"?) to hold
-// AuthSrv and AuthCounters.
+//        AuthSrv and AuthCounters.
 
-class AuthCountersImpl {
-private:
-    // prohibit copy
-    AuthCountersImpl(const AuthCountersImpl& source);
-    AuthCountersImpl& operator=(const AuthCountersImpl& source);
+// TODO: Make use of wrappers like isc::dns::Opcode
+//        for counter item type.
+
+class AuthCountersImpl : boost::noncopyable {
 public:
     AuthCountersImpl();
     ~AuthCountersImpl();
-    void inc(const AuthCounters::CounterType type);
+    void inc(const AuthCounters::ServerCounterType type);
+    void inc(const std::string& zone,
+             const AuthCounters::PerZoneCounterType type);
     bool submitStatistics() const;
     void setStatisticsSession(isc::cc::AbstractSession* statistics_session);
     // Currently for testing purpose only
-    uint64_t getCounter(const AuthCounters::CounterType type) const;
+    uint64_t getCounter(const AuthCounters::ServerCounterType type) const;
 private:
-    std::vector<uint64_t> counters_;
+    Counter server_counter_;
+    CounterDictionary per_zone_counter_;
     isc::cc::AbstractSession* statistics_session_;
 };
 
 AuthCountersImpl::AuthCountersImpl() :
     // initialize counter
-    // size: AuthCounters::COUNTER_TYPES, initial value: 0
-    counters_(AuthCounters::COUNTER_TYPES, 0),
+    // size of server_counter_: AuthCounters::SERVER_COUNTER_TYPES
+    // size of per_zone_counter_: AuthCounters::PER_ZONE_COUNTER_TYPES
+    server_counter_(AuthCounters::SERVER_COUNTER_TYPES),
+    per_zone_counter_(AuthCounters::PER_ZONE_COUNTER_TYPES),
     statistics_session_(NULL)
-{}
+{
+    per_zone_counter_.addElement("_SERVER_");
+}
 
 AuthCountersImpl::~AuthCountersImpl()
 {}
 
 void
-AuthCountersImpl::inc(const AuthCounters::CounterType type) {
-    ++counters_.at(type);
+AuthCountersImpl::inc(const AuthCounters::ServerCounterType type) {
+    server_counter_.inc(type);
+}
+
+void
+AuthCountersImpl::inc(const std::string& zone,
+                      const AuthCounters::PerZoneCounterType type)
+{
+    per_zone_counter_[zone].inc(type);
 }
 
 bool
@@ -69,9 +88,9 @@ AuthCountersImpl::submitStatistics() const {
     statistics_string << "{\"command\": [\"set\","
                       <<   "{ \"stats_data\": "
                       <<     "{ \"auth.queries.udp\": "
-                      <<     counters_.at(AuthCounters::COUNTER_UDP_QUERY)
+                      <<     server_counter_.get(AuthCounters::SERVER_UDP_QUERY)
                       <<     ", \"auth.queries.tcp\": "
-                      <<     counters_.at(AuthCounters::COUNTER_TCP_QUERY)
+                      <<     server_counter_.get(AuthCounters::SERVER_TCP_QUERY)
                       <<   " }"
                       <<   "}"
                       << "]}";
@@ -107,19 +126,17 @@ AuthCountersImpl::setStatisticsSession
 
 // Currently for testing purpose only
 uint64_t
-AuthCountersImpl::getCounter(const AuthCounters::CounterType type) const {
-    return (counters_.at(type));
+AuthCountersImpl::getCounter(const AuthCounters::ServerCounterType type) const {
+    return (server_counter_.get(type));
 }
 
 AuthCounters::AuthCounters() : impl_(new AuthCountersImpl())
 {}
 
-AuthCounters::~AuthCounters() {
-    delete impl_;
-}
+AuthCounters::~AuthCounters() {}
 
 void
-AuthCounters::inc(const AuthCounters::CounterType type) {
+AuthCounters::inc(const AuthCounters::ServerCounterType type) {
     impl_->inc(type);
 }
 
@@ -136,6 +153,6 @@ AuthCounters::setStatisticsSession
 }
 
 uint64_t
-AuthCounters::getCounter(const AuthCounters::CounterType type) const {
+AuthCounters::getCounter(const AuthCounters::ServerCounterType type) const {
     return (impl_->getCounter(type));
 }

+ 13 - 7
src/bin/auth/statistics.h

@@ -17,6 +17,7 @@
 
 #include <cc/session.h>
 #include <stdint.h>
+#include <boost/scoped_ptr.hpp>
 
 class AuthCountersImpl;
 
@@ -51,13 +52,18 @@ class AuthCountersImpl;
 /// \todo Consider overhead of \c AuthCounters::inc()
 class AuthCounters {
 private:
-    AuthCountersImpl* impl_;
+    boost::scoped_ptr<AuthCountersImpl> impl_;
 public:
     // Enum for the type of counter
-    enum CounterType {
-        COUNTER_UDP_QUERY = 0,  ///< COUNTER_UDP_QUERY: counter for UDP queries
-        COUNTER_TCP_QUERY = 1,  ///< COUNTER_TCP_QUERY: counter for TCP queries
-        COUNTER_TYPES = 2 ///< The number of defined counters
+    enum ServerCounterType {
+        SERVER_UDP_QUERY = 0,  ///< SERVER_UDP_QUERY: counter for UDP queries
+        SERVER_TCP_QUERY = 1,  ///< SERVER_TCP_QUERY: counter for TCP queries
+        SERVER_COUNTER_TYPES = 2 ///< The number of defined counters
+    };
+    enum PerZoneCounterType {
+        ZONE_UDP_QUERY = 0,  ///< ZONE_UDP_QUERY: counter for UDP queries
+        ZONE_TCP_QUERY = 1,  ///< ZONE_TCP_QUERY: counter for TCP queries
+        PER_ZONE_COUNTER_TYPES = 2 ///< The number of defined counters
     };
     /// The constructor.
     ///
@@ -79,7 +85,7 @@ public:
     ///
     /// usage: counter.inc(CounterType::COUNTER_UDP_QUERY);
     /// 
-    void inc(const CounterType type);
+    void inc(const ServerCounterType type);
 
     /// \brief Submit statistics counters to statistics module.
     ///
@@ -130,7 +136,7 @@ public:
     ///
     /// \return the value of the counter specified by \a type.
     ///
-    uint64_t getCounter(const AuthCounters::CounterType type) const;
+    uint64_t getCounter(const AuthCounters::ServerCounterType type) const;
 };
 
 #endif // __STATISTICS_H

+ 1 - 0
src/bin/auth/tests/Makefile.am

@@ -56,6 +56,7 @@ run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
 run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
 run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
 run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
+run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 endif
 

+ 6 - 6
src/bin/auth/tests/auth_srv_unittest.cc

@@ -702,7 +702,7 @@ TEST_F(AuthSrvTest, cacheSlots) {
 // Submit UDP normal query and check query counter
 TEST_F(AuthSrvTest, queryCounterUDPNormal) {
     // The counter should be initialized to 0.
-    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_UDP_QUERY));
+    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
     // Create UDP message and process.
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                        default_qid, Name("example.com"),
@@ -711,13 +711,13 @@ TEST_F(AuthSrvTest, queryCounterUDPNormal) {
     server.processMessage(*io_message, parse_message, response_obuffer,
                           &dnsserv);
     // After processing UDP query, the counter should be 1.
-    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_UDP_QUERY));
+    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
 }
 
 // Submit TCP normal query and check query counter
 TEST_F(AuthSrvTest, queryCounterTCPNormal) {
     // The counter should be initialized to 0.
-    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
     // Create TCP message and process.
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                        default_qid, Name("example.com"),
@@ -726,13 +726,13 @@ TEST_F(AuthSrvTest, queryCounterTCPNormal) {
     server.processMessage(*io_message, parse_message, response_obuffer,
                           &dnsserv);
     // After processing TCP query, the counter should be 1.
-    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
 }
 
 // Submit TCP AXFR query and check query counter
 TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
     // The counter should be initialized to 0.
-    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
     UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                          Name("example.com"), RRClass::IN(), RRType::AXFR());
     createRequestPacket(request_message, IPPROTO_TCP);
@@ -740,7 +740,7 @@ TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
     // so we shouldn't have to respond.
     server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
     // After processing TCP AXFR query, the counter should be 1.
-    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
 }
 
 // class for queryCounterUnexpected test

+ 13 - 15
src/bin/auth/tests/statistics_unittest.cc

@@ -141,25 +141,23 @@ AuthCountersTest::MockSession::setThrowSessionTimeout(bool flag) {
 
 TEST_F(AuthCountersTest, incrementUDPCounter) {
     // The counter should be initialized to 0.
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::COUNTER_UDP_QUERY));
-    EXPECT_NO_THROW(counters.inc(AuthCounters::COUNTER_UDP_QUERY));
+    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_UDP_QUERY));
+    EXPECT_NO_THROW(counters.inc(AuthCounters::SERVER_UDP_QUERY));
     // After increment, the counter should be 1.
-    EXPECT_EQ(1, counters.getCounter(AuthCounters::COUNTER_UDP_QUERY));
+    EXPECT_EQ(1, counters.getCounter(AuthCounters::SERVER_UDP_QUERY));
 }
 
 TEST_F(AuthCountersTest, incrementTCPCounter) {
     // The counter should be initialized to 0.
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::COUNTER_TCP_QUERY));
-    EXPECT_NO_THROW(counters.inc(AuthCounters::COUNTER_TCP_QUERY));
+    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_TCP_QUERY));
+    EXPECT_NO_THROW(counters.inc(AuthCounters::SERVER_TCP_QUERY));
     // After increment, the counter should be 1.
-    EXPECT_EQ(1, counters.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+    EXPECT_EQ(1, counters.getCounter(AuthCounters::SERVER_TCP_QUERY));
 }
 
 TEST_F(AuthCountersTest, incrementInvalidCounter) {
-    // Expect to throw isc::InvalidParameter if the type of the counter is
-    // invalid.
-    EXPECT_THROW(counters.inc(AuthCounters::COUNTER_TYPES),
-                 std::out_of_range);
+    // Expect to die.
+    EXPECT_DEATH(counters.inc(AuthCounters::SERVER_COUNTER_TYPES), "Assertion.+failed");
 }
 
 TEST_F(AuthCountersTest, submitStatisticsWithoutSession) {
@@ -186,14 +184,14 @@ TEST_F(AuthCountersTest, submitStatistics) {
     // Validate if it submits correct data.
 
     // Counters should be initialized to 0.
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::COUNTER_UDP_QUERY));
-    EXPECT_EQ(0, counters.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_UDP_QUERY));
+    EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_TCP_QUERY));
 
     // UDP query counter is set to 2.
-    counters.inc(AuthCounters::COUNTER_UDP_QUERY);
-    counters.inc(AuthCounters::COUNTER_UDP_QUERY);
+    counters.inc(AuthCounters::SERVER_UDP_QUERY);
+    counters.inc(AuthCounters::SERVER_UDP_QUERY);
     // TCP query counter is set to 1.
-    counters.inc(AuthCounters::COUNTER_TCP_QUERY);
+    counters.inc(AuthCounters::SERVER_TCP_QUERY);
     counters.submitStatistics();
 
     // Destination is "Stats".

+ 1 - 1
src/lib/Makefile.am

@@ -1,3 +1,3 @@
 SUBDIRS = exceptions util log cryptolink dns cc config acl python xfr \
           bench asiolink asiodns nsas cache resolve testutils datasrc \
-          server_common
+          server_common statistics

+ 24 - 0
src/lib/statistics/Makefile.am

@@ -0,0 +1,24 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/statistics -I$(top_builddir)/src/lib/statistics
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+if USE_CLANGPP
+# clang++ complains about unused function parameters in some boost header
+# files.
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
+
+lib_LTLIBRARIES = libstatistics.la
+libstatistics_la_SOURCES  = counter.h counter.cc
+libstatistics_la_SOURCES  += counter_dict.h counter_dict.cc
+
+CLEANFILES = *.gcno *.gcda

+ 65 - 0
src/lib/statistics/counter.cc

@@ -0,0 +1,65 @@
+#include <vector>
+#include <cassert>
+#include <boost/unordered_map.hpp>
+
+#include <statistics/counter.h>
+
+namespace {
+const unsigned int InitialValue = 0;
+} // namespace
+
+namespace isc {
+namespace statistics {
+
+class CounterImpl {
+    private:
+        CounterImpl(const CounterImpl& source);
+        CounterImpl& operator=(const CounterImpl& source);
+    private:
+        std::vector<Counter::Value> counters_;
+    public:
+        CounterImpl(const size_t nelements);
+        ~CounterImpl();
+        void inc(const Counter::Type&);
+        const Counter::Value& get(const Counter::Type&) const;
+};
+
+CounterImpl::CounterImpl(const size_t items) :
+    counters_(items, InitialValue)
+{
+    assert(items != 0);
+}
+
+CounterImpl::~CounterImpl() {}
+
+void
+CounterImpl::inc(const Counter::Type& type) {
+    assert(type < counters_.size());
+    ++counters_.at(type);
+    return;
+}
+
+const Counter::Value&
+CounterImpl::get(const Counter::Type& type) const {
+    assert(type < counters_.size());
+    return (counters_.at(type));
+}
+
+Counter::Counter(const size_t items) : impl_(new CounterImpl(items))
+{}
+
+Counter::~Counter() {}
+
+void
+Counter::inc(const Type& type) {
+    impl_->inc(type);
+    return;
+}
+
+const Counter::Value&
+Counter::get(const Type& type) const {
+    return (impl_->get(type));
+}
+
+}   // namespace statistics
+}   // namespace isc

+ 54 - 0
src/lib/statistics/counter.h

@@ -0,0 +1,54 @@
+#ifndef __COUNTER_H
+#define __COUNTER_H 1
+
+#include <boost/scoped_ptr.hpp>
+
+namespace isc {
+namespace statistics {
+
+// forward declaration for pImpl idiom
+class CounterImpl;
+
+class Counter {
+    private:
+        Counter(const Counter& source);
+        Counter& operator=(const Counter& source);
+        boost::scoped_ptr<CounterImpl> impl_;
+    public:
+        typedef unsigned int Type;
+        typedef unsigned int Value;
+
+        /// The constructor.
+        ///
+        /// This constructor is mostly exception free. But it may still throw
+        /// a standard exception if memory allocation fails inside the method.
+        ///
+        /// Note: \a items must be greater than 0. Otherwise this constructor
+        /// causes an assertion failure.
+        /// 
+        /// \param items A number of counter items to hold (greater than 0)
+        Counter(const size_t items);
+
+        /// The destructor.
+        ///
+        /// This method never throws an exception.
+        ~Counter();
+
+        /// \brief Increment a counter item specified with \a type.
+        ///
+        /// Note: \a type must be valid counter type. Otherwise this method
+        /// causes an assertion failure.
+        /// 
+        /// \param type %Counter item to increment
+        void inc(const Type& type);
+
+        /// \brief Get the value of a counter item specified with \a type.
+        /// 
+        /// \param type %Counter item to get the value of
+        const Value& get(const Type& type) const;
+};
+
+}   // namespace statistics
+}   // namespace isc
+
+#endif

+ 246 - 0
src/lib/statistics/counter_dict.cc

@@ -0,0 +1,246 @@
+#include <cassert>
+#include <stdexcept>
+#include <iterator>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/unordered_map.hpp>
+
+#include <statistics/counter_dict.h>
+
+namespace {
+typedef boost::shared_ptr<isc::statistics::Counter> CounterPtr;
+typedef boost::unordered_map<std::string, CounterPtr> DictionaryMap;
+}
+
+namespace isc {
+namespace statistics {
+
+// Implementation detail class for CounterDictionary::ConstIterator
+class CounterDictionaryConstIteratorImpl;
+
+class CounterDictionaryImpl : boost::noncopyable {
+    private:
+        DictionaryMap dictionary_;
+        std::vector<std::string> elements_;
+        const size_t items_;
+        // Default constructor is forbidden; number of counter items must be
+        // specified at the construction of this class.
+        CounterDictionaryImpl();
+    public:
+        CounterDictionaryImpl(const size_t items);
+        ~CounterDictionaryImpl();
+        void addElement(const std::string& element);
+        void deleteElement(const std::string& elemet);
+        Counter& getElement(const std::string& element);
+    public:
+        CounterDictionaryConstIteratorImpl begin() const;
+        CounterDictionaryConstIteratorImpl end() const;
+};
+
+// Constructor with number of items
+CounterDictionaryImpl::CounterDictionaryImpl(const size_t items) :
+    items_(items)
+{
+    // The number of the items must not be 0.
+    assert(items != 0);
+}
+
+// Destructor
+CounterDictionaryImpl::~CounterDictionaryImpl() {}
+
+void
+CounterDictionaryImpl::addElement(const std::string& element) {
+    // throw if the element already exists
+    if (dictionary_.count(element) != 0) {
+        isc_throw(isc::InvalidParameter,
+                  "Element " << element << " already exists");
+    }
+    // Create a new Counter and add to the map
+    dictionary_.insert(
+        DictionaryMap::value_type(element, CounterPtr(new Counter(items_))));
+}
+
+void
+CounterDictionaryImpl::deleteElement(const std::string& element) {
+    size_t result = dictionary_.erase(element);
+    if (result != 1) {
+        // If an element with specified name does not exist, throw
+        // isc::OutOfRange.
+        isc_throw(isc::OutOfRange, "Element " << element << " does not exist");
+    }
+}
+
+Counter&
+CounterDictionaryImpl::getElement(const std::string& element) {
+    try {
+        return (*(dictionary_.at(element)));
+    } catch (const std::out_of_range &e) {
+        // If an element with specified name does not exist, throw
+        // isc::OutOfRange.
+        isc_throw(isc::OutOfRange, "Element " << element << " does not exist");
+    }
+}
+
+// Constructor
+// Initialize impl_
+CounterDictionary::CounterDictionary(const size_t items) :
+    impl_(new CounterDictionaryImpl(items))
+{}
+
+// Destructor
+// impl_ will be freed automatically with scoped_ptr
+CounterDictionary::~CounterDictionary() {}
+
+void
+CounterDictionary::addElement(const std::string& element) {
+    impl_->addElement(element);
+}
+
+void
+CounterDictionary::deleteElement(const std::string& element) {
+    impl_->deleteElement(element);
+}
+
+Counter&
+CounterDictionary::getElement(const std::string& element) const {
+    return (impl_->getElement(element));
+}
+
+Counter&
+CounterDictionary::operator[](const std::string& element) const {
+    return (impl_->getElement(element));
+}
+
+// Implementation detail class for CounterDictionary::ConstIterator
+class CounterDictionaryConstIteratorImpl {
+    public:
+        CounterDictionaryConstIteratorImpl();
+        ~CounterDictionaryConstIteratorImpl();
+        CounterDictionaryConstIteratorImpl(
+            const CounterDictionaryConstIteratorImpl &other);
+        CounterDictionaryConstIteratorImpl &operator=(
+            const CounterDictionaryConstIteratorImpl &source);
+        CounterDictionaryConstIteratorImpl(
+            DictionaryMap::const_iterator iterator);
+    public:
+        void increment();
+        CounterDictionary::ValueType dereference() const;
+        bool equal(const CounterDictionaryConstIteratorImpl& other) const;
+    private:
+        DictionaryMap::const_iterator iterator_;
+};
+
+CounterDictionaryConstIteratorImpl::CounterDictionaryConstIteratorImpl() {}
+
+CounterDictionaryConstIteratorImpl::~CounterDictionaryConstIteratorImpl() {}
+
+// Copy constructor: deep copy of iterator_
+CounterDictionaryConstIteratorImpl::CounterDictionaryConstIteratorImpl(
+    const CounterDictionaryConstIteratorImpl &other) :
+    iterator_(other.iterator_)
+{}
+
+// Assignment operator: deep copy of iterator_
+CounterDictionaryConstIteratorImpl &
+CounterDictionaryConstIteratorImpl::operator=(
+    const CounterDictionaryConstIteratorImpl &source)
+{
+    iterator_ = source.iterator_;
+    return (*this);
+}
+
+// Constructor from implementation detail DictionaryMap::const_iterator
+CounterDictionaryConstIteratorImpl::CounterDictionaryConstIteratorImpl(
+    DictionaryMap::const_iterator iterator) :
+    iterator_(iterator)
+{}
+
+CounterDictionaryConstIteratorImpl
+CounterDictionaryImpl::begin() const {
+    return (CounterDictionaryConstIteratorImpl(dictionary_.begin()));
+}
+
+CounterDictionaryConstIteratorImpl
+CounterDictionaryImpl::end() const {
+    return (CounterDictionaryConstIteratorImpl(dictionary_.end()));
+}
+
+void
+CounterDictionaryConstIteratorImpl::increment() {
+    ++iterator_;
+    return;
+}
+
+CounterDictionary::ValueType
+CounterDictionaryConstIteratorImpl::dereference() const {
+    return (CounterDictionary::ValueType(iterator_->first,
+                                         *(iterator_->second)));
+}
+
+bool
+CounterDictionaryConstIteratorImpl::equal(
+    const CounterDictionaryConstIteratorImpl& other) const
+{
+    return (iterator_ == other.iterator_);
+}
+
+CounterDictionary::ConstIterator
+CounterDictionary::begin() const {
+    return (CounterDictionary::ConstIterator(
+               CounterDictionaryConstIteratorImpl(impl_->begin())));
+}
+
+CounterDictionary::ConstIterator
+CounterDictionary::end() const {
+    return (CounterDictionary::ConstIterator(
+               CounterDictionaryConstIteratorImpl(impl_->end())));
+}
+
+CounterDictionary::ConstIterator::ConstIterator() :
+    impl_(new CounterDictionaryConstIteratorImpl())
+{}
+
+CounterDictionary::ConstIterator::~ConstIterator() {}
+
+// Copy constructor: deep copy of impl_
+CounterDictionary::ConstIterator::ConstIterator(
+    const CounterDictionary::ConstIterator& source) :
+    impl_(new CounterDictionaryConstIteratorImpl(*(source.impl_)))
+{}
+
+// Assignment operator: deep copy of impl_
+CounterDictionary::ConstIterator &
+CounterDictionary::ConstIterator::operator=(
+    const CounterDictionary::ConstIterator &source)
+{
+    *impl_ = *source.impl_;
+    return (*this);
+}
+
+// The constructor from implementation detail
+CounterDictionary::ConstIterator::ConstIterator(
+    const CounterDictionaryConstIteratorImpl& source) :
+    impl_(new CounterDictionaryConstIteratorImpl(source))
+{}
+
+const CounterDictionary::ValueType
+CounterDictionary::ConstIterator::dereference() const
+{
+    return (impl_->dereference());
+}
+
+bool
+CounterDictionary::ConstIterator::equal(
+    CounterDictionary::ConstIterator const& other) const
+{
+    return (impl_->equal(*(other.impl_)));
+}
+
+void
+CounterDictionary::ConstIterator::increment() {
+    impl_->increment();
+    return;
+}
+
+}   // namespace statistics
+}   // namespace isc

+ 151 - 0
src/lib/statistics/counter_dict.h

@@ -0,0 +1,151 @@
+#ifndef __COUNTER_DICT_H
+#define __COUNTER_DICT_H 1
+
+#include <string>
+#include <vector>
+#include <utility>
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+
+#include <exceptions/exceptions.h>
+#include <statistics/counter.h>
+
+namespace isc {
+namespace statistics {
+
+class CounterDictionaryImpl;
+class CounterDictionaryConstIteratorImpl;
+
+class CounterDictionary : boost::noncopyable {
+    private:
+        boost::scoped_ptr<CounterDictionaryImpl> impl_;
+        // Default constructor is forbidden; number of counter items must be
+        // specified at the construction of this class.
+        CounterDictionary();
+    public:
+        /// The constructor.
+        /// This constructor is mostly exception free. But it may still throw
+        /// a standard exception if memory allocation fails inside the method.
+        ///
+        /// Note: \a items must be greater than 0; otherwise thist constructor
+        /// causes assertion failure.
+        /// 
+        /// \param items A number of counter items to hold (greater than 0)
+        CounterDictionary(const size_t items);
+
+        /// The destructor.
+        ///
+        /// This method never throws an exception.
+        ~CounterDictionary();
+
+        /// \brief Add an element
+        ///
+        /// \throw isc::InvalidParameter \a element alerady exists.
+        ///
+        /// \param element A name of the element to append
+        void addElement(const std::string& element);
+
+        /// \brief Delete
+        ///
+        /// \throw isc::OutOfRange \a element does not exist.
+        ///
+        /// \param element A name of the element to delete
+        void deleteElement(const std::string& element);
+
+        /// \brief Lookup
+        ///
+        /// \throw isc::OutOfRange \a element does not exist.
+        ///
+        /// \param element A name of the element to get the counters
+        Counter& getElement(const std::string &element) const;
+
+        /// Same as getElement()
+        Counter& operator[](const std::string &element) const;
+
+        /// Typedef for the pair which represents an element of
+        /// CounterDictionary. This type is used for the iterator.
+        typedef std::pair<const std::string&, const Counter&> ValueType;
+
+        /// \brief \c ConstIterator is a constant iterator that provides an
+        /// interface for accessing elements stored in CounterDictionary.
+        ///
+        /// This class is derived from boost::iterator_facade and uses pImpl
+        /// idiom not to expose implementation detail of
+        /// CounterDictionary::iterator.
+        ///
+        /// It is intended to walk through the elements when sending the
+        /// counters to statistics module.
+        class ConstIterator :
+            public boost::iterator_facade<ConstIterator,
+                                   const ValueType,
+                                   boost::forward_traversal_tag>
+        {
+            private:
+                boost::scoped_ptr<CounterDictionaryConstIteratorImpl> impl_;
+            public:
+                /// The constrcutor.
+                ///
+                /// This constructor is mostly exception free. But it may still
+                /// throw a standard exception if memory allocation fails
+                /// inside the method.
+                ConstIterator();
+                /// The destrcutor.
+                /// 
+                /// This method never throws an exception.
+                ~ConstIterator();
+                /// The assignment operator.
+                ///
+                /// This method is mostly exception free. But it may still
+                /// throw a standard exception if memory allocation fails
+                /// inside the method.
+                ConstIterator& operator=(const ConstIterator &source);
+                /// The copy constructor.
+                ///
+                /// This constructor is mostly exception free. But it may still
+                /// throw a standard exception if memory allocation fails
+                /// inside the method.
+                ConstIterator(const ConstIterator& source);
+                /// The constructor from implementation detail.
+                /// 
+                /// This method is used to create an instance of ConstIterator
+                /// by CounterDict::begin() and CounterDict::end().
+                ///
+                /// This constructor is mostly exception free. But it may still
+                /// throw a standard exception if memory allocation fails
+                /// inside the method.
+                ConstIterator(
+                    const CounterDictionaryConstIteratorImpl& source);
+            private:
+                /// \brief An internal method to increment this iterator.
+                void increment();
+                /// \brief An internal method to check equality.
+                bool equal(const ConstIterator& other) const;
+                /// \brief An internal method to dereference this iterator.
+                const value_type dereference() const;
+            private:
+                friend class boost::iterator_core_access;
+        };
+
+        typedef ConstIterator const_iterator;
+
+        /// \brief Return an iterator corresponding to the beginning of the
+        /// elements stored in CounterDictionary.
+        ///
+        /// This method is mostly exception free. But it may still throw a
+        /// standard exception if memory allocation fails inside the method.
+        const_iterator begin() const;
+
+        /// \brief Return an iterator corresponding to the end of the elements
+        /// stored in CounterDictionary.
+        ///
+        /// This method is mostly exception free. But it may still throw a
+        /// standard exception if memory allocation fails inside the method.
+        const_iterator end() const;
+
+};
+
+}   // namespace statistics
+}   // namespace isc
+
+#endif

+ 47 - 0
src/lib/statistics/tests/Makefile.am

@@ -0,0 +1,47 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES  = run_unittests.cc
+run_unittests_SOURCES += counter_unittest.cc
+run_unittests_SOURCES += counter_dict_unittest.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+
+run_unittests_LDADD  = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+
+# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
+# B10_CXXFLAGS)
+run_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_GXX
+run_unittests_CXXFLAGS += -Wno-unused-parameter
+endif
+if USE_CLANGPP
+# Same for clang++, but we need to turn off -Werror completely.
+run_unittests_CXXFLAGS += -Wno-error
+endif
+endif
+
+noinst_PROGRAMS = $(TESTS)

+ 198 - 0
src/lib/statistics/tests/counter_dict_unittest.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 <config.h>
+#include <gtest/gtest.h>
+
+#include <set>
+
+#include <boost/foreach.hpp>
+
+#include <statistics/counter_dict.h>
+
+enum CounterItems {
+    ITEM1 = 0,
+    ITEM2 = 1,
+    ITEM3 = 2,
+    NUMBER_OF_ITEMS = 3
+};
+
+using namespace isc::statistics;
+
+// This fixture is for testing CounterDictionary.
+class CounterDictionaryTest : public ::testing::Test {
+protected:
+    CounterDictionaryTest() {}
+    ~CounterDictionaryTest() {}
+};
+
+TEST_F(CounterDictionaryTest, createCounterDictionary) {
+    // Create counters
+    CounterDictionary counters(NUMBER_OF_ITEMS);
+    // Add an element for this test
+    counters.addElement("test");
+    // Check if the all counters are initialized with 0
+    EXPECT_EQ(counters["test"].get(ITEM1), 0);
+    EXPECT_EQ(counters["test"].get(ITEM2), 0);
+    EXPECT_EQ(counters["test"].get(ITEM3), 0);
+}
+
+TEST_F(CounterDictionaryTest, getElement) {
+    // Create counters
+    CounterDictionary counters(NUMBER_OF_ITEMS);
+    // Add an element for this test
+    counters.addElement("test");
+    // Another member function to get counters for the element
+    EXPECT_EQ(counters.getElement("test").get(ITEM1), 0);
+    EXPECT_EQ(counters.getElement("test").get(ITEM2), 0);
+    EXPECT_EQ(counters.getElement("test").get(ITEM3), 0);
+}
+
+TEST_F(CounterDictionaryTest, incrementCounterItem) {
+    // Create counters
+    CounterDictionary counters(NUMBER_OF_ITEMS);
+    // Add elements for this test
+    counters.addElement("test");
+    counters.addElement("sub.test");
+    // Increment counters
+    counters["test"].inc(ITEM1);
+    counters["test"].inc(ITEM2);
+    counters["test"].inc(ITEM2);
+    counters["test"].inc(ITEM3);
+    counters["test"].inc(ITEM3);
+    counters["test"].inc(ITEM3);
+    // Check if the counters have expected values
+    EXPECT_EQ(counters["test"].get(ITEM1), 1);
+    EXPECT_EQ(counters["test"].get(ITEM2), 2);
+    EXPECT_EQ(counters["test"].get(ITEM3), 3);
+    EXPECT_EQ(counters["sub.test"].get(ITEM1), 0);
+    EXPECT_EQ(counters["sub.test"].get(ITEM2), 0);
+    EXPECT_EQ(counters["sub.test"].get(ITEM3), 0);
+}
+
+TEST_F(CounterDictionaryTest, deleteElement) {
+    // Create counters
+    CounterDictionary counters(NUMBER_OF_ITEMS);
+    // Add an element for this test
+    counters.addElement("test");
+    // Ensure the element is accessible
+    EXPECT_EQ(counters["test"].get(ITEM1), 0);
+    EXPECT_EQ(counters["test"].get(ITEM2), 0);
+    EXPECT_EQ(counters["test"].get(ITEM3), 0);
+    // Delete the element
+    counters.deleteElement("test");
+    // Accessing to the deleted element will cause an isc::OutOfRange exception
+    EXPECT_THROW(counters["test"].get(ITEM1), isc::OutOfRange);
+    // Deleting an element which does not exist will cause an isc::OutOfRange
+    //  exception
+    EXPECT_THROW(counters.deleteElement("test"), isc::OutOfRange);
+}
+
+TEST_F(CounterDictionaryTest, invalidCounterSize) {
+    // Creating counter with 0 elements will cause assertion failure
+    EXPECT_DEATH(CounterDictionary counters(0), "Assertion.+failed");
+}
+
+TEST_F(CounterDictionaryTest, invalidCounterItem) {
+    // Create counters
+    CounterDictionary counters(NUMBER_OF_ITEMS);
+    // Add an element for this test
+    counters.addElement("test");
+    // Incrementing out-of-bound counter will cause assertion failure
+    EXPECT_DEATH(counters["test"].inc(NUMBER_OF_ITEMS), "Assertion.+failed");
+}
+
+TEST_F(CounterDictionaryTest, uniqueCheck) {
+    // Create counters
+    CounterDictionary counters(NUMBER_OF_ITEMS);
+    // Add an element for this test
+    counters.addElement("test");
+    // Adding an element which already exists will cause an isc::OutOfRange
+    //  exception 
+    EXPECT_THROW(counters.addElement("test"), isc::InvalidParameter);
+}
+
+TEST_F(CounterDictionaryTest, iteratorTest) {
+    // Create counters
+    CounterDictionary counters(NUMBER_OF_ITEMS);
+    // Add elements for this test
+    counters.addElement("test");
+    counters.addElement("sub.test");
+    // Increment counters
+    counters["test"].inc(ITEM1);
+    counters["sub.test"].inc(ITEM2);
+    counters["sub.test"].inc(ITEM2);
+
+    // boolean values to check all of the elements can be accessed through
+    // the iterator
+    bool element_test_visited = false;
+    bool element_sub_test_visited = false;
+    // Walk through the elements with iterator
+    // Check if the elements "test" and "sub.test" appears only once
+    //  and the counters have expected value
+    BOOST_FOREACH(CounterDictionary::ValueType i,
+                  static_cast<const CounterDictionary &>(counters))
+    {
+        if (i.first == "test" && element_test_visited == false) {
+            element_test_visited = true;
+            // Check if the counters have expected value
+            EXPECT_EQ(i.second.get(ITEM1), 1);
+            EXPECT_EQ(i.second.get(ITEM2), 0);
+        } else if (i.first == "sub.test" &&
+                   element_sub_test_visited == false) {
+            element_sub_test_visited = true;
+            // Check if the counters have expected value
+            EXPECT_EQ(i.second.get(ITEM1), 0);
+            EXPECT_EQ(i.second.get(ITEM2), 2);
+        } else {
+            // Test fails when reaches here: the element is not expected or
+            //  the element appeared twice
+            FAIL() << "Unexpected iterator value";
+        }
+    }
+    // Check if the "test" and "sub.test" could be accessed
+    EXPECT_TRUE(element_test_visited);
+    EXPECT_TRUE(element_sub_test_visited);
+}
+
+TEST_F(CounterDictionaryTest, iteratorCopyTest) {
+    // Create counters
+    CounterDictionary counters(NUMBER_OF_ITEMS);
+    // Add elements for this test
+    counters.addElement("test");
+    counters.addElement("sub.test");
+    // Increment counters
+    counters["test"].inc(ITEM1);
+    counters["sub.test"].inc(ITEM2);
+    counters["sub.test"].inc(ITEM2);
+
+    CounterDictionary::ConstIterator i1 = counters.begin();
+    CounterDictionary::ConstIterator i2(i1);
+    CounterDictionary::ConstIterator i3;
+    i3 = i1;
+
+    EXPECT_TRUE(i1 == i2);
+    EXPECT_TRUE(i1 == i3);
+    EXPECT_TRUE(i2 == i3);
+
+    ++i2;
+    EXPECT_TRUE(i1 != i2);
+    EXPECT_TRUE(i1 == i3);
+    EXPECT_TRUE(i2 != i3);
+
+    ++i3;
+    EXPECT_TRUE(i1 != i2);
+    EXPECT_TRUE(i1 != i3);
+    EXPECT_TRUE(i2 == i3);
+}

+ 73 - 0
src/lib/statistics/tests/counter_unittest.cc

@@ -0,0 +1,73 @@
+// 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 <config.h>
+#include <gtest/gtest.h>
+
+#include <statistics/counter.h>
+
+namespace {
+enum CounterItems {
+    ITEM1 = 0,
+    ITEM2 = 1,
+    ITEM3 = 2,
+    NUMBER_OF_ITEMS = 3
+};
+}
+
+using namespace isc::statistics;
+
+// This fixture is for testing Counter.
+class CounterTest : public ::testing::Test {
+protected:
+    CounterTest() {}
+    ~CounterTest() {}
+};
+
+TEST_F(CounterTest, createCounter) {
+    // Create counter
+    Counter counter(NUMBER_OF_ITEMS);
+    // Check if the all counters are initialized with 0
+    EXPECT_EQ(counter.get(ITEM1), 0);
+    EXPECT_EQ(counter.get(ITEM2), 0);
+    EXPECT_EQ(counter.get(ITEM3), 0);
+}
+
+TEST_F(CounterTest, incrementCounterItem) {
+    // Create counter
+    Counter counter(NUMBER_OF_ITEMS);
+    // Increment counters
+    counter.inc(ITEM1);
+    counter.inc(ITEM2);
+    counter.inc(ITEM2);
+    counter.inc(ITEM3);
+    counter.inc(ITEM3);
+    counter.inc(ITEM3);
+    // Check if the counters have expected values
+    EXPECT_EQ(counter.get(ITEM1), 1);
+    EXPECT_EQ(counter.get(ITEM2), 2);
+    EXPECT_EQ(counter.get(ITEM3), 3);
+}
+
+TEST_F(CounterTest, invalidCounterSize) {
+    // Creating counter with 0 elements will cause assertion failure
+    EXPECT_DEATH(Counter counter(0), "Assertion.+failed");
+}
+
+TEST_F(CounterTest, invalidCounterItem) {
+    // Create counter
+    Counter counter(NUMBER_OF_ITEMS);
+    // Incrementing out-of-bound counter will cause assertion failure
+    EXPECT_DEATH(counter.inc(NUMBER_OF_ITEMS), "Assertion.+failed");
+}

+ 25 - 0
src/lib/statistics/tests/run_unittests.cc

@@ -0,0 +1,25 @@
+// Copyright (C) 2009  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 <gtest/gtest.h>
+#include <util/unittests/run_all.h>
+#include <log/logger_manager.h>
+
+int
+main(int argc, char* argv[])
+{
+    ::testing::InitGoogleTest(&argc, argv);         // Initialize Google test
+    isc::log::LoggerManager::init("unittest");      // Set a root logger name
+    return (isc::util::unittests::run_all());
+}