Logger API skeleton implementation
g0dil [Tue, 20 Feb 2007 11:19:40 +0000 (11:19 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@204 270642c3-0616-0410-b53a-bc976706d245

Utils/Logger.hh [new file with mode: 0644]
Utils/Logger.test.cc [new file with mode: 0644]

diff --git a/Utils/Logger.hh b/Utils/Logger.hh
new file mode 100644 (file)
index 0000000..3082632
--- /dev/null
@@ -0,0 +1,218 @@
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     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 Logger public header */
+
+/** \defgroup logger The SENF Logger
+    
+    The Loggger infrastructure shall implement a highliy flexible compile- and run-time configurable
+    logging infrastructure supporting multiple streams, user defineable log areas and fine grained
+    log levels. Logging can be configured at compile and runtime on any combination of above
+    parameters. The library supports a host of log targets and messages can be routed into multiple
+    targets at the same time. To allow concise usage of the libarary, a utlity to define logging
+    defaults for any scope is provided.
+
+    An important basic concept of the library is, that most of the macros take a variable number of
+    arguments. Since this is not supported in the needed manner by the C++ preprocessor, the
+    arguments are encoded into a <a
+    href="http://www.boost.org/libs/preprocessor/doc/index.html">Boost.Preprocessor</a> like
+    sequence:
+    
+    \code
+    SENF_LOG( (senf::log::Debug)(senf::log::NOTICE)(FroblizerArea)("The log message") );
+    \endcode
+    
+    The last sequence element always is the log message. Before that we have a number of log
+    parameters <it>in arbitrary order</it>. Since giving all the parameters in every log message is
+    to verbose, there are two helpful constructs to reduce the verbosity. Using \ref SENF_LOG_DEFAULTS it
+    is possible to define the default logging parameters to be used within a given scope. Using
+    \ref SENF_LOG_DEF_ALIAS you can define an alias (which is a scoped symbol) as an arbitrary
+    combination of parameters.
+
+    \code
+    SENF_LOG_DEF_STREAM(userLog);
+    
+    class Froblizer 
+    {
+        // Define a new log area
+        SENF_LOG_DEF_AREA(FroblizerArea);
+
+        // Set default log parameters for this scope
+        SENF_LOG_DEFAULTS( (senf::log::Debug) (senf::log::NOTICE) (FroblizerArea) );
+
+        // Define an alias for emergency messages to the sysadmin.
+        // The log area is inherited from the default at the place, where this
+        // alias is used *not* where it is defined
+        SENF_LOG_DEF_ALIAS(LogEmerg, (userLog) (senf::log::CRITICAL));
+
+        void test();
+
+    public:
+        void froblize();
+    };
+
+    void Froblizer::froblize()
+    {
+        SENF_LOG(("This is the Debug stream at level NOTICE in the FroblizeArea"));
+        SENF_LOG((senf::log::WARNING) ("Same stream and area but at warning level"));
+        SENF_LOG((LogEmerg) ("This goes to the userLog at level CRITICAL in the FroblizerArea"));
+    }
+
+    void Froblizer::test()
+    {
+        // Change the default log level for this method. stream and area are taken
+        // from the next scope up
+        SENF_LOG_DEFAULTS((senf::log::DEBUG));
+
+        SENF_LOG(("Log to Debug stream in Froblizer area however at DEBUG level"));
+    }
+    \endcode
+
+    Currently, the library is not implemented in any way. The interface has been defined up to a
+    point and we have dummy implementations of the 'in-code' part ot the interface. This is the
+    part, which is called throughout the code. The configuration API is defined but we don't even
+    have a template implementation. However, this allows starting to use the SENF Logger in newly
+    developed code. Even though this code will unconditionally log everything to \c std::cerr for
+    now and errors in the parameter specification will not be caught (since they are just ignored)
+    the logging should work automatically as advertised as soon as the logger is completely
+    implemented.
+
+    \implementation I would have much preferred a more C++ like implementation. However given the
+    design goals
+    \li Flexible configuration at compile and runtime
+    \li Concise usage and simple interface
+    \li Zero overhead for compile-time disabled log messages
+
+    I did not find any implementation which was not either completely convoluted, unusable or
+    slow. So I turned to a macro based implementation which can provide all the design goals stated
+    above.
+ */
+
+#ifndef HH_Logger_
+#define HH_Logger_ 1
+
+// Custom includes
+#include <iostream>
+#include <boost/preprocessor/seq/size.hpp>
+#include <boost/preprocessor/dec.hpp>
+#include <boost/preprocessor/seq/elem.hpp>
+
+//#include "Logger.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+#   ifndef _senf_LOG_STREAM
+#     define _senf_LOG_STREAM std::cerr
+#   endif
+   
+    /// \addtogroup logger
+    /// @{
+
+    /** \brief Write log message
+       
+       This macro will write it's last argument to the log stream. The last argument must be an
+       expression which will be placed after a streaming \c operator<< (like
+       <it>some-log-sttream</it> \c << <it>last-macro-arg</it>).
+       \code
+       BOOST_LOG((parameters...)("log message " << args << ...));
+       \endcode
+
+       \hideinitializer
+     */
+#   define SENF_LOG(args)                                                                      \
+        _senf_LOG_STREAM << BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(args)),args)      \
+                         << std::endl;
+
+    /** \brief Enable block based on logging parameters
+       
+       This macro is like SENF_LOG, however instead of writing a simple message, this macro allows
+       to specify a complete block of code to be executed if the log message is enabled.
+       \code
+       BOOST_LOG_BLOCK((parameters...)({
+          // arbitrary code using 'log' for logging
+          log << "log message";
+        }));
+       \endcode
+
+       \hideinitializer
+     */
+#   define SENF_LOG_BLOCK(args)                                                        \
+        do {                                                                   \
+            std::ostream & log (_senf_LOG_STREAM);                             \
+           BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(args)),args)       \
+            log << std::endl;                                                  \
+       } while (0)
+
+    /** \brief Set scope default log parameters
+
+       Sets the default log parameters for the current scope
+       \code
+       BOOST_LOG_DEFAULTS((parameters...));
+       \endcode
+
+       \hideinitializer
+     */
+#   define SENF_LOG_DEFAULTS(args)
+
+    /** \brief Define log area
+       
+       Defines a new log area named \a area. The area is defined as a symbol in the current scope.
+
+       \hideinitializer
+     */
+#   define SENF_LOG_DEF_AREA(area)
+
+    /** \brief Define log stream
+       
+       Defines a new log stream named \a stream. The stream is defined as a symbol in the current
+       scope.
+
+       \hideinitializer
+     */
+#   define SENF_LOG_DEF_STREAM(stream)
+
+    /** \brief Define log parameter alias
+       
+       Defines a new parameter alias named \a alias as an alias for the parameters in \a args. The
+       alias is defined as a symbol in the current scope.
+
+       \hideinitializer
+     */
+#   define SENF_LOG_DEF_ALIAS(alias,args)
+
+    /// @}
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "Logger.cci"
+//#include "Logger.ct"
+//#include "Logger.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// ispell-local-dictionary: "american"
+// End:
diff --git a/Utils/Logger.test.cc b/Utils/Logger.test.cc
new file mode 100644 (file)
index 0000000..3efa3d5
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     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 Logger.test unit tests */
+
+//#include "Logger.test.hh"
+//#include "Logger.test.ih"
+
+// Custom includes
+#include <sstream>
+#define _senf_LOG_STREAM logstream
+#include "Logger.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+BOOST_AUTO_UNIT_TEST(logger)
+{
+    std::stringstream logstream;
+
+    SENF_LOG_DEFAULTS( (senf::log::Debug) (senf::log::NOTICE) );
+    SENF_LOG_DEF_ALIAS( LogFoo, (senf::log::Debug) (senf::log::CRITICAL) );
+    SENF_LOG_DEF_STREAM( myStream );
+    SENF_LOG_DEF_AREA( myArea );
+
+    SENF_LOG(("Log message"));
+
+    SENF_LOG((LogFoo) ("Another log message: " << 10));
+
+    SENF_LOG_BLOCK((senf::log::Debug) (senf::log::WARNING) ({
+       log << "Last message";
+       log << " continued here";
+    }));
+
+    BOOST_CHECK_EQUAL( logstream.str(), "Log message\nAnother log message: 10\nLast message continued here\n" );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// ispell-local-dictionary: "american"
+// End: