From 73a016f0e5bd98c7965374d4731838c7f4b6dc75 Mon Sep 17 00:00:00 2001
From: Joseph Mirabel <jmirabel@laas.fr>
Date: Fri, 28 Sep 2018 17:02:04 +0200
Subject: [PATCH] Add macros to use real time logs.

---
 include/dynamic-graph/real-time-logger.h | 28 ++++++++++++---
 src/debug/real-time-logger.cpp           | 46 ++++++++++++++++++++++++
 tests/real-time-logger.cpp               | 32 ++++++-----------
 3 files changed, 79 insertions(+), 27 deletions(-)

diff --git a/include/dynamic-graph/real-time-logger.h b/include/dynamic-graph/real-time-logger.h
index 55dea17..b0a4283 100644
--- a/include/dynamic-graph/real-time-logger.h
+++ b/include/dynamic-graph/real-time-logger.h
@@ -23,6 +23,8 @@
 # include <boost/shared_ptr.hpp>
 
 # include <dynamic-graph/config.hh>
+# include <dynamic-graph/debug.h>
+
 
 namespace dynamicgraph
 {
@@ -50,7 +52,8 @@ namespace dynamicgraph
   {
     public:
       RTLoggerStream (RealTimeLogger* logger, std::ostream& os) : logger_(logger), os_ (os) {}
-      template <typename T> RTLoggerStream& operator<< (T  t) { os_ << t; return *this; }
+      template <typename T> inline RTLoggerStream& operator<< (T  t) { os_ << t; return *this; }
+      inline RTLoggerStream& operator<< (std::ostream& (*pf)(std::ostream&)) { os_ << pf; return *this; }
 
       ~RTLoggerStream();
     private:
@@ -65,6 +68,10 @@ namespace dynamicgraph
   class DYNAMIC_GRAPH_DLLAPI RealTimeLogger
   {
   public:
+    static RealTimeLogger& instance();
+
+    static void destroy();
+
     /// \todo add an argument to preallocate the internal string to a given size.
     RealTimeLogger (const std::size_t& bufferSize);
 
@@ -72,9 +79,6 @@ namespace dynamicgraph
 
     inline void addOutputStream (const LoggerStreamPtr_t& os) { outputs_.push_back(os); }
 
-    /// The function to be called by the thread who exports the outputs
-    //void spin ();
-
     /// Write next message to output.
     /// It does nothing if the buffer is empty.
     /// \return true if it wrote something
@@ -104,7 +108,7 @@ namespace dynamicgraph
         return backIdx_ + buffer_.size() - frontIdx_;
     }
 
-    inline std::size_t getBufferSize () { return buffer_.capacity(); }
+    inline std::size_t getBufferSize () { return buffer_.size(); }
 
     ~RealTimeLogger ();
 
@@ -121,7 +125,21 @@ namespace dynamicgraph
     /// Index of the slot where to write next value (does not contain valid data).
     std::size_t backIdx_;
     std::ostream oss_;
+
+    struct thread;
+
+    static RealTimeLogger* instance_;
+    static thread* thread_;
   };
 } // end of namespace dynamicgraph
 
+#ifdef ENABLE_RT_LOG
+# define dgADD_OSTREAM_TO_RTLOG(ostr) ::dynamicgraph::RealTimeLogger::instance() \
+  .addOutputStream(::dynamicgraph::LoggerStreamPtr_t(new ::dynamicgraph::LoggerIOStream(ostr)))
+# define dgRTLOG() ::dynamicgraph::RealTimeLogger::instance().front()
+#else // ENABLE_RT_LOG
+# define dgADD_OSTREAM_TO_RTLOG(ostr) struct __end_with_semicolon
+# define dgRTLOG() if (1) ; else __null_stream()
+#endif
+
 #endif //! DYNAMIC_GRAPH_LOGGER_REAL_TIME_H
diff --git a/src/debug/real-time-logger.cpp b/src/debug/real-time-logger.cpp
index 4386b58..d98f98c 100644
--- a/src/debug/real-time-logger.cpp
+++ b/src/debug/real-time-logger.cpp
@@ -19,6 +19,9 @@
 
 #include <dynamic-graph/real-time-logger.h>
 
+#include <boost/thread/thread.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
 namespace dynamicgraph
 {
   RealTimeLogger::RealTimeLogger (const std::size_t& bufferSize)
@@ -68,4 +71,47 @@ namespace dynamicgraph
     os_ << std::ends;
     if (logger_ != NULL) logger_->frontReady();
   }
+
+  struct RealTimeLogger::thread
+  {
+    bool requestShutdown_;
+    boost::thread t_;
+
+    thread (RealTimeLogger* logger)
+      : requestShutdown_ (false)
+      , t_ (&thread::spin, this, logger)
+    {}
+
+    void spin (RealTimeLogger* logger)
+    {
+      while (!requestShutdown_ || !logger->empty())
+      {
+        // If the logger did not write anything, it means the buffer is empty.
+        // Do a pause
+        if (!logger->spinOnce())
+          boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+      }
+    }
+  };
+
+  RealTimeLogger* RealTimeLogger::instance_ = NULL;
+  RealTimeLogger::thread* RealTimeLogger::thread_ = NULL;
+
+  RealTimeLogger& RealTimeLogger::instance()
+  {
+    if (instance_ == NULL) {
+      instance_ = new RealTimeLogger (1000);
+      thread_ = new thread (instance_);
+    }
+    return *instance_;
+  }
+
+  void RealTimeLogger::destroy ()
+  {
+    if (instance_ == NULL) return;
+    thread_->requestShutdown_ = true;
+    thread_->t_.join();
+    delete instance_;
+    delete thread_;
+  }
 }
diff --git a/tests/real-time-logger.cpp b/tests/real-time-logger.cpp
index 064ae10..055a365 100644
--- a/tests/real-time-logger.cpp
+++ b/tests/real-time-logger.cpp
@@ -18,6 +18,8 @@
  */
 
 #include <iostream>
+
+#define ENABLE_RT_LOG
 #include <dynamic-graph/real-time-logger.h>
 
 #define BOOST_TEST_MODULE real_time_logger
@@ -25,7 +27,6 @@
 #include <boost/test/unit_test.hpp>
 #include <boost/test/output_test_stream.hpp>
 
-#include <boost/thread.hpp>
 #include <boost/thread/thread.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 
@@ -51,33 +52,20 @@ BOOST_AUTO_TEST_CASE (monothread)
   rtl.spinOnce();
 }
 
-bool requestShutdown = false;
-void spin (RealTimeLogger* logger)
-{
-  while (!requestShutdown || !logger->empty())
-  {
-    // If the logger did not write anything, it means the buffer is empty.
-    // Do a pause
-    if (!logger->spinOnce())
-      boost::this_thread::sleep(boost::posix_time::milliseconds(100));
-  }
-}
-
 BOOST_AUTO_TEST_CASE (multithread)
 {
-  RealTimeLogger rtl (10);
-  rtl.addOutputStream (LoggerStreamPtr_t (new LoggerIOStream(std::cout)));
-
-  boost::thread loggerThread (spin, &rtl);
+  RealTimeLogger& rtl = RealTimeLogger::instance();
+  dgADD_OSTREAM_TO_RTLOG (std::cout);
 
-  for (int i = 0; i < 10; ++i) {
-    boost::this_thread::sleep(boost::posix_time::milliseconds(20));
+  for (std::size_t i = 0; i < rtl.getBufferSize()-1; ++i)
     rtl.front() << "Call number " << i << '\n';
+  for (std::size_t i = 0; i < 12; ++i) {
+    boost::this_thread::sleep(boost::posix_time::milliseconds(20));
+    rtl.front() << "Call number " << i << std::endl;
     BOOST_CHECK (!rtl.full());
   }
 
-  rtl.front() << "This call should appear in the output" << '\n';
+  dgRTLOG() << "This call should appear in the output" << '\n';
 
-  requestShutdown = true;
-  loggerThread.join();
+  RealTimeLogger::destroy();
 }
-- 
GitLab