From 1dbe3c59bea72ee8a19082b97a35a2211df6540b Mon Sep 17 00:00:00 2001
From: Philippe Hamelin <philippe.hamelin@gmail.com>
Date: Wed, 26 Jan 2011 10:53:03 -0500
Subject: [PATCH] Add real-time output string stream.

---
 logging/Appender.hpp       |    2 +-
 logging/CMakeLists.txt     |    2 +-
 logging/Category.cpp       |   57 ++++++++++++++++++++++++++++++++++++
 logging/Category.hpp       |    4 ++
 logging/CategoryStream.cpp |   42 ++++++++++++++++++++++++++
 logging/CategoryStream.hpp |   69 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 174 insertions(+), 2 deletions(-)
 create mode 100644 logging/CategoryStream.cpp
 create mode 100644 logging/CategoryStream.hpp

diff --git a/logging/Appender.hpp b/logging/Appender.hpp
index 02e19f4..828a08b 100644
--- a/logging/Appender.hpp
+++ b/logging/Appender.hpp
@@ -3,7 +3,7 @@
 
 #include <rtt/TaskContext.hpp>
 #include <rtt/Port.hpp>
-#include "logging/LoggingEvent.hpp"
+#include "LoggingEvent.hpp"
 
 // forward declare
 namespace log4cpp {
diff --git a/logging/CMakeLists.txt b/logging/CMakeLists.txt
index 465773f..a7958cb 100644
--- a/logging/CMakeLists.txt
+++ b/logging/CMakeLists.txt
@@ -8,7 +8,7 @@ IF ( BUILD_LOGGING AND LOG4CPP_FOUND )
 
   FILE( GLOB HPPS [^.]*.hpp )
 
-  set(LOGLIB_CPPS Category.cpp LoggingEvent.cpp)
+  set(LOGLIB_CPPS Category.cpp LoggingEvent.cpp CategoryStream.cpp)
   set(LOGCOMP_CPPS Appender.cpp FileAppender.cpp OstreamAppender.cpp LoggingService.cpp)
 
   INCLUDE_DIRECTORIES( "${LOG4CPP_INCLUDE_DIRS}" )
diff --git a/logging/Category.cpp b/logging/Category.cpp
index cdf27c8..6eae0c3 100644
--- a/logging/Category.cpp
+++ b/logging/Category.cpp
@@ -145,6 +145,63 @@ log4cpp::Category* Category::createOCLCategory(const std::string& name,
     return c;
 }
 
+CategoryStream Category::getRTStream(log4cpp::Priority::Value priority)
+{
+    return CategoryStream(this, isPriorityEnabled(priority) ? 
+                          priority : log4cpp::Priority::NOTSET);
+}
+/*
+CategoryStream Category::debugStream()
+{
+    return getRTStream(log4cpp::Priority::DEBUG);
+}
+
+CategoryStream Category::infoRTStream()
+{
+    return getRTStream(log4cpp::Priority::INFO);
+}
+
+CategoryStream Category::noticeRTStream()
+{
+    return getRTStream(log4cpp::Priority::NOTICE);
+}
+
+CategoryStream Category::warnRTStream()
+{
+    return getRTStream(log4cpp::Priority::WARN);
+}
+
+CategoryStream Category::errorRTStream()
+{
+    return getRTStream(log4cpp::Priority::ERROR);
+}
+
+CategoryStream Category::critRTStream()
+{
+    return getRTStream(log4cpp::Priority::CRIT);
+}
+
+CategoryStream Category::alertRTStream()
+{
+    return getRTStream(log4cpp::Priority::ALERT);
+}
+
+CategoryStream Category::emergRTStream()
+{
+    return getRTStream(log4cpp::Priority::EMERG);
+}
+
+CategoryStream Category::fatalRTStream()
+{
+    return getRTStream(log4cpp::Priority::FATAL);
+}
+*/
+/*
+CategoryStream Category::operator<<(log4cpp::Priority::Value priority)
+{
+    return getStream(priority);
+}
+*/
 // namespaces
 }
 }
diff --git a/logging/Category.hpp b/logging/Category.hpp
index b9fd154..1c85bc2 100644
--- a/logging/Category.hpp
+++ b/logging/Category.hpp
@@ -3,6 +3,7 @@
 
 #include <log4cpp/Category.hh>
 #include "LoggingEvent.hpp"
+#include "CategoryStream.hpp"
 #include <rtt/Port.hpp>
 
 namespace OCL {
@@ -35,6 +36,8 @@ public:
     void emerg(const RTT::rt_string& message) throw();
     void fatal(const RTT::rt_string& message) throw();
 
+    CategoryStream getRTStream(log4cpp::Priority::Value priority);
+
 protected:
     void _logUnconditionally2(log4cpp::Priority::Value priority, 
                               const RTT::rt_string& message) throw();
@@ -143,6 +146,7 @@ public:
                                                 log4cpp::Category* parent, 
                                                 log4cpp::Priority::Value priority);
 
+
 protected:
 //protected:
     RTT::OutputPort<OCL::logging::LoggingEvent>   log_port;
diff --git a/logging/CategoryStream.cpp b/logging/CategoryStream.cpp
new file mode 100644
index 0000000..dd32540
--- /dev/null
+++ b/logging/CategoryStream.cpp
@@ -0,0 +1,42 @@
+#include "CategoryStream.hpp"
+#include "Category.hpp"
+
+namespace OCL {
+namespace logging {
+
+CategoryStream::CategoryStream(Category* rt_category, log4cpp::Priority::Value priority) :
+    _priority(priority),
+    _category(rt_category)
+{
+
+}
+ 
+CategoryStream::~CategoryStream()
+{
+    flush();
+}   
+
+void CategoryStream::flush()
+{
+    _category->log(_priority, oss.str());
+    oss.flush();
+}
+
+CategoryStream& eol(CategoryStream& os)
+{
+    os.flush();
+
+    return os;
+}
+
+CategoryStream::CategoryStream(const CategoryStream & rhs) :
+    _category(rhs._category),
+    _priority(rhs._priority)
+{
+    // Must copy the underlying buffer but not the output stream
+    (*this).oss.str(rhs.oss.str());
+}
+
+} // namespace logging
+} // namespace OCL
+
diff --git a/logging/CategoryStream.hpp b/logging/CategoryStream.hpp
new file mode 100644
index 0000000..e009144
--- /dev/null
+++ b/logging/CategoryStream.hpp
@@ -0,0 +1,69 @@
+#ifndef CATEGORY_STREAM_HPP
+#define CATEGORY_STREAM_HPP 1
+
+#include <ocl/OCL.hpp>
+#include <log4cpp/Priority.hh>
+#include <rtt/rt_string.hpp>
+
+namespace OCL {
+namespace logging {
+
+class OCL_API Category;
+
+OCL_API class CategoryStream
+{
+public:
+
+    /**
+     * Construct a CategoryStream for given Category with given priority.
+     * @param category The category this stream will send log messages to.
+     * @param priority The priority the log messages will get or 
+     * Priority::NOTSET to silently discard any streamed in messages.
+     **/
+    CategoryStream(Category* rt_category, log4cpp::Priority::Value priority);
+
+    /**
+     * Copy-constructor needed because the output string stream can't be
+     * copied. We rater have to copy the underlying (real-time) string.
+     * @param rhs The CategoryStream to copy from
+     */ 
+    CategoryStream(const CategoryStream & rhs);
+
+    /**
+     * Destructor for CategoryStream
+     **/
+    virtual ~CategoryStream();
+
+    /**
+     * Flush the contents of the stream buffer to the Category and
+     * empties the buffer.
+     **/
+    void flush();
+
+    /**
+     * Stream in arbitrary types and objects.  
+     * @param t The value or object to stream in.
+     * @returns A reference to itself.
+     **/
+    template<typename T> CategoryStream& operator<<(const T& t) 
+    {
+         if (_priority != log4cpp::Priority::NOTSET) 
+         {
+             (oss) << t;
+         }
+         return *this;
+     }
+
+private:
+
+    Category* _category;
+    log4cpp::Priority::Value _priority;
+    RTT::rt_ostringstream oss;
+
+};
+
+
+} // namespace logging
+} // namespace OCL
+
+#endif // CATEGORY_STREAM_HPP
-- 
1.7.0.4

