27 #include "ndn-cxx/util/impl/logger-android.hpp" 
   30 #include <boost/log/attributes/function.hpp> 
   31 #include <boost/log/expressions.hpp> 
   32 #include <boost/log/expressions/attr.hpp> 
   33 #include <boost/log/expressions/formatters/date_time.hpp> 
   34 #include <boost/log/support/date_time.hpp> 
   35 #include <boost/range/adaptor/map.hpp> 
   36 #include <boost/range/algorithm/copy.hpp> 
   37 #include <boost/range/iterator_range.hpp> 
   47 #pragma clang diagnostic ignored "-Wundefined-func-template" 
   59   const auto sinceEpoch = system_clock::now().time_since_epoch();
 
   60   BOOST_ASSERT(sinceEpoch.count() >= 0);
 
   62   const auto usecs = 
std::abs(duration_cast<microseconds>(sinceEpoch).count());
 
   63   const auto usecsPerSec = microseconds::period::den;
 
   66   std::string buffer(10 + 1 + 6 + 1, 
'\0'); 
 
   67   BOOST_ASSERT_MSG(usecs / usecsPerSec <= 9999999999, 
"whole seconds cannot fit in 10 characters");
 
   69   static_assert(std::is_same<microseconds::rep, int_least64_t>::value,
 
   70                 "PRIdLEAST64 is incompatible with microseconds::rep");
 
   72   ::snprintf(&buffer.front(), buffer.size(), 
"%" PRIdLEAST64 
".%06" PRIdLEAST64,
 
   73              usecs / usecsPerSec, usecs % usecsPerSec);
 
   80 BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, 
"Timestamp", std::string)
 
   91   static Logging instance;
 
   98   bool wantAutoFlush = std::getenv(
"NDN_LOG_NOFLUSH") == 
nullptr;
 
   99   auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&std::clog, [] (
auto&&) {}),
 
  102   auto destination = detail::makeAndroidLogger();
 
  106   this->setDestinationImpl(std::move(destination));
 
  108   const char* env = std::getenv(
"NDN_LOG");
 
  109   if (env != 
nullptr) {
 
  110     this->setLevelImpl(env);
 
  113   boost::log::core::get()->add_global_attribute(
"Timestamp",
 
  114                                                 boost::log::attributes::make_function(&log::makeTimestamp));
 
  118 Logging::addLoggerImpl(Logger& logger)
 
  120   std::lock_guard<std::mutex> lock(m_mutex);
 
  122   const std::string& moduleName = logger.getModuleName();
 
  123   m_loggers.emplace(moduleName, &logger);
 
  125   logger.setLevel(findLevel(moduleName));
 
  129 Logging::registerLoggerNameImpl(std::string name)
 
  131   std::lock_guard<std::mutex> lock(m_mutex);
 
  132   m_loggers.emplace(std::move(name), 
nullptr);
 
  135 std::set<std::string>
 
  136 Logging::getLoggerNamesImpl()
 const 
  138   std::lock_guard<std::mutex> lock(m_mutex);
 
  140   std::set<std::string> loggerNames;
 
  141   boost::copy(m_loggers | boost::adaptors::map_keys, std::inserter(loggerNames, loggerNames.end()));
 
  146 Logging::findLevel(std::string mn)
 const 
  148   while (!mn.empty()) {
 
  149     auto it = m_enabledLevel.find(mn);
 
  150     if (it != m_enabledLevel.end()) {
 
  153     size_t pos = mn.find_last_of(
'.');
 
  154     if (pos < mn.size() - 1) {
 
  155       mn = mn.substr(0, pos + 1);
 
  157     else if (pos == mn.size() - 1) {
 
  159       pos = mn.find_last_of(
'.');
 
  160       if (pos != std::string::npos) {
 
  161         mn = mn.substr(0, pos + 1);
 
  172   auto it = m_enabledLevel.find(mn);
 
  173   return it != m_enabledLevel.end() ? it->second : INITIAL_DEFAULT_LEVEL;
 
  176 #ifdef NDN_CXX_HAVE_TESTS 
  178 Logging::removeLogger(Logger& logger)
 
  180   const std::string& moduleName = logger.getModuleName();
 
  181   auto range = m_loggers.equal_range(moduleName);
 
  182   for (
auto i = range.first; i != range.second; ++i) {
 
  183     if (i->second == &logger) {
 
  193 Logging::setLevelImpl(
const std::string& prefix, 
LogLevel level)
 
  195   std::lock_guard<std::mutex> lock(m_mutex);
 
  197   if (prefix.empty() || prefix.back() == 
'*') {
 
  198     std::string p = prefix;
 
  203     for (
auto i = m_enabledLevel.begin(); i != m_enabledLevel.end();) {
 
  204       if (i->first.compare(0, p.size(), p) == 0) {
 
  205         i = m_enabledLevel.erase(i);
 
  211     m_enabledLevel[p] = level;
 
  213     for (
const auto& pair : m_loggers) {
 
  214       if (pair.first.compare(0, p.size(), p) == 0 && pair.second != 
nullptr) {
 
  215         pair.second->setLevel(level);
 
  220     m_enabledLevel[prefix] = level;
 
  221     auto range = boost::make_iterator_range(m_loggers.equal_range(prefix));
 
  222     for (
const auto& pair : range) {
 
  223       if (pair.second != 
nullptr) {
 
  224         pair.second->setLevel(level);
 
  231 Logging::setLevelImpl(
const std::string& config)
 
  233   std::stringstream ss(config);
 
  234   std::string configModule;
 
  235   while (std::getline(ss, configModule, 
':')) {
 
  236     size_t ind = configModule.find(
'=');
 
  237     if (ind == std::string::npos) {
 
  238       NDN_THROW(std::invalid_argument(
"malformed logging config: '=' is missing"));
 
  241     std::string moduleName = configModule.substr(0, ind);
 
  243     this->setLevelImpl(moduleName, level);
 
  247 #ifdef NDN_CXX_HAVE_TESTS 
  249 Logging::resetLevels()
 
  251   this->setLevelImpl(
"*", INITIAL_DEFAULT_LEVEL);
 
  252   m_enabledLevel.clear();
 
  259   auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&os, [] (
auto&&) {}),
 
  261   setDestination(std::move(destination));
 
  264 class TextOstreamBackend : 
public boost::log::sinks::text_ostream_backend
 
  267   TextOstreamBackend(std::shared_ptr<std::ostream> os, 
bool wantAutoFlush)
 
  268     : m_stdPtr(std::move(os))
 
  270     auto_flush(wantAutoFlush);
 
  271     add_stream(boost::shared_ptr<std::ostream>(m_stdPtr.get(), [] (
auto&&) {}));
 
  277   std::shared_ptr<std::ostream> m_stdPtr;
 
  280 boost::shared_ptr<boost::log::sinks::sink>
 
  283   auto backend = boost::make_shared<TextOstreamBackend>(std::move(os), wantAutoFlush);
 
  284   auto destination = boost::make_shared<boost::log::sinks::asynchronous_sink<TextOstreamBackend>>(backend);
 
  286   namespace expr = boost::log::expressions;
 
  287   destination->set_formatter(expr::stream
 
  288                              << expr::attr<std::string>(log::timestamp.get_name())
 
  289                              << 
" " << std::setw(5) << expr::attr<LogLevel>(log::severity.get_name()) << 
": " 
  290                              << 
"[" << expr::attr<std::string>(log::module.get_name()) << 
"] " 
  296 Logging::setDestinationImpl(boost::shared_ptr<boost::log::sinks::sink> destination)
 
  298   std::lock_guard<std::mutex> lock(m_mutex);
 
  300   if (destination == m_destination) {
 
  304   if (m_destination != 
nullptr) {
 
  305     boost::log::core::get()->remove_sink(m_destination);
 
  306     m_destination->flush();
 
  309   m_destination = std::move(destination);
 
  311   if (m_destination != 
nullptr) {
 
  312     boost::log::core::get()->add_sink(m_destination);
 
  316 #ifdef NDN_CXX_HAVE_TESTS 
  317 boost::shared_ptr<boost::log::sinks::sink>
 
  318 Logging::getDestination()
 const 
  320   return m_destination;
 
  324 Logging::setLevelImpl(
const std::unordered_map<std::string, LogLevel>& prefixRules)
 
  327   for (
const auto& rule : prefixRules) {
 
  328     setLevelImpl(rule.first, rule.second);
 
  332 const std::unordered_map<std::string, LogLevel>&
 
  333 Logging::getLevels()
 const 
  335   return m_enabledLevel;
 
  342   std::lock_guard<std::mutex> lock(m_mutex);
 
  344   if (m_destination != 
nullptr) {
 
  345     m_destination->flush();
 
static void setDestination(boost::shared_ptr< boost::log::sinks::sink > destination)
Set or replace log destination.
 
static boost::shared_ptr< boost::log::sinks::sink > makeDefaultStreamDestination(shared_ptr< std::ostream > os, bool wantAutoFlush=true)
Create stream log destination using default formatting.
 
constexpr duration< Rep, Period > abs(duration< Rep, Period > d)
 
LogLevel parseLogLevel(const std::string &s)
Parse LogLevel from a string.
 
LogLevel
Indicates the severity level of a log message.