Utils/Logger: Completed documentation
g0dil [Wed, 31 Oct 2007 15:31:33 +0000 (15:31 +0000)]
Utils/Logger: FileTarget implementation

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@488 270642c3-0616-0410-b53a-bc976706d245

15 files changed:
Packets/MPEGDVBBundle/GREPacket.hh
SConstruct
Utils/Logger/Config.hh
Utils/Logger/ConsoleTarget.hh
Utils/Logger/FileTarget.cc [new file with mode: 0644]
Utils/Logger/FileTarget.hh [new file with mode: 0644]
Utils/Logger/IOStreamTarget.hh
Utils/Logger/Log.ih
Utils/Logger/Mainpage.dox
Utils/Logger/StringTarget.hh
Utils/Logger/Target.cc
Utils/Logger/Target.cci
Utils/Logger/Target.cti
Utils/Logger/Target.hh
Utils/Logger/Target.ih [new file with mode: 0644]

index fc1d433..fa0b2e2 100644 (file)
@@ -43,8 +43,8 @@ namespace senf {
      */
     struct Parse_GREPacket : public PacketParserBase
     {
-        
-#include SENF_PARSER()
+#       include SENF_PARSER()
+
         SENF_PARSER_BITFIELD         ( checksum_present,  1, bool );
         SENF_PARSER_PRIVATE_BITFIELD ( reserved0_,       12, unsigned ); // TODO: SKIP !!
         SENF_PARSER_BITFIELD_RO      ( version_number,    3, unsigned ); // TODO: Always Zero !!
@@ -53,6 +53,7 @@ namespace senf {
                                                    (VoidPacketParser) (Parse_UInt16) );
         SENF_PARSER_PRIVATE_VARIANT  ( reserved1_, checksum_present,
                                                    (VoidPacketParser) (Parse_UInt16) );
+
         SENF_PARSER_FINALIZE( Parse_GREPacket );
 
       private: 
index 2753d30..478cfdf 100644 (file)
@@ -168,6 +168,8 @@ if not env.GetOption('clean') and not os.path.exists(".prepare-stamp") \
 
 env.Clean('all', '.prepare-stamp')
 
+# Not nice, but until we get to fixing the dependency jungle
+# concerning generated sources ...
 scripts = []
 dependencies = []
 
index 7ec3c7f..8e55030 100644 (file)
@@ -86,8 +86,8 @@
     decide a log messages fate for that target.
 
     \see 
-        \ref SENF_LOG_CONF: compile time configuration \n
-        \ref senf::log::Target: runtime configuration
+        \ref SENF_LOG_CONF compile time configuration \n
+        \ref senf::log::Target runtime configuration
  */
 
 namespace senf {
index b345ef7..85cf8d7 100644 (file)
@@ -38,6 +38,8 @@ namespace log {
     /** \brief Write log messages to std::cout
 
         IOStreamTarget writing to std::cout
+
+        \ingroup targets
      */
     class ConsoleTarget : public IOStreamTarget
     {
diff --git a/Utils/Logger/FileTarget.cc b/Utils/Logger/FileTarget.cc
new file mode 100644 (file)
index 0000000..c2538c4
--- /dev/null
@@ -0,0 +1,64 @@
+// $Id$
+//
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer NETwork research (NET)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief FileTarget non-inline non-template implementation */
+
+#include "FileTarget.hh"
+//#include "FileTarget.ih"
+
+// Custom includes
+
+//#include "FileTarget.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+prefix_ senf::log::FileTarget::FileTarget(std::string file)
+    : ofstream_t(file.c_str(), std::ofstream::app), IOStreamTarget(ofstream_t::member), file_(file)
+{}
+
+prefix_ void senf::log::FileTarget::reopen()
+{
+    ofstream_t::member.close();
+    ofstream_t::member.open(file_.c_str(), std::ofstream::app);
+}
+
+prefix_ void senf::log::FileTarget::reopen(std::string file)
+{
+    file_ = file;
+    reopen();
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "FileTarget.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/Logger/FileTarget.hh b/Utils/Logger/FileTarget.hh
new file mode 100644 (file)
index 0000000..a6fac2b
--- /dev/null
@@ -0,0 +1,90 @@
+// $Id$
+//
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer NETwork research (NET)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief FileTarget public header */
+
+#ifndef HH_FileTarget_
+#define HH_FileTarget_ 1
+
+// Custom includes
+#include <boost/utility.hpp>
+#include <fstream>
+#include "IOStreamTarget.hh"
+
+//#include "FileTarget.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace log {
+
+    /** \brief Log target writing to a log file.
+
+        The FileTarget will save all log messages in the given file. Messages will be appended at
+        the end of the file.
+
+        After log files have been rotated, the reopen() member should be called to create a new log
+        file.
+
+        \ingroup targets
+      */
+    class FileTarget 
+        : private boost::base_from_member<std::ofstream>,
+          public IOStreamTarget
+    {
+        typedef boost::base_from_member<std::ofstream> ofstream_t;
+
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        explicit FileTarget(std::string file); ///< Construct FileTarget writing to \a file
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+        void reopen();                  ///< Reopen log after log-file rotation
+        void reopen(std::string file);  ///< Reopen log under a new name
+
+    private:
+        std::string file_;
+    };
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "FileTarget.cci"
+//#include "FileTarget.ct"
+//#include "FileTarget.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
index 94f9999..3e0b61e 100644 (file)
@@ -55,7 +55,9 @@ namespace log {
         \warning The class keeps a reference to the passed stream.
         
         \note This class will permanently and globally change the date formating of the given
-            stream.
+            stream if no \c boost::posix_time::time_facet has been set.
+
+        \ingroup targets
       */
     class IOStreamTarget
         : public Target
index 95c6020..e87be73 100644 (file)
 
 #define SENF_LOG_BLOCK_(parameters, block)                                                        \
     do {                                                                                          \
-        if (parameters::compileEnabled && parameters::enabled()) {                                \
+        typedef parameters SENFLogParameters;                                                     \
+        if (SENFLogParameters::compileEnabled && SENFLogParameters::enabled()) {                  \
             std::stringstream log;                                                                \
             do block while(0);                                                                    \
-            senf::log::write<parameters::stream, parameters::area, parameters::level>(log.str()); \
+            senf::log::detail::write< SENFLogParameters::stream,                                  \
+                                      SENFLogParameters::area,                                    \
+                                      SENFLogParameters::level >(log.str());                      \
         }                                                                                         \
     } while(0) 
 
 #define SENF_LOG_BLOCK_TPL_(parameters, block)                                                    \
     do {                                                                                          \
-        if (parameters::compileEnabled && parameters::enabled()) {                                \
+        typedef parameters SENFLogParameters;                                                     \
+        if (SENFLogParameters::compileEnabled && SENFLogParameters::enabled()) {                  \
             std::stringstream log;                                                                \
             do block while(0);                                                                    \
-            senf::log::write<typename parameters::stream,                                         \
-                             typename parameters::area,                                           \
-                             typename parameters::level>(log.str());                              \
+            senf::log::detail::write<typename SENFLogParameters::stream,                          \
+                             typename SENFLogParameters::area,                                    \
+                             typename SENFLogParameters::level>(log.str());                       \
         }                                                                                         \
     } while(0) 
 
index 30b80fa..bc1d220 100644 (file)
 
     \section logging_concepts Concepts
 
-    The log messages are devided along several categories: \e streams, \e areas and log \e levels.
-
-    A \e stream combines log messages with a single purpose. There is one default stream, called \c
-    senf::log::Debug. New streams are defined with \ref SENF_LOG_DEF_STREAM.
-
-    An \e area labels a log message with the source location of the message. An area is an arbitrary
-    tag which may be added to the message. There is one default area called \c
-    senf::log::DefaultArea. New areas are defined either with \ref SENF_LOG_DEF_AREA or \ref
-    SENF_LOG_CLASS_AREA, the latter being the more typical. The area will normally indicate the
-    class or subsystem from which the message was generated.
-
-    The log \e level gives information on the importance of the message. The list lof \ref loglevels
-    is fixed.
-
-    After log messages have been created, they have to be placed somewhere. This is the
-    responsibility of the \e target. A target is an arbitrary sink for log messages. The target
-    manages message routing and will pass the message on to it's destination, be it the system
-    console, some log file or some other place (e.g. an SQL database). The target is responsible for
-    formating the message.
+    Log messages are arbitrarily created throughout the code using simple log statements (which are
+    macros). Besides the log message itself, every log message is labeled with additional
+    information: The \e stream, the \e area and a log \e level. If the message is not compile-time
+    disabled, the message is then directed to one of several log \e targets.
+
+    A \e stream combines log messages with a single purpose: Debug messages, access logging and so
+    on. Any number of streams may be defined. There is one predefined default stream called \c
+    senf::log::Debug. (see: \ref SENF_LOG_DEF_STREAM)
+
+    The \e area gives information about the source location of the message. Areas may be defined and
+    assigned arbitrarily but should be used to label messages from a single class or subsystem. It
+    is possible to reuse a class as it's own area tag, which is often desireable.  (see: \ref
+    SENF_LOG_DEF_AREA, \ref SENF_LOG_CLASS_AREA)
+
+    The log \e level gives information on the importance of the message. The list of log-levels is
+    fixed. (see: \ref loglevels)
+
+    Depending on their the \e stream, \e area and \e level information, log messages can be enabled
+    or disabled at \e compile time. Messages disabled at compile time should not generate any
+    code. (see: \ref SENF_LOG_CONF)
+
+    To be of any use, the log messages have to be written somewhere. This is the responsibility of
+    any number of \e targets. A \e target receives messages and using it's routing information
+    decides, wether the message is output or not. A message may be routed to multiple targets
+    simultaneously or may not be output by any target at all. (see: \ref targets)
     
     \section logging_tutorial Tutorial introduction
 
 
         SENF_LOG(("Log to UserLog stream in Froblizer area however at VERBOSE level"));
     }
+
+    int main(int, char **)
+    {
+        // Set up the routing targets
+        senf::log::ConsoleTarget console;
+        senf::log::FileTarget logfile ("my.log");
+
+        // Debug messages go to the console
+        console.route<senf::log::Debug>();
+        // Important user message are written to the log file
+        logfile.route<foo::UserLog, senf::log::IMPORTANT>();
+    }
     \endcode
 
     \implementation I would have much preferred a more C++ like implementation. However given the
index 6aa740b..1981d74 100644 (file)
@@ -37,6 +37,10 @@ namespace senf {
 namespace log {
   
     /** \brief Store log messages in a string buffer
+
+        This target is mostly useful for debug purposes. 
+
+        \ingroup targets
       */
     class StringTarget 
         : private boost::base_from_member<std::stringstream>,
@@ -56,8 +60,8 @@ namespace log {
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
-        std::string str() const;
-        void clear();
+        std::string str() const;        ///< Get log messages accumulated so far
+        void clear();                   ///< Clear buffer
 
     protected:
 
index c07ba21..3c32f95 100644 (file)
@@ -24,7 +24,7 @@
     \brief Target non-inline non-template implementation */
 
 #include "Target.hh"
-//#include "Target.ih"
+#include "Target.ih"
 
 // Custom includes
 #include <algorithm>
@@ -38,7 +38,7 @@
 
 prefix_ senf::log::Target::Target()
 {
-    TargetRegistry::instance().registerTarget(this);
+    detail::TargetRegistry::instance().registerTarget(this);
 }
 
 prefix_ senf::log::Target::~Target()
@@ -49,7 +49,7 @@ prefix_ senf::log::Target::~Target()
         RIB::reverse_iterator i (rib_.rbegin());
         unroute(i->stream_, i->area_, i->level_, i->action_);
     }
-    TargetRegistry::instance().unregisterTarget(this);
+    detail::TargetRegistry::instance().unregisterTarget(this);
 }
 
 prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
@@ -90,7 +90,7 @@ prefix_ void senf::log::Target::unroute(int index)
             i = rib_.begin();
         else {
             i = rib_.end();
-            std::advance(i, -index);
+            std::advance(i, index);
         }
     } else {
         if (RIB::size_type(index+1) >= rib_.size()) {
@@ -101,6 +101,8 @@ prefix_ void senf::log::Target::unroute(int index)
             std::advance(i, index);
         }
     }
+    if (i == rib_.end())
+        return;
     RoutingEntry entry (*i);
     rib_.erase(i);
     if (entry.action_ == ACCEPT)
@@ -199,9 +201,9 @@ prefix_ void senf::log::Target::write(boost::posix_time::ptime timestamp,
 ///////////////////////////////////////////////////////////////////////////
 // senf::log::TargetRegistry
 
-prefix_ void senf::log::TargetRegistry::write(detail::StreamBase const & stream,
-                                              detail::AreaBase const & area, unsigned level,
-                                              std::string msg)
+prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
+                                                      AreaBase const & area, unsigned level,
+                                                      std::string msg)
 {
     boost::posix_time::ptime timestamp (boost::posix_time::microsec_clock::universal_time());
     area.write(timestamp, stream, level, msg);
index 1d6f6d9..e7b2409 100644 (file)
@@ -23,7 +23,7 @@
 /** \file
     \brief Target inline non-template implementation */
 
-//#include "Target.ih"
+#include "Target.ih"
 
 // Custom includes
 
@@ -92,14 +92,14 @@ prefix_ senf::log::Target::action_t senf::log::Target::RoutingEntry::action()
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::log::TargetRegistry
+// senf::log::detail::TargetRegistry
 
-prefix_ void senf::log::TargetRegistry::registerTarget(Target * target)
+prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target)
 {
     targets_.insert(target);
 }
 
-prefix_ void senf::log::TargetRegistry::unregisterTarget(Target * target)
+prefix_ void senf::log::detail::TargetRegistry::unregisterTarget(Target * target)
 {
     targets_.erase(target);
 }
index 2312dc6..ccc364d 100644 (file)
@@ -23,7 +23,7 @@
 /** \file
     \brief Target inline template implementation */
 
-//#include "Target.ih"
+#include "Target.ih"
 
 // Custom includes
 #include "Levels.hh"
@@ -36,6 +36,8 @@
 
 // senf::log::Target::route
 
+#ifndef DOXYGEN
+
 template <class Stream>
 prefix_ void senf::log::Target::route(action_t action, int index)
 {
@@ -130,11 +132,13 @@ unroute(action_t action,
     unroute(&Stream::instance(), &AreaClass::SENFLogArea::instance(), Level::value, action);
 }
 
+#endif 
+
 ///////////////////////////////////////////////////////////////////////////
-// namespace senf::log members
+// namespace senf::log::detail members
 
 template <class Stream, class Area, class Level>
-prefix_ void senf::log::write(std::string msg)
+prefix_ void senf::log::detail::write(std::string msg)
 {
     TargetRegistry::instance().write(Stream::instance(), Area::instance(), Level::value, msg);
 }
index b4137d6..5b8dd1b 100644 (file)
 //#include "Target.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 
+/** \defgroup targets Targets
+
+    Targets receive log messages and write them to some destination: The console, a log file, an SQL
+    DB and so on. Every target is derived from the \ref senf::log::Target base class. This base
+    class provides the target with the necessary routing infrastructure. The different targets only
+    differ in the way, they write the data.
+
+    \see senf::log::Target
+ */
+
 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
-        responsibility of the logging target to write the log messages somewhere: onto the console,
-        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).
+        
+        Targets are the final destination of log messages. Every message is eventually routed to one
+        or several targets.
+
+        \section target_routing Routing
+
+        Each target manages a routing table. The message meta-data (stream, area and level) is
+        matched against this table. If an entry matches, the action associated with this entry is
+        taken (either \c ACCEPT or \c REJECT).
+
+        Every target manages it's own routing table. Conceptually, every routing message will be
+        routed to every target where it will then be matched against each targets routing table (the
+        implementation is more efficient and utilizes a routing cache).
+
+        Each routing entry consists of the following parameters
+        \li (mandatory) \e stream. The entry will match only messages directed at that stream
+        \li (optional) \e area. If the area is specified, only messages directed at that area are
+            matched, otherwise any area will be allowed
+        \li (optional) \e level. If the log level is specified, messages will be accepted if their
+            level is at least that value. If the value is not specified, the limit will be taken
+            from the stream's default value.
+
+        Each parameter (stream, area and level) has two representations: A static (compile time
+        constant) representation, which is the representation also used in the log statements, and a
+        dynamic representation, which may be used for manipulating the routing table.
+
+        The static representation is used, when passing routing parameters via template arguments:
+        \code
+        target.route<foo::SomeStream, senf::log::NOTICE>(senf::log::Target::REJECT);
+        target.route<foo::SomeStream>();
+        \endcode
+        The identical routing statements may be expressed using dynamic routing via:
+        \code
+        target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT);
+        target.route("foo::SomeStream");
+        \endcode
+        The static representation has the benefit of being compile-time type checked: Invalid
+        routing parameters will be caught while compiling the code. The dynamic representation is
+        more flexible as it allows to adjust routing from user input (e.g. configuration files).
+
+        The different object representations are:
+        \li The \e streams is statically represented by it's name, which is the name of a class
+            defined with \ref SENF_LOG_DEF_STREAM. The dynamic representation is a string
+            representation of this name.
+        \li The \e area is statically represented by it's name, which again is the name of a class
+            defined with \ref SENF_LOG_DEF_STREAM. The dynamic representation again is a string
+            representation of this class's name. The dynamic representation represents an absent
+            area with the empty string.
+        \li The \e level is statically represented by a level class from \ref
+            loglevels. Dynamically, it is represented by an unsigned integer number, the \c value
+            member of that class.
+
+        \section target_impl Implementing new targets
+
+        To implement a new target type, you need to derive from senf::log::Target and implement the
+        single \c v_write member. This member will be called whenever a message should be output. 
+
+        The target may process in any arbitrary way: reformat, writing it into an SQL DB, whatever
+        can be envisioned. However, there is one important limitation: The \c v_write call must not
+        block. So for more complex scenarios, additional measures must be taken (e.g. writing a log
+        backend daemon which receives the messages via UDP and processes them). Of course, in rare
+        cases messages might be lost but this cannot be avoided.
+
+        \see \ref targets
 
         \fixme optionally Integrate with Scheduler / ClockService to reduce number of gettimeofday()
             calls.
@@ -61,18 +129,37 @@ namespace log {
         ///////////////////////////////////////////////////////////////////////////
         // Types
 
-        enum action_t { ACCEPT, REJECT };
+        /** \brief Routing action
 
+            Every routing entry is associated with a routing action. This action is final (for this
+            target. Each target is processed independently).
+         */
+        enum action_t { 
+            ACCEPT /** Output message */
+          , REJECT /** Suppress message output */
+        };
+
+        /** \brief Target routing entry
+
+            A single routing entry matches messages against their \e stream, \e area and \e
+            level. If the entry matches, the given \e action is performed.
+
+            \see senf::log::Target
+         */
         struct RoutingEntry 
         {
+            std::string stream() const; ///< Stream to match
+            std::string area() const;   ///< Area to match (empty of unspecified)
+            unsigned level() const;     ///< Level to match (senf::log::NONE::value if unspecified)
+            action_t action() const;    ///< Action to take
+            
+#           ifdef DOXYGEN
+        private:
+#           endif
+
             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);
@@ -89,7 +176,7 @@ namespace log {
         typedef std::vector<RoutingEntry> RIB;
 
     public:
-        typedef RIB::const_iterator iterator;
+        typedef RIB::const_iterator iterator; ///< Routing table iterator
 
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
@@ -99,6 +186,112 @@ namespace log {
         virtual ~Target();
 
         ///@}
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Routing
+        ///\{
+
+#       ifdef DOXYGEN
+
+        template <class Stream, class Area, class Level> void route(
+            action_t action = ACCEPT, int index = -1); ///< Add route (static)
+                                        /**< Add a route for the given combination of \a Stream, \a
+                                             Area and \a Level. The \a Stream parameter is mandatory
+                                             while either \a Area or \a Level are optional (the
+                                             template signature is shown simplified here):
+                                             \code
+                                             target.route<SomeStream>();
+                                             target.route<SomeStream, SomeLevel>();
+                                             target.route<SomeStream, SomeArea>();
+                                             target.route<SomeStream, SomeArea, SomeLevel>();
+                                             \endcode
+
+                                             See the class description for information on the \a
+                                             action and \a index parameters 
+
+                                             \param[in] Stream mandatory stream to match
+                                             \param[in] Area optional area to match
+                                             \param[in] Level optional level, matches messages with
+                                                 at least the given level. 
+                                             \param[in] action routing action to take
+                                             \param[in] index position of new route in the routing
+                                                 table */
+
+#       endif
+
+        void route(std::string const & stream, std::string const & area = "", 
+                   unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
+                                        ///< Add route (dynamic)
+                                        /**< Add a route for the given combination of \a stream, \a
+                                             area and \a level. The \a stream parameter is mandatory
+                                             while either \a area or \a level may be left
+                                             unspecified by setting them to the empty string or
+                                             senf::log::NONE::value respectively.
+
+                                             See the class description for information on the \a
+                                             action and \a index parameters 
+
+                                             \throws InvalidStreamException if the given \a stream
+                                                 is not found in the StreamRegistry
+                                             \throws InvalidAreaException if the given \a area is
+                                                 not found in the AreaRegistry
+
+                                             \param[in] stream mandatory stream to match
+                                             \param[in] area optional area to match
+                                             \param[in] level optional level, matches messages with
+                                                 at least the given level.
+                                             \param[in] action routing action to take
+                                             \param[in] index position of new route in the routing
+                                                 table */
+
+#       ifdef DOXYGEN
+
+        template <class Stream, class Area, class Level> 
+        void unroute(action_t action = ACCEPT);
+                                        ///< Remove route (static)
+                                        /**< This member removes an arbitrary routing entry. The
+                                             template parameters are the same as for the
+                                             corresponding \ref route() call.
+
+                                             The routing table is searched for a route exactly
+                                             matching the given specification. If such a route is
+                                             found, it will be removed, otherwise the call will be
+                                             ignored
+
+                                             \param[in] Stream mandatory stream to match
+                                             \param[in] Area optional area to match
+                                             \param[in] Level optional level, matches messages with
+                                                 at least the given level. 
+                                             \param[in] action routing action to take */
+
+#       endif
+
+        void unroute(std::string const & stream, std::string const & area = "", 
+                     unsigned level = NONE::value, action_t action = ACCEPT);
+                                        ///< Remove route (dynamic)
+                                        /**< This member removes an arbitrary routing entry. The \a
+                                             stream parameter is mandatory while either \a area or
+                                             \a level may be left unspecified by setting them to the
+                                             empty string or senf::log::NONE::value respectively.
+
+                                             The routing table is searched for a route exactly
+                                             matching the given specification. If such a route is
+                                             found, it will be removed, otherwise the call will be
+                                             ignored
+
+                                             \param[in] stream mandatory stream to match
+                                             \param[in] area optional area to match
+                                             \param[in] level optional level, matches messages with
+                                                 at least the given level.
+                                             \param[in] action routing action to take */
+        void unroute(int index=-1);     ///< Remove route (indexed)
+                                        /**< This call will remove the route with the given index.
+                                             
+                                             See the class documentation for more information on
+                                             indexing. 
+
+                                             \param[in] index index of routing entry to remove */
+
+#       ifndef DOXYGEN
 
         template <class Stream> void route(
             action_t action = ACCEPT, int index = -1);
@@ -123,9 +316,6 @@ namespace log {
             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(
@@ -149,20 +339,22 @@ namespace log {
             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);
+#       endif
+
+        ///\}
 
+        /** \brief Exception: Invalid stream */
         struct InvalidStreamException : public std::exception
         { virtual char const * what() const throw() 
                 { return "senf::log::Target::InvalidStreamException"; } };
         
+        /** \brief Exception: Invalid area */
         struct InvalidAreaException : public std::exception
         { virtual char const * what() const throw() 
                 { return "senf::log::Target::InvalidAreaException"; } };
 
-        iterator begin() const;
-        iterator end() const;
+        iterator begin() const;         ///< Iterator to beginning of routing table
+        iterator end() const;           ///< Iterator past the end of routing table
         
     private:
         void route(detail::StreamBase const * stream, detail::AreaBase const * area, 
@@ -179,9 +371,28 @@ namespace log {
     protected:
 #   endif
 
-        virtual void v_write(boost::posix_time::ptime, std::string const & stream, 
+        virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream, 
                              std::string const & area, unsigned level, 
                              std::string const & message) = 0;
+                                        ///< Called to write out the routing message
+                                        /**< This member must be defined in the derived class to
+                                             somehow format and write the log message. 
+
+                                             Every log message always possesses a complete set of
+                                             meta information (\a stream, \a area and \a level). The
+                                             \a area may be an empty string if the message was
+                                             written from the senf::log::DefaultArea.
+
+                                             \note This member must \e not block since it may be
+                                                 called from any unknown context. This prohibits
+                                                 simple logging over NFS or many other network
+                                                 protocols.
+
+                                             \param[in] timestamp log message timing information
+                                             \param[in] stream message stream
+                                             \param[in] area message area
+                                             \param[in] level message level
+                                             \param[in] message the message string */
 
 #   ifdef DOXYGEN
     private:
@@ -192,33 +403,6 @@ namespace log {
         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////////////////////////////////////////
diff --git a/Utils/Logger/Target.ih b/Utils/Logger/Target.ih
new file mode 100644 (file)
index 0000000..115c71e
--- /dev/null
@@ -0,0 +1,75 @@
+// $Id$
+//
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer NETwork research (NET)
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief Target internal header */
+
+#ifndef IH_Target_
+#define IH_Target_ 1
+
+// Custom includes
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+namespace log {
+namespace detail {
+
+    /** \brief Internal: Target registry */
+    class TargetRegistry
+        : public senf::singleton<TargetRegistry>
+    {
+    public:
+        using senf::singleton<TargetRegistry>::instance;
+
+        void write(StreamBase const & stream, 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 senf::log::Target;
+    };
+
+    /** \brief Internal: Write log message */
+    template <class Stream, class Area, class Level>
+    void write(std::string msg);
+
+}}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End: