util: fix Logging::getLoggerNames()

Change-Id: Ia243b7eeb7aae69427526e23e7eff4896506871a
diff --git a/src/util/logger.hpp b/src/util/logger.hpp
index 87e317b..75d86b4 100644
--- a/src/util/logger.hpp
+++ b/src/util/logger.hpp
@@ -61,13 +61,18 @@
 parseLogLevel(const std::string& s);
 
 /** \brief Represents a log module in the logging facility.
- *  \note New loggers should be defined using #NDN_LOG_INIT or #NDN_LOG_MEMBER_INIT.
+ *
+ *  \note Normally, loggers should be defined using #NDN_LOG_INIT, #NDN_LOG_MEMBER_INIT,
+ *        or #NDN_LOG_MEMBER_INIT_SPECIALIZED.
  */
 class Logger : public boost::log::sources::logger_mt
 {
 public:
   explicit
-  Logger(const std::string& name);
+  Logger(const char* name);
+
+  static void
+  registerModuleName(const char* name);
 
   const std::string&
   getModuleName() const
@@ -126,6 +131,14 @@
 } // namespace detail
 
 /** \cond */
+// implementation detail
+#define NDN_LOG_REGISTER_NAME(name) \
+  []() -> bool { \
+    ::ndn::util::Logger::registerModuleName(BOOST_STRINGIZE(name)); \
+    return true; \
+  }()
+
+// implementation detail
 #define NDN_LOG_INIT_FUNCTION_BODY(name) \
   { \
     static ::ndn::util::Logger logger(BOOST_STRINGIZE(name)); \
@@ -149,47 +162,61 @@
  */
 #define NDN_LOG_INIT(name) \
   namespace { \
+    const bool ndn_cxx_loggerRegistration __attribute__((used)) = NDN_LOG_REGISTER_NAME(name); \
     ::ndn::util::Logger& ndn_cxx_getLogger() \
     NDN_LOG_INIT_FUNCTION_BODY(name) \
   } \
   struct ndn_cxx_allow_trailing_semicolon
 
-/** \brief Define a member log module.
+/** \brief Declare a member log module, without initializing it.
  *
- *  This macro should only be used to define a log module as a class or struct member.
+ *  This macro should only be used to declare a log module as a class or struct member.
  *  It is recommended to place this macro in the private or protected section of the
- *  class or struct definition. Use #NDN_LOG_INIT to define a non-member log module.
+ *  class or struct definition. Use #NDN_LOG_INIT to declare a non-member log module.
  *
+ *  If the enclosing class is a template, this macro can be used in conjunction with
+ *  #NDN_LOG_MEMBER_DECL_SPECIALIZED and #NDN_LOG_MEMBER_INIT_SPECIALIZED to provide
+ *  different loggers for different template specializations.
+ */
+#define NDN_LOG_MEMBER_DECL() \
+  static ::ndn::util::Logger& ndn_cxx_getLogger(); \
+  private: \
+  static const bool ndn_cxx_loggerRegistration
+
+/** \brief Initialize a member log module.
+ *
+ *  This macro should only be used to initialize a previously declared member log module.
+ *  It must be placed in a .cpp file (NOT in a header file), in the same namespace as
+ *  the class or struct that contains the log module.
+ *
+ *  \param cls class name; wrap in parentheses if it contains commas
  *  \param name the logger name
  *  \note The logger name is restricted to alphanumeric characters and a select set of
  *        symbols: `~`, `#`, `%`, `_`, `<`, `>`, `.`, `-`. It must not start or end with
  *        a dot (`.`), or contain multiple consecutive dots.
  */
-#define NDN_LOG_MEMBER_INIT(name) \
-  static ::ndn::util::Logger& ndn_cxx_getLogger() \
+#define NDN_LOG_MEMBER_INIT(cls, name) \
+  const bool ::ndn::util::detail::ArgumentType<void(cls)>::ndn_cxx_loggerRegistration = \
+  NDN_LOG_REGISTER_NAME(name); \
+  ::ndn::util::Logger& ::ndn::util::detail::ArgumentType<void(cls)>::ndn_cxx_getLogger() \
   NDN_LOG_INIT_FUNCTION_BODY(name) \
   struct ndn_cxx_allow_trailing_semicolon
 
-/** \brief Forward-declare a member log module, without fully defining it.
- *
- *  This macro can be used to declare a log module as a member of a class template.
- *  Use this macro in conjunction with #NDN_LOG_MEMBER_DECL_SPECIALIZED and
- *  #NDN_LOG_MEMBER_INIT_SPECIALIZED to provide different loggers for different
- *  template specializations.
- */
-#define NDN_LOG_MEMBER_DECL() \
-  static ::ndn::util::Logger& ndn_cxx_getLogger()
-
 /** \brief Declare an explicit specialization of a member log module of a class template.
  *
  *  \param cls fully specialized class name; wrap in parentheses if it contains commas
  */
 #define NDN_LOG_MEMBER_DECL_SPECIALIZED(cls) \
   template<> \
+  const bool ::ndn::util::detail::ArgumentType<void(cls)>::ndn_cxx_loggerRegistration; \
+  template<> \
   ::ndn::util::Logger& ::ndn::util::detail::ArgumentType<void(cls)>::ndn_cxx_getLogger()
 
 /** \brief Define an explicit specialization of a member log module of a class template.
  *
+ *  This macro must be placed in a .cpp file (NOT in a header file), in the same namespace
+ *  as the class template that contains the log module.
+ *
  *  \param cls fully specialized class name; wrap in parentheses if it contains commas
  *  \param name the logger name
  *  \note The logger name is restricted to alphanumeric characters and a select set of
@@ -197,7 +224,10 @@
  *        a dot (`.`), or contain multiple consecutive dots.
  */
 #define NDN_LOG_MEMBER_INIT_SPECIALIZED(cls, name) \
-  template<> inline \
+  template<> \
+  const bool ::ndn::util::detail::ArgumentType<void(cls)>::ndn_cxx_loggerRegistration = \
+  NDN_LOG_REGISTER_NAME(name); \
+  template<> \
   ::ndn::util::Logger& ::ndn::util::detail::ArgumentType<void(cls)>::ndn_cxx_getLogger() \
   NDN_LOG_INIT_FUNCTION_BODY(name) \
   struct ndn_cxx_allow_trailing_semicolon
@@ -210,6 +240,7 @@
 #define NDN_BOOST_LOG(x) BOOST_LOG(x)
 #endif
 
+// implementation detail
 #define NDN_LOG_INTERNAL(lvl, lvlstr, expression) \
   do { \
     if (ndn_cxx_getLogger().isLevelEnabled(::ndn::util::LogLevel::lvl)) { \