util: Introduce NDN_LOG_NOFLUSH env variable to disable auto-flushing logs

Change-Id: Id1699d044e318aac315a545e913d0fc80306939b
Refs: #3668
diff --git a/docs/manpages/ndn-log.rst b/docs/manpages/ndn-log.rst
index b8fc3b2..40db707 100644
--- a/docs/manpages/ndn-log.rst
+++ b/docs/manpages/ndn-log.rst
@@ -18,6 +18,11 @@
 setting the environment variable. Wildcards can be used to enable logging for all
 modules (just ``*``) or all modules under a selected prefix (e.g., ``ndn.*``).
 
+If an additional environment variable ``NDN_LOG_NOFLUSH`` is set, the automatic flushing
+after each log record will be disabled. This can improve logging performance but may
+cause the log records to appear delayed or, in case of application crash, the last
+few log records may be lost.
+
 ndn-cxx logging facility provides a mechanism to manage the type of log messages
 that are written by classifying log messages by severity levels. Listed below
 are the available log levels.
diff --git a/ndn-cxx/util/logging.cpp b/ndn-cxx/util/logging.cpp
index ca6d584..4db9f28 100644
--- a/ndn-cxx/util/logging.cpp
+++ b/ndn-cxx/util/logging.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -90,11 +90,17 @@
 
 Logging::Logging()
 {
+  bool wantAutoFlush = true;
+  const char* environ = std::getenv("NDN_LOG_NOFLUSH");
+  if (environ != nullptr) {
+    wantAutoFlush = false;
+  }
+
   // cannot call the static setDestination that uses the singleton Logging object that is not yet constructed
-  auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&std::clog, [] (auto) {}));
+  auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&std::clog, [] (auto) {}), wantAutoFlush);
   this->setDestinationImpl(std::move(destination));
 
-  const char* environ = std::getenv("NDN_LOG");
+  environ = std::getenv("NDN_LOG");
   if (environ != nullptr) {
     this->setLevelImpl(environ);
   }
@@ -242,19 +248,19 @@
 #endif // NDN_CXX_HAVE_TESTS
 
 void
-Logging::setDestination(std::ostream& os)
+Logging::setDestination(std::ostream& os, bool wantAutoFlush)
 {
-  auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&os, [] (auto) {}));
+  auto destination = makeDefaultStreamDestination(shared_ptr<std::ostream>(&os, [] (auto) {}), wantAutoFlush);
   setDestination(std::move(destination));
 }
 
 class TextOstreamBackend : public boost::log::sinks::text_ostream_backend
 {
 public:
-  TextOstreamBackend(std::shared_ptr<std::ostream> os)
+  TextOstreamBackend(std::shared_ptr<std::ostream> os, bool wantAutoFlush)
     : m_stdPtr(std::move(os))
   {
-    auto_flush(true);
+    auto_flush(wantAutoFlush);
     add_stream(boost::shared_ptr<std::ostream>(m_stdPtr.get(), [] (auto) {}));
   }
 
@@ -265,9 +271,9 @@
 };
 
 boost::shared_ptr<boost::log::sinks::sink>
-Logging::makeDefaultStreamDestination(shared_ptr<std::ostream> os)
+Logging::makeDefaultStreamDestination(shared_ptr<std::ostream> os, bool wantAutoFlush)
 {
-  auto backend = boost::make_shared<TextOstreamBackend>(std::move(os));
+  auto backend = boost::make_shared<TextOstreamBackend>(std::move(os), wantAutoFlush);
   auto destination = boost::make_shared<boost::log::sinks::asynchronous_sink<TextOstreamBackend>>(backend);
 
   namespace expr = boost::log::expressions;
diff --git a/ndn-cxx/util/logging.hpp b/ndn-cxx/util/logging.hpp
index 8162358..ccb2196 100644
--- a/ndn-cxx/util/logging.hpp
+++ b/ndn-cxx/util/logging.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -97,12 +97,13 @@
   /** \brief Helper method to set stream log destination.
    *  \param os a stream for log output; caller must ensure it remains valid
    *            until setDestination() is invoked again or program exits
+   *  \param wantAutoFlush if true, the created logging sink will be auto-flushed
    *`
    *  This is equivalent to `setDestination(makeDefaultStreamDestination(shared_ptr<std::ostream>(&os, nullDeleter)))`.
    *
    */
   static void
-  setDestination(std::ostream& os);
+  setDestination(std::ostream& os, bool wantAutoFlush = true);
 
   /** \brief Flush log backend.
    *
@@ -114,7 +115,7 @@
   /** \brief Create stream log destination using default formatting
    */
   static boost::shared_ptr<boost::log::sinks::sink>
-  makeDefaultStreamDestination(shared_ptr<std::ostream> os);
+  makeDefaultStreamDestination(shared_ptr<std::ostream> os, bool wantAutoFlush = true);
 
 private:
   Logging();