util: Make use of attributes in logging facilities
Refs: #4969
Change-Id: Ib7e495629107d9ebe2105a7fe1f99d89ad92e244
diff --git a/ndn-cxx/util/logger.cpp b/ndn-cxx/util/logger.cpp
index 5f6c2de..15203ec 100644
--- a/ndn-cxx/util/logger.cpp
+++ b/ndn-cxx/util/logger.cpp
@@ -21,12 +21,8 @@
#include "ndn-cxx/util/logger.hpp"
#include "ndn-cxx/util/logging.hpp"
-#include "ndn-cxx/util/time.hpp"
-#include <cinttypes> // for PRIdLEAST64
-#include <cstdlib> // for std::abs()
-#include <cstring> // for std::strspn()
-#include <stdio.h> // for snprintf()
+#include <cstring> // for std::strspn()
namespace ndn {
namespace util {
@@ -107,6 +103,7 @@
NDN_THROW(std::invalid_argument("Logger name '" + m_moduleName + "' is invalid"));
}
this->setLevel(LogLevel::NONE);
+ this->add_attribute(log::module.get_name(), boost::log::attributes::constant<std::string>(m_moduleName));
Logging::get().addLoggerImpl(*this);
}
@@ -120,32 +117,5 @@
Logging::get().registerLoggerNameImpl(std::move(moduleName));
}
-namespace detail {
-
-std::ostream&
-operator<<(std::ostream& os, LoggerTimestamp)
-{
- using namespace ndn::time;
-
- const auto sinceEpoch = system_clock::now().time_since_epoch();
- BOOST_ASSERT(sinceEpoch.count() >= 0);
- // use abs() to silence truncation warning in snprintf(), see #4365
- const auto usecs = std::abs(duration_cast<microseconds>(sinceEpoch).count());
- const auto usecsPerSec = microseconds::period::den;
-
- // 10 (whole seconds) + '.' + 6 (fraction) + '\0'
- char buffer[10 + 1 + 6 + 1];
- BOOST_ASSERT_MSG(usecs / usecsPerSec <= 9999999999, "whole seconds cannot fit in 10 characters");
-
- static_assert(std::is_same<microseconds::rep, int_least64_t>::value,
- "PRIdLEAST64 is incompatible with microseconds::rep");
- // std::snprintf unavailable on some platforms, see #2299
- ::snprintf(buffer, sizeof(buffer), "%" PRIdLEAST64 ".%06" PRIdLEAST64,
- usecs / usecsPerSec, usecs % usecsPerSec);
-
- return os << buffer;
-}
-
-} // namespace detail
} // namespace util
} // namespace ndn
diff --git a/ndn-cxx/util/logger.hpp b/ndn-cxx/util/logger.hpp
index f785c7b..30b8779 100644
--- a/ndn-cxx/util/logger.hpp
+++ b/ndn-cxx/util/logger.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -29,7 +29,9 @@
#else
#include <boost/log/common.hpp>
-#include <boost/log/sources/logger.hpp>
+#include <boost/log/expressions/keyword.hpp>
+#include <boost/log/sources/severity_logger.hpp>
+
#include <atomic>
namespace ndn {
@@ -60,12 +62,19 @@
LogLevel
parseLogLevel(const std::string& s);
+namespace log {
+
+BOOST_LOG_ATTRIBUTE_KEYWORD(module, "Module", std::string)
+BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", LogLevel)
+
+} // namespace log
+
/** \brief Represents a log module in the logging facility.
*
* \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
+class Logger : public boost::log::sources::severity_logger_mt<LogLevel>
{
public:
explicit
@@ -99,21 +108,6 @@
namespace detail {
-/** \brief A tag type used to output a timestamp to a stream.
- * \code
- * std::clog << LoggerTimestamp();
- * \endcode
- */
-struct LoggerTimestamp
-{
-};
-
-/** \brief Write a timestamp to \p os.
- * \note This function is thread-safe.
- */
-std::ostream&
-operator<<(std::ostream& os, LoggerTimestamp);
-
/** \cond */
template<class T>
struct ExtractArgument;
@@ -235,51 +229,51 @@
/** \cond */
#if BOOST_VERSION == 105900
// workaround Boost bug 11549
-#define NDN_BOOST_LOG(x) BOOST_LOG(x) << ""
+#define NDN_BOOST_LOG(x, sev) BOOST_LOG_SEV(x, sev) << ""
#else
-#define NDN_BOOST_LOG(x) BOOST_LOG(x)
+#define NDN_BOOST_LOG(x, sev) BOOST_LOG_SEV(x, sev)
#endif
// implementation detail
-#define NDN_LOG_INTERNAL(lvl, lvlstr, expression) \
+#define NDN_LOG_INTERNAL(lvl, expression) \
do { \
if (ndn_cxx_getLogger().isLevelEnabled(::ndn::util::LogLevel::lvl)) { \
- NDN_BOOST_LOG(ndn_cxx_getLogger()) << ::ndn::util::detail::LoggerTimestamp{} \
- << " " BOOST_STRINGIZE(lvlstr) ": [" << ndn_cxx_getLogger().getModuleName() << "] " \
+ NDN_BOOST_LOG(ndn_cxx_getLogger(), ::ndn::util::LogLevel::lvl) \
<< expression; \
} \
} while (false)
+
/** \endcond */
/** \brief Log at TRACE level.
* \pre A log module must be declared in the same translation unit, class, struct, or namespace.
*/
-#define NDN_LOG_TRACE(expression) NDN_LOG_INTERNAL(TRACE, TRACE, expression)
+#define NDN_LOG_TRACE(expression) NDN_LOG_INTERNAL(TRACE, expression)
/** \brief Log at DEBUG level.
* \pre A log module must be declared in the same translation unit, class, struct, or namespace.
*/
-#define NDN_LOG_DEBUG(expression) NDN_LOG_INTERNAL(DEBUG, DEBUG, expression)
+#define NDN_LOG_DEBUG(expression) NDN_LOG_INTERNAL(DEBUG, expression)
/** \brief Log at INFO level.
* \pre A log module must be declared in the same translation unit, class, struct, or namespace.
*/
-#define NDN_LOG_INFO(expression) NDN_LOG_INTERNAL(INFO, INFO, expression)
+#define NDN_LOG_INFO(expression) NDN_LOG_INTERNAL(INFO, expression)
/** \brief Log at WARN level.
* \pre A log module must be declared in the same translation unit, class, struct, or namespace.
*/
-#define NDN_LOG_WARN(expression) NDN_LOG_INTERNAL(WARN, WARNING, expression)
+#define NDN_LOG_WARN(expression) NDN_LOG_INTERNAL(WARN, expression)
/** \brief Log at ERROR level.
* \pre A log module must be declared in the same translation unit, class, struct, or namespace.
*/
-#define NDN_LOG_ERROR(expression) NDN_LOG_INTERNAL(ERROR, ERROR, expression)
+#define NDN_LOG_ERROR(expression) NDN_LOG_INTERNAL(ERROR, expression)
/** \brief Log at FATAL level.
* \pre A log module must be declared in the same translation unit, class, struct, or namespace.
*/
-#define NDN_LOG_FATAL(expression) NDN_LOG_INTERNAL(FATAL, FATAL, expression)
+#define NDN_LOG_FATAL(expression) NDN_LOG_INTERNAL(FATAL, expression)
} // namespace util
} // namespace ndn
diff --git a/ndn-cxx/util/logging.cpp b/ndn-cxx/util/logging.cpp
index 5f19548..45f4ba7 100644
--- a/ndn-cxx/util/logging.cpp
+++ b/ndn-cxx/util/logging.cpp
@@ -21,15 +21,22 @@
#include "ndn-cxx/util/logging.hpp"
#include "ndn-cxx/util/logger.hpp"
+#include "ndn-cxx/util/time.hpp"
+#include <boost/log/attributes/function.hpp>
#include <boost/log/expressions.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatters/date_time.hpp>
+#include <boost/log/support/date_time.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/iterator_range.hpp>
-#include <cstdlib>
+#include <cinttypes> // for PRIdLEAST64
+#include <cstdlib> // for std::abs()
#include <iostream>
#include <sstream>
+#include <stdio.h> // for snprintf()
// suppress warning caused by <boost/log/sinks/text_ostream_backend.hpp>
#ifdef __clang__
@@ -38,6 +45,37 @@
namespace ndn {
namespace util {
+namespace log {
+
+static std::string
+makeTimestamp()
+{
+ using namespace ndn::time;
+
+ const auto sinceEpoch = system_clock::now().time_since_epoch();
+ BOOST_ASSERT(sinceEpoch.count() >= 0);
+ // use abs() to silence truncation warning in snprintf(), see #4365
+ const auto usecs = std::abs(duration_cast<microseconds>(sinceEpoch).count());
+ const auto usecsPerSec = microseconds::period::den;
+
+ // 10 (whole seconds) + '.' + 6 (fraction) + '\0'
+ std::string buffer(10 + 1 + 6 + 1, '\0'); // note 1 extra byte still needed for snprintf
+ BOOST_ASSERT_MSG(usecs / usecsPerSec <= 9999999999, "whole seconds cannot fit in 10 characters");
+
+ static_assert(std::is_same<microseconds::rep, int_least64_t>::value,
+ "PRIdLEAST64 is incompatible with microseconds::rep");
+ // std::snprintf unavailable on some platforms, see #2299
+ ::snprintf(&buffer.front(), buffer.size(), "%" PRIdLEAST64 ".%06" PRIdLEAST64,
+ usecs / usecsPerSec, usecs % usecsPerSec);
+
+ // need to remove extra 1 byte ('\0')
+ buffer.pop_back();
+ return buffer;
+}
+
+BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "Timestamp", std::string)
+
+} // namespace log
static const LogLevel INITIAL_DEFAULT_LEVEL = LogLevel::NONE;
@@ -58,6 +96,8 @@
if (environ != nullptr) {
this->setLevelImpl(environ);
}
+
+ boost::log::core::get()->add_global_attribute("Timestamp", boost::log::attributes::make_function(&log::makeTimestamp));
}
void
@@ -222,8 +262,13 @@
m_sink.reset();
}
+ namespace expr = boost::log::expressions;
m_sink = boost::make_shared<Sink>(backend);
- m_sink->set_formatter(boost::log::expressions::stream << boost::log::expressions::message);
+ m_sink->set_formatter(expr::stream
+ << expr::attr<std::string>(log::timestamp.get_name())
+ << " " << std::setw(5) << expr::attr<LogLevel>(log::severity.get_name()) << ": "
+ << "[" << expr::attr<std::string>(log::module.get_name()) << "] "
+ << expr::smessage);
boost::log::core::get()->add_sink(m_sink);
}
diff --git a/tests/unit/util/logging.t.cpp b/tests/unit/util/logging.t.cpp
index fd867d2..5be163a 100644
--- a/tests/unit/util/logging.t.cpp
+++ b/tests/unit/util/logging.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -205,7 +205,7 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n"
));
@@ -218,8 +218,8 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " INFO: [Module1] info1\n" +
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " INFO: [Module1] info1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n"
));
@@ -233,8 +233,8 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
LOG_SYSTIME_STR + " DEBUG: [Module1] debug1\n" +
- LOG_SYSTIME_STR + " INFO: [Module1] info1\n" +
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " INFO: [Module1] info1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n"
));
@@ -249,8 +249,8 @@
BOOST_CHECK(os.is_equal(
LOG_SYSTIME_STR + " TRACE: [Module1] trace1\n" +
LOG_SYSTIME_STR + " DEBUG: [Module1] debug1\n" +
- LOG_SYSTIME_STR + " INFO: [Module1] info1\n" +
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " INFO: [Module1] info1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n"
));
@@ -265,8 +265,8 @@
BOOST_CHECK(os.is_equal(
LOG_SYSTIME_STR + " TRACE: [Module1] trace1\n" +
LOG_SYSTIME_STR + " DEBUG: [Module1] debug1\n" +
- LOG_SYSTIME_STR + " INFO: [Module1] info1\n" +
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " INFO: [Module1] info1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n"
));
@@ -293,8 +293,8 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ns1] hello world from ns1\n" +
- LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ns2] hi there from ns2\n"
+ LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ns1] hello world from ns1\n" +
+ LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ns2] hi there from ns2\n"
));
}
@@ -314,8 +314,8 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ClassWithLogger] static member function\n" +
- LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ClassWithLogger] const member function\n"
+ LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ClassWithLogger] static member function\n" +
+ LOG_SYSTIME_STR + " INFO: [ndn.util.tests.ClassWithLogger] const member function\n"
));
ClassTemplateWithLogger<int, double>::logFromStaticMemberFunction();
@@ -325,8 +325,8 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " INFO: [ndn.util.tests.Specialized1] class template static member function\n" +
- LOG_SYSTIME_STR + " INFO: [ndn.util.tests.Specialized1] class template non-static member function\n"
+ LOG_SYSTIME_STR + " INFO: [ndn.util.tests.Specialized1] class template static member function\n" +
+ LOG_SYSTIME_STR + " INFO: [ndn.util.tests.Specialized1] class template non-static member function\n"
));
}
@@ -340,10 +340,10 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" +
- LOG_SYSTIME_STR + " WARNING: [Module1] warnModule1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warnModule1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] errorModule1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatalModule1\n"
));
@@ -357,8 +357,8 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
LOG_SYSTIME_STR + " DEBUG: [Module3] debugModule3\n" +
- LOG_SYSTIME_STR + " INFO: [Module3] infoModule3\n" +
- LOG_SYSTIME_STR + " WARNING: [Module3] warnModule3\n" +
+ LOG_SYSTIME_STR + " INFO: [Module3] infoModule3\n" +
+ LOG_SYSTIME_STR + " WARN: [Module3] warnModule3\n" +
LOG_SYSTIME_STR + " ERROR: [Module3] errorModule3\n" +
LOG_SYSTIME_STR + " FATAL: [Module3] fatalModule3\n"
));
@@ -386,10 +386,10 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" +
- LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" +
+ LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" +
LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" +
LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n"
));
@@ -404,12 +404,12 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" +
LOG_SYSTIME_STR + " DEBUG: [Module2] debug2\n" +
- LOG_SYSTIME_STR + " INFO: [Module2] info2\n" +
- LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" +
+ LOG_SYSTIME_STR + " INFO: [Module2] info2\n" +
+ LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" +
LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" +
LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n"
));
@@ -446,10 +446,10 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" +
- LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" +
+ LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" +
LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" +
LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n"
));
@@ -485,12 +485,12 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" +
LOG_SYSTIME_STR + " DEBUG: [Module2] debug2\n" +
- LOG_SYSTIME_STR + " INFO: [Module2] info2\n" +
- LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" +
+ LOG_SYSTIME_STR + " INFO: [Module2] info2\n" +
+ LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" +
LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" +
LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n"
));
@@ -510,12 +510,12 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " WARNING: [Module1] warn1\n" +
+ LOG_SYSTIME_STR + " WARN: [Module1] warn1\n" +
LOG_SYSTIME_STR + " ERROR: [Module1] error1\n" +
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" +
LOG_SYSTIME_STR + " DEBUG: [Module2] debug2\n" +
- LOG_SYSTIME_STR + " INFO: [Module2] info2\n" +
- LOG_SYSTIME_STR + " WARNING: [Module2] warn2\n" +
+ LOG_SYSTIME_STR + " INFO: [Module2] info2\n" +
+ LOG_SYSTIME_STR + " WARN: [Module2] warn2\n" +
LOG_SYSTIME_STR + " ERROR: [Module2] error2\n" +
LOG_SYSTIME_STR + " FATAL: [Module2] fatal2\n"
));
@@ -563,8 +563,8 @@
BOOST_CHECK(os.is_equal(
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" +
LOG_SYSTIME_STR + " DEBUG: [fm.FilterModule] debugFM\n" +
- LOG_SYSTIME_STR + " INFO: [fm.FilterModule] infoFM\n" +
- LOG_SYSTIME_STR + " WARNING: [fm.FilterModule] warnFM\n" +
+ LOG_SYSTIME_STR + " INFO: [fm.FilterModule] infoFM\n" +
+ LOG_SYSTIME_STR + " WARN: [fm.FilterModule] warnFM\n" +
LOG_SYSTIME_STR + " ERROR: [fm.FilterModule] errorFM\n" +
LOG_SYSTIME_STR + " FATAL: [fm.FilterModule] fatalFM\n"
));
@@ -586,8 +586,8 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
LOG_SYSTIME_STR + " FATAL: [Module1] fatal1\n" +
- LOG_SYSTIME_STR + " INFO: [fm.FilterModule] infoFM\n" +
- LOG_SYSTIME_STR + " WARNING: [fm.FilterModule] warnFM\n" +
+ LOG_SYSTIME_STR + " INFO: [fm.FilterModule] infoFM\n" +
+ LOG_SYSTIME_STR + " WARN: [fm.FilterModule] warnFM\n" +
LOG_SYSTIME_STR + " ERROR: [fm.FilterModule] errorFM\n" +
LOG_SYSTIME_STR + " FATAL: [fm.FilterModule] fatalFM\n"
));
@@ -603,8 +603,8 @@
Logging::flush();
BOOST_CHECK(os.is_equal(
- LOG_SYSTIME_STR + " INFO: [fm.a.b] infofm.a.b\n" +
- LOG_SYSTIME_STR + " WARNING: [fm.a.b] warnfm.a.b\n" +
+ LOG_SYSTIME_STR + " INFO: [fm.a.b] infofm.a.b\n" +
+ LOG_SYSTIME_STR + " WARN: [fm.a.b] warnfm.a.b\n" +
LOG_SYSTIME_STR + " ERROR: [fm.a.b] errorfm.a.b\n" +
LOG_SYSTIME_STR + " FATAL: [fm.a.b] fatalfm.a.b\n" +
LOG_SYSTIME_STR + " ERROR: [fm.a.b.c] errorfm.a.b.c\n" +