Utils/Logger: Complete unit testing
[senf.git] / Utils / Logger / Target.hh
index 6298800..b4137d6 100644 (file)
 #define HH_Target_ 1
 
 // Custom includes
+#include <set>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/utility.hpp>
+#include <boost/type_traits/is_convertible.hpp>
 #include "../singleton.hh"
+#include "../mpl.hh"
 #include "StreamRegistry.hh"
 #include "AreaRegistry.hh"
 
@@ -37,6 +42,8 @@
 namespace senf {
 namespace log {
 
+    class TargetRegistry;
+
     /** \brief Logging target base class
 
         All enabled log messages are eventually routed to one or more logging targets. It is the
@@ -44,74 +51,180 @@ namespace log {
         to a file, to mail them to the administrator or whatever. To this end, the logging target is
         passed the log message and a complete set of logging parameters (\e stream, \e area and \e
         level).
+
+        \fixme optionally Integrate with Scheduler / ClockService to reduce number of gettimeofday()
+            calls.
       */
-    class Target
-        : public senf::singleton<Target>
+    class Target : private boost::noncopyable
     {
     public:
         ///////////////////////////////////////////////////////////////////////////
         // Types
 
+        enum action_t { ACCEPT, REJECT };
+
+        struct RoutingEntry 
+        {
+            RoutingEntry();
+            bool operator==(RoutingEntry const & other);
+
+            std::string stream() const;
+            std::string area() const;
+            unsigned level() const;
+            action_t action() const;
+            
+        private:
+            RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area, 
+                         unsigned level, action_t action);
+
+            detail::StreamBase const * stream_;
+            detail::AreaBase const * area_;
+            unsigned level_;
+            action_t action_;
+            
+            friend class Target;
+        };
+
+    private:
+        typedef std::vector<RoutingEntry> RIB;
+
+    public:
+        typedef RIB::const_iterator iterator;
+
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
         ///@{
 
+        Target();
         virtual ~Target();
 
-        // default default constructor
-        // default copy constructor
-        // default copy assignment
-        // default destructor
-
-        // no conversion constructors
-
         ///@}
 
-    protected:
+        template <class Stream> void route(
+            action_t action = ACCEPT, int index = -1);
+        template <class Stream, class Level> void route(
+            action_t action = ACCEPT, int index = -1,
+            typename boost::enable_if< boost::is_convertible<Level*,
+                                                             detail::LevelBase *> >::type * = 0);
+        template <class Stream, class Area> void route(
+            action_t action = ACCEPT, int index = -1,
+            typename boost::enable_if< boost::is_convertible<Area*,
+                                                             detail::AreaBase *> >::type * = 0);
+        template <class Stream, class AreaClass> void route(
+            action_t action = ACCEPT, int index = -1,
+            typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
+                                                             detail::AreaBase *> >::type * = 0);
+        template <class Stream, class Area, class Level> void route(
+            action_t action = ACCEPT, int index = -1,
+            typename boost::enable_if< boost::is_convertible<Area *,
+                                                             detail::AreaBase *> >::type * = 0);
+        template <class Stream, class AreaClass, class Level> void route(
+            action_t action = ACCEPT, int index = -1,
+            typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
+                                                             detail::AreaBase *> >::type * = 0);
+
+        void route(std::string const & stream, std::string const & area = "", 
+                   unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
+
+        template <class Stream> void unroute(
+            action_t action = ACCEPT);
+        template <class Stream, class Level> void unroute(
+            action_t action = ACCEPT,
+            typename boost::enable_if< boost::is_convertible<Level*,
+                                                             detail::LevelBase *> >::type * = 0);
+        template <class Stream, class Area> void unroute(
+            action_t action = ACCEPT,
+            typename boost::enable_if< boost::is_convertible<Area*,
+                                                             detail::AreaBase *> >::type * = 0);
+        template <class Stream, class AreaClass> void unroute(
+            action_t action = ACCEPT,
+            typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
+                                                             detail::AreaBase *> >::type * = 0);
+        template <class Stream, class Area, class Level> void unroute(
+            action_t action = ACCEPT,
+            typename boost::enable_if< boost::is_convertible<Area*,
+                                                             detail::AreaBase *> >::type * = 0);
+        template <class Stream, class AreaClass, class Level> void unroute(
+            action_t action = ACCEPT,
+            typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
+                                                             detail::AreaBase *> >::type * = 0);
+
+        void unroute(std::string const & stream, std::string const & area = "", 
+                     unsigned level = NONE::value, action_t action = ACCEPT);
+        void unroute(int index);
+
+        struct InvalidStreamException : public std::exception
+        { virtual char const * what() const throw() 
+                { return "senf::log::Target::InvalidStreamException"; } };
+        
+        struct InvalidAreaException : public std::exception
+        { virtual char const * what() const throw() 
+                { return "senf::log::Target::InvalidAreaException"; } };
 
+        iterator begin() const;
+        iterator end() const;
+        
     private:
-
         void route(detail::StreamBase const * stream, detail::AreaBase const * area, 
-                   unsigned level);
+                   unsigned level, action_t action, int index);
         void unroute(detail::StreamBase const * stream, detail::AreaBase const * area, 
-                     unsigned level);
+                     unsigned level, action_t action);
 
-        void updateAreaCache(detail::AreaBase const & area, detail::StreamBase const * stream,
-                             unsigned level);
+        void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
 
-        void write(detail::StreamBase const & stream, detail::AreaBase const & area, 
-                   unsigned level, std::string const & message);
-        
-        virtual void v_write(std::string const & stream, std::string const & area, unsigned level,
-                             std::string const & message) = 0;
+        void write(boost::posix_time::ptime timestamp, detail::StreamBase const & stream,
+                   detail::AreaBase const & area, unsigned level, std::string const & message);
 
-        struct RoutingEntry 
-        {
-            RoutingEntry(detail::StreamBase const * stream_, detail::AreaBase const * area_, 
-                         unsigned level_)
-                : stream(stream_), area(area_), level(level_) {}
-            RoutingEntry() 
-                : stream(0), area(0), level(0) {}
-
-            bool operator==(RoutingEntry const & other) 
-                { return stream == other.stream && area == other.area && level == other.level; }
-
-            detail::StreamBase const * stream;
-            detail::AreaBase const * area;
-            unsigned level;
-        };
+#   ifdef DOXYGEN
+    protected:
+#   endif
 
-        typedef std::vector<RoutingEntry> RIB;
+        virtual void v_write(boost::posix_time::ptime, std::string const & stream, 
+                             std::string const & area, unsigned level, 
+                             std::string const & message) = 0;
+
+#   ifdef DOXYGEN
+    private:
+#   endif
 
         RIB rib_;
+        
+        friend class detail::AreaBase;
     };
 
+    /** \brief Target registry
+
+        The TargetRegistry keeps a record of all existing targets. 
+      */
+    class TargetRegistry
+        : public senf::singleton<TargetRegistry>
+    {
+    public:
+        using senf::singleton<TargetRegistry>::instance;
+
+        void write(detail::StreamBase const & stream, detail::AreaBase const & area,
+                   unsigned level, std::string msg);
+
+    private:
+        void registerTarget(Target * target);
+        void unregisterTarget(Target * target);
+
+        typedef std::set<Target *> Targets;
+        Targets targets_;
+        
+        friend class Target;
+    };
+
+
+    template <class Stream, class Area, class Level>
+    void write(std::string msg);
+
 }}
 
 ///////////////////////////////hh.e////////////////////////////////////////
 #include "Target.cci"
 //#include "Target.ct"
-//#include "Target.cti"
+#include "Target.cti"
 #endif
 
 \f