// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Area inline non-template implementation */
+ \brief AreaRegistry inline non-template implementation */
-#include "Area.ih"
+#include "AreaRegistry.ih"
// Custom includes
#include "../TypeInfo.hh"
#include "Levels.hh"
-#include "Stream.hh"
+#include "StreamRegistry.hh"
#define prefix_ inline
///////////////////////////////cci.p///////////////////////////////////////
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Area public header */
+ \brief AreaRegistry public header */
-#ifndef HH_Area_
-#define HH_Area_ 1
+#ifndef HH_AreaRegistry_
+#define HH_AreaRegistry_ 1
// Custom includes
#include <map>
#include <boost/iterator/transform_iterator.hpp>
#include "../singleton.hh"
-//#include "Area.mpp"
+//#include "AreaRegistry.mpp"
+#include "AreaRegistry.ih"
///////////////////////////////hh.p////////////////////////////////////////
-/** \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) SENF_LOG_DEF_AREA_I(area, ; )
-
namespace senf {
namespace log {
namespace detail { struct AreaBase; }
-
+
+ /** \brief Area registry
+
+ The area registry keeps track of all areas defined. Area classes are defined as singletons
+ and will automatically register with this registry.
+
+ The area registry exposes a forward sequence interface which is a sequence of the names of
+ all registered areas.
+ */
class AreaRegistry
: public senf::singleton<AreaRegistry>
{
public:
typedef boost::transform_iterator<SelectName, Registry::const_iterator> iterator;
+# ifdef DOXYGEN
+ // Hmm ... doxygen does not understand using declarations ...
+ /// Access area registry singleton instance
+ static AreaRegistry & instance();
+# endif
+
using senf::singleton<AreaRegistry>::instance;
iterator begin();
}}
///////////////////////////////hh.e////////////////////////////////////////
-#include "Area.cci"
-//#include "Area.ct"
-//#include "Area.cti"
+#include "AreaRegistry.cci"
+//#include "AreaRegistry.ct"
+//#include "AreaRegistry.cti"
#endif
\f
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Defaults public header */
+ \brief AreaRegistry internal header */
-#ifndef HH_Defaults_
-#define HH_Defaults_ 1
+#ifndef IH_AreaRegistry_
+#define IH_AreaRegistry_ 1
// Custom includes
-#include "Stream.hh"
-#include "Area.hh"
+#include <string>
+#include <vector>
-//#include "Defaults.mpp"
-///////////////////////////////hh.p////////////////////////////////////////
+///////////////////////////////ih.p////////////////////////////////////////
namespace senf {
namespace log {
+namespace detail {
- SENF_LOG_DEF_STREAM(Debug, MESSAGE, DISABLED, DISABLED);
+ class StreamBase;
- SENF_LOG_DEF_AREA_I(DefaultArea,
- std::string v_name() const { return ""; });
+ /** \brief Internal: Area base class */
+ struct AreaBase
+ {
+ virtual ~AreaBase() {};
+
+ std::string fullName() const;
+ virtual std::string v_name() const;
-}}
+ void init();
-///////////////////////////////hh.e////////////////////////////////////////
-//#include "Defaults.cci"
-//#include "Defaults.ct"
-//#include "Defaults.cti"
+ unsigned streamLimit(StreamBase const & stream) const;
+ void setStreamLimit(StreamBase const & stream, unsigned value) const;
+
+ private:
+ typedef std::vector<unsigned> StreamLimits;
+ // mutable since this is a cache and may therefore change at unexpected places ...
+ mutable StreamLimits streamLimits_;
+ };
+
+}}}
+
+
+///////////////////////////////ih.e////////////////////////////////////////
#endif
\f
#include "Config.ih"
///////////////////////////////hh.p////////////////////////////////////////
+/** \defgroup config Configuration
+
+ The logger infrastructure provides for very fine-grained configuration of log messages. There
+ are two parts to this configuration: compile-time configuration and runtime configuration.
+
+ <em>Compile-time</em> configuration selects, which log statements will even be compiled. If
+ logging for a certain combination of stream, area and level is disabled at compile time, no code
+ will be generated for any such disabled log statement. This type of configuration is done using
+ \ref SENF_LOG_CONF.
+
+ <em>Runtime</em> configuration on the other hand deals with routing all those messages, which
+ are enabled at compile time to the logging targets. If a message is not routed, it will be
+ discarded. This allows to additionally disable messages at run-time.
+ */
+
namespace senf {
namespace log {
+ ///\ingroup config
+ ///\{
+
+# ifdef DOXYGEN
+
+ /** \brief Compile time configuration
+
+ This define symbol sets the compile time logger configuration. This symbol should normally
+ be set on the compiler command line:
+ <pre>
+ g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Debug),(_),DISABLED ))
+ (( (senf)(log)(Debug),(foo)(SomeClass),(VERBOSE) ))
+ (( (foo)(Transactions),(_),NOTICE ))" ...
+ </pre>
+ (As this option can get quite long, you might want to use the '-imacros' option instead)
+
+ The formal syntax of this option is:
+
+ \par ""
+ <table class="ebnf">
+ <tr><td>conf</td> <td>::= \e element \e element* \n</td></tr>
+ <tr><td>element</td> <td>::= <tt>((</tt> \e stream <tt>,</tt> \e optional_area <tt>,</tt> \e level <tt>))</tt> \n</td></tr>
+ <tr><td>stream</td> <td>::= \e scope_seq \n</td></tr>
+ <tr><td>optional_area</td><td>::= <tt>(_)</tt> | \e scope_seq \n</td></tr>
+ <tr><td>level</td> <td>::= \c VERBOSE | \c NOTICE | \c MESSAGE | \c IMPORTANT | \c CRITICAL | \c DISABLED \n</td></tr>
+ <tr><td>scope_seq</td> <td>::= \e scope \e scope \e scope* \n</td></tr>
+ <tr><td>scope</td> <td>::= <tt>(</tt> \e name <tt>)</tt> \n</td></tr>
+ <tr><td>name</td> <td>::= arbitrary C++ identifier</td></tr>
+ </table>
+
+ \ref SENF_LOG_CONF is a Boost.Preprocessor style sequence of 3-tuples. Each tuple applies to
+ a specific stream which is defined by the first tuple element \e stream.
+
+ The next tuple element, \e optional_area optionally restricts the entry to match only the
+ given area.
+
+ The last tuple element \e level defines the compile time log level. Messages with a level
+ below this are discarded at compile time.
+
+ Both \e stream and \e optional_area are given as a \e scope_seq. A scope sequence is a fully
+ qualified C++ identifier placed into a sequence: <tt>foo::bar::baz</tt> is represented by
+ <tt>(foo)(bar)(baz)</tt>.
+ */
+# define SENF_LOG_CONF
+
+# endif
+
+ /** \brief Check, if logging is enabled for stream/area/level tuple
+
+ This is a template meta-function which will check, whether logging to the given combination
+ of parameters \a Stream, \a Area and \a Level is compile-time enabled. The logging might
+ still be disabled at runtime.
+ \code
+ if (senf::log::Enabled<senf::log::Debug,
+ senf::log::DefaultArea,
+ senf::log::VERBOSE>::value) {
+ // ...
+ }
+ \endcode
+
+ Since the \e value member is a compile time constant, the compiler will completely optimize
+ away this block of code when logging is disabled.
+ */
template <class Stream, class Area, class Level>
struct Enabled
{
>= detail::Config<Stream,Area>::compileLimit::value );
};
+ ///\}
+
}}
///////////////////////////////hh.e////////////////////////////////////////
namespace log {
namespace detail {
+ /// Internal: Compile time configuration for given \a Stream and \a Area
template <class Stream, class Area>
struct Config
{
typedef typename Config<Stream,void>::compileLimit compileLimit;
};
+# ifndef DOXYGEN
+
template <class Stream>
struct Config<Stream, void>
{
typedef typename Stream::compileLimit compileLimit;
};
+# endif
+
}}}
-#define SENF_LOG_SEQ_TO_NAME_(s,data,elem) ::elem
+#define SENF_LOG_SEQ_TO_NAME_(s,state,elem) state::elem
#define SENF_LOG_SEQ_TO_NAME(seq) \
- BOOST_PP_SEQ_FOR_EACH(SENF_LOG_SEQ_TO_NAME_, none, seq)
+ BOOST_PP_SEQ_FOLD_LEFT(SENF_LOG_SEQ_TO_NAME_, , seq)
#define SENF_LOG_PREDECL_(s, state, elem) \
namespace elem { state }
#ifdef SENF_LOG_CONF
-# define SLC_elt(s, state, elt) \
+# define SLC_elt(r, data, elt) \
SENF_LOG_CONF_DEFINE elt
// Need to use fold here to not exhaust the maximum FOR nesting depth ...
- BOOST_PP_SEQ_FOLD_LEFT(SLC_elt, none, SENF_LOG_CONF)
+ BOOST_PP_SEQ_FOR_EACH(SLC_elt, none, SENF_LOG_CONF)
# undef SLC_elt
--- /dev/null
+// $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 Definitions public header */
+
+#ifndef HH_Definitions_
+#define HH_Definitions_ 1
+
+// Custom includes
+
+//#include "Definitions.mpp"
+#include "Definitions.ih"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace log {
+
+ ///\addtogroup logging
+ ///\{
+ ///\name Defining logger objects
+ ///\{
+
+ /** \brief Define log stream
+
+ Defines a new log stream named \a stream. The stream is defined as a symbol in the current
+ scope.
+
+ \a defaultLevel defines the default log level for messages posted to this stream. \a
+ runtimeLimit defines the default log limit. Messages with a level below this will not be
+ output. \a compileLimit defines the default log level limit at compile time: Messages
+ posted with a level below \a compileLimit will be discarded at compile time.
+
+ \hideinitializer
+ */
+# define SENF_LOG_DEF_STREAM(stream, defaultLevel_, runtimeLimit_, compileLimit_) \
+ struct stream \
+ : public senf::log::detail::StreamBase, public senf::singleton<stream> \
+ { \
+ typedef defaultLevel_ defaultLevel; \
+ typedef runtimeLimit_ runtimeLimit; \
+ typedef compileLimit_ compileLimit; \
+ static std::string name() { return instance().v_name(); } \
+ private: \
+ stream() { init(); } \
+ friend class senf::singleton<stream>; \
+ }
+
+ /** \brief Define log area
+
+ Defines a new log area named \a area. The area is defined as a symbol in the current scope.
+
+ \hideinitializer
+ \ingroup logging
+ */
+# define SENF_LOG_DEF_AREA(area) SENF_LOG_DEF_AREA_I(area, ; )
+
+ /** \brief Define new default log area for the class
+
+ This command declares the containing class to be it's own default log area. It is such like a
+ combination of \ref SENF_LOG_DEF_AREA and \ref SENF_LOG_DEFAULT_AREA with a twist.
+ */
+# define SENF_LOG_CLASS_AREA() \
+ SENF_LOG_DEF_AREA_I( \
+ SENFLogArea, \
+ std::string v_name() const \
+ { std::string s (fullName()); return std::string(s,0,s.size()-13); }); \
+ SENF_LOG_DEFAULT_AREA(SENFLogArea)
+
+
+ /** \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) \
+ struct alias : public senf::log::detail::AliasBase \
+ { \
+ template <class Base> \
+ struct apply \
+ { \
+ typedef typename SENF_LOG_MERGE_PARAMETERS_I(Base,args) type; \
+ }; \
+ }
+
+ /** \brief Default global log stream */
+ SENF_LOG_DEF_STREAM(Debug, MESSAGE, DISABLED, DISABLED);
+
+ /** \brief Default global log area */
+ SENF_LOG_DEF_AREA_I(DefaultArea,
+ std::string v_name() const { return ""; });
+
+ ///\}
+ ///\}
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "Definitions.cci"
+//#include "Definitions.ct"
+//#include "Definitions.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:
//
// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Kompetenzzentrum fuer NETwork research (NET)
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Area internal header */
+ \brief Definitions internal header */
-#ifndef IH_Area_
-#define IH_Area_ 1
+#ifndef IH_Definitions_
+#define IH_Definitions_ 1
// Custom includes
-#include <string>
-#include <vector>
///////////////////////////////ih.p////////////////////////////////////////
-namespace senf {
-namespace log {
-namespace detail {
-
- class StreamBase;
-
- struct AreaBase
- {
- virtual ~AreaBase() {};
-
- std::string fullName() const;
- virtual std::string v_name() const;
-
- void init();
-
- unsigned streamLimit(StreamBase const & stream) const;
- void setStreamLimit(StreamBase const & stream, unsigned value) const;
-
- private:
- typedef std::vector<unsigned> StreamLimits;
- // mutable since this is a cache and may therefore change at unexpected places ...
- mutable StreamLimits streamLimits_;
- };
-
-}}}
-
#define SENF_LOG_DEF_AREA_I(area, decls) \
struct area \
: public senf::log::detail::AreaBase, public senf::singleton<area> \
friend class senf::singleton<area>; \
}
+namespace senf {
+namespace log {
+namespace detail {
+
+ /// Internal: Alias base class
+ struct AliasBase {};
+
+}}}
+
///////////////////////////////ih.e////////////////////////////////////////
#endif
namespace senf {
namespace log {
- /** \brief Log levels
+ /** \defgroup loglevels Log levels
These are the valid log levels with some additional special values:
\c NONE is used to in some special places to inherit the default log level.
*/
+ ///\ingroup loglevels
+ ///\{
+
+ /** \brief Log level VERBOSE
+ \see loglevels */
struct VERBOSE : public detail::LevelBase { static unsigned const value = 1; };
+
+ /** \brief Log level NOTICE
+ \see loglevels */
struct NOTICE : public detail::LevelBase { static unsigned const value = 2; };
+
+ /** \brief Log level MESSAGE
+ \see loglevels */
struct MESSAGE : public detail::LevelBase { static unsigned const value = 3; };
+
+ /** \brief Log level IMPORTANT
+ \see loglevels */
struct IMPORTANT : public detail::LevelBase { static unsigned const value = 4; };
+
+ /** \brief Log level CRITICAL
+ \see loglevels */
struct CRITICAL : public detail::LevelBase { static unsigned const value = 5; };
+ /** \brief Disable logging
+ \see loglevels */
struct DISABLED : public detail::LevelBase { static unsigned const value = 6; };
+
+ /** \brief Inherit log level
+ \see loglevels */
struct NONE : public detail::LevelBase { static unsigned const value = 0; };
+ ///\}
+
}}
///////////////////////////////hh.e////////////////////////////////////////
namespace senf {
namespace log {
namespace detail {
-
+
+ /// Internal: Log level base class
struct LevelBase {};
}}}
#include "Parameters.hh"
//#include "Log.mpp"
+#include "Log.ih"
///////////////////////////////hh.p////////////////////////////////////////
+/** \defgroup logging Logging commands
+
+ The logging library provides several commands to create log messages. All these macro commands
+ take a variable number of arguments. Since this is not supported in a usable way 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
+
+ For each log message, the following information is needed:
+ \li The <em>log stream</em>,
+ \li the <em>log area</em>,
+ \li the <em>log level</em>,
+ \li and the log message itself
+
+ These parameters may be specified <i>in arbitrary order</i> and even multiple times in the
+ parameter sequence. If some argument type occurs multiple times, the last occurrence wins. If
+ any one of the parameters is not specified, it's current default value will be used.
+
+ This current default value is set using \ref SENF_LOG_DEFAULT_STREAM, \ref SENF_LOG_DEFAULT_AREA
+ and \ref SENF_LOG_DEFAULT_LEVEL respectively. These macros set the default stream, area and/or
+ level of the current scope. The logging library defines the global defaults for these values to
+ be \c senf::log::Debug (\e stream), senf::log::DefaultArea (\e area), and senf::log::NONE (\e
+ level).
+
+ There is one special log level, senf::log::NONE. If the log level is set to this value, the log
+ level will be set from the stream provided default value.
+
+
+ All these parameters must be <em>compile time constants</em> (they are all types, so it's
+ difficult form them to be something else).
+ */
+
+///\ingroup logging
+///\{
+
+///\name Generating log messages
+///\{
+
/** \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
- <i>some-log-sttream</i> \c << <i>last-macro-arg</i>).
+ <i>some-log-stream</i> \c << <i>last-macro-arg</i>).
\code
SENF_LOG((parameters...)("log message " << args << ...));
\endcode
SENF_LOG_BLOCK_( SENF_LOG_MERGE_PARAMETERS(BOOST_PP_SEQ_POP_BACK(args)), \
{ log << BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(args)),args); })
+/** \brief Write log message (template context)
+
+ This macro is used like \ref SENF_LOG() if called from a template context
+
+ \hideinitializer
+ */
#define SENF_LOG_TPL(args) \
SENF_LOG_BLOCK_( SENF_LOG_MERGE_PARAMETERS_TPL(BOOST_PP_SEQ_POP_BACK(args)), \
{ log << BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(args)),args); })
SENF_LOG_BLOCK_( SENF_LOG_MERGE_PARAMETERS(BOOST_PP_SEQ_POP_BACK(args)), \
BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(args)),args))
+/** \brief Write log message (template context)
+
+ This macro is used like \ref SENF_LOG_BLOCK() if called from a template context
+
+ \hideinitializer
+ */
#define SENF_LOG_BLOCK_TPL(args) \
SENF_LOG_BLOCK_( SENF_LOG_MERGE_PARAMETERS_TPL(BOOST_PP_SEQ_POP_BACK(args)), \
BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(args)),args))
-#define SENF_LOG_BLOCK_(parameters, block) \
- do { \
- if (parameters::compile_enabled && parameters::enabled()) { \
- std::ostream & log (parameters::log_stream()); \
- do block while(0); \
- log << std::endl; \
- } \
- } while(0)
+///\}
+///\}
///////////////////////////////hh.e////////////////////////////////////////
//#include "Log.cci"
//
// Copyright (C) 2007
// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// Kompetenzzentrum fuer NETwork research (NET)
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Stream internal header */
+ \brief Log internal header */
-#ifndef IH_Stream_
-#define IH_Stream_ 1
+#ifndef IH_Log_
+#define IH_Log_ 1
// Custom includes
-#include <string>
///////////////////////////////ih.p////////////////////////////////////////
-namespace senf {
-namespace log {
-namespace detail {
-
- struct StreamBase
- {
- StreamBase();
- virtual ~StreamBase() {};
-
- std::string fullName() const;
- virtual std::string v_name() const;
-
- void init();
-
- unsigned index;
- static unsigned nStreams;
- };
-
-}}}
+#define SENF_LOG_BLOCK_(parameters, block) \
+ do { \
+ if (parameters::compile_enabled && parameters::enabled()) { \
+ std::ostream & log (parameters::log_stream()); \
+ do block while(0); \
+ log << std::endl; \
+ } \
+ } while(0)
///////////////////////////////ih.e////////////////////////////////////////
#endif
#define SENF_LOG_CONF (( (senf)(log)(Debug), (_), NOTICE ))
-#include "Log.hh"
-#include "Defaults.hh"
-#include "Parameters.hh"
-#include "Levels.hh"
+#include "Logger.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-namespace {
+namespace not_anonymous {
- template <class T>
struct Foo
{
- typedef int value;
+ SENF_LOG_CLASS_AREA();
+
+ static void log() {
+ SENF_LOG(("Foo::log"));
+ }
};
SENF_LOG_DEF_ALIAS( LogCritical, (senf::log::Debug) (senf::log::CRITICAL) );
SENF_LOG_DEF_AREA( myArea );
}
+using namespace not_anonymous;
BOOST_AUTO_UNIT_TEST(logger)
{
log << " continued here";
}));
+ Foo::log();
+ SENF_LOG((Foo)("Foo area"));
+
BOOST_CHECK_EQUAL( logstream.str(),
"Important message\n"
"Another log message: 10\n"
- "Last message continued here\n" );
+ "Last message continued here\n"
+ "Foo::log\n" );
}
BOOST_AUTO_UNIT_TEST(streamRegistry)
{
- char const * streams[] = { "(anonymous namespace)::myStream", "senf::log::Debug" };
+ char const * streams[] = { "not_anonymous::myStream", "senf::log::Debug" };
BOOST_CHECK_EQUAL_COLLECTIONS( senf::log::StreamRegistry::instance().begin(),
senf::log::StreamRegistry::instance().end(),
BOOST_AUTO_UNIT_TEST(areaRegistry)
{
- char const * areas[] = { "", "(anonymous namespace)::myArea" };
+ char const * areas[] = { "", "not_anonymous::Foo", "not_anonymous::myArea" };
BOOST_CHECK_EQUAL_COLLECTIONS( senf::log::AreaRegistry::instance().begin(),
senf::log::AreaRegistry::instance().end(),
targets at the same time. To allow concise usage of the library, a utility 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:
+ \see
+ \ref logging \n
+ \ref config \n
- \code
- SENF_LOG( (senf::log::Debug)(senf::log::NOTICE)(FroblizerArea)("The log message") );
- \endcode
+ \section logging_tutorial Tutorial introduction
- The last sequence element always is the log message. Before that we have a number of log
- parameters <i>in arbitrary order</i>. 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_DEFAULT_STREAM, \ref SENF_LOG_DEFAULT_AREA and \ref SENF_LOG_DEFAULT_LEVEL 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.
+ Using the logging library mostly concerns using \ref SENF_LOG statements in your code. There are
+ some other helpers used to simplify specifying parameters.
\code
- SENF_LOG_DEF_STREAM( userLog, senf::log::MESSAGE, senf::log::MESSAGE );
+ namespace foo {
- class Froblizer
- {
- // Define a new log area
- SENF_LOG_DEF_AREA(FroblizerArea);
+ // Define a new log stream with default level, runtime limit and compile time limit
+ // set to senf::log::MESSAGE
+ SENF_LOG_DEF_STREAM( UserLog, senf::log::MESSAAGE, senf::log::MESSAGE, senf::log::MESSAGE );
- // Set default log parameters for this scope
- SENF_LOG_DEFAULTS((senf::log::Debug)(senf::log::NOTICE)(FroblizerArea));
+ class Froblizer
+ {
+ // Define a log area which will automatically be used by all members of this class.
+ // This is a combination of SENF_LOG_DEF_AREA and SENF_LOG_DEFAULT_AREA.
+ SENF_LOG_CLASS_AREA();
- // 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));
+ // Set default log parameters for this scope. The values here are not really
+ // necessary since these are the global default values
+ SENF_LOG_DEFAULT_STREAM(foo::UserLog);
+ SENF_LOG_DEFAULT_LEVEL(senf::log::NOTICE);
- void test();
+ // Define an alias for emergency debug messages
+ // 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, (senf::log::Debug)(senf::log::CRITICAL));
- public:
- void froblize();
- };
+ void test();
+
+ public:
+ void froblize();
+ };
+ }
- void Froblizer::froblize()
+ void foo::Froblizer::froblize()
{
- SENF_LOG(("This is the Debug stream at level NOTICE in the FroblizeArea"));
+ SENF_LOG(("This is the UserLog 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"));
+ SENF_LOG((LogEmerg) ("This goes to the DebugLog at level CRITICAL in the FroblizerArea"));
}
- void Froblizer::test()
+ void foo::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::VERBOSE));
+ SENF_LOG_DEFAULT_LEVEL(senf::log::VERBOSE);
- SENF_LOG(("Log to Debug stream in Froblizer area however at VERBOSE level"));
+ SENF_LOG(("Log to UserLog stream in Froblizer area however at VERBOSE 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 of 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.
-
- 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.
-
- \section logger_compile_conf Compile time configuration
-
- The logger infrastructure allows to enable or disable log levels or areas at compile
- time. Levels or areas disabled at compile time do not generate any code. The compile time
- configuration is done in two parts: When defining log streams, default log levels and log level
- limits are defined. Additionally the \c SENF_LOG_CONF symbol can be defined to customize this
- default configuration.
-
- The \c SENF_LOG_CONF symbol is a Boost.Preprocessor style sequence of sequences:
- <pre>
- g++ ... -DSENF_LOG_CONF="((senf::log::Debug)(_)(DISABLED)) \
- ((senf::log::Debug)(foo::FooArea)(VERBOSE))" ...
- </pre>
- Each element defines the compile time limit for a stream and optional area.
-
\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
+ 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 non-mcaro
+ 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.
*/
\f
#define HH_Parameters_ 1
// Custom includes
-#include "Area.hh"
//#include "Parameters.mpp"
#include "Parameters.ih"
///////////////////////////////hh.p////////////////////////////////////////
+///\addtogroup logging
+///\{
+///\name Default parameters
+///\{
+
/** \brief Set scope default log stream
\hideinitializer
*/
*/
#define SENF_LOG_DEFAULT_LEVEL(level) typedef level SENFLogDefaultLevel
-/** \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) \
- struct alias : public senf::log::detail::AliasBase \
- { \
- template <class Base> \
- struct apply \
- { \
- typedef typename SENF_LOG_MERGE_PARAMETERS_I(Base,args) type; \
- }; \
- }
-
-#define SENF_LOG_CLASS_AREA() \
- SENF_LOG_DEF_AREA_I(SenfLogArea, \
- std::string v_name() const \
- { std::string s (fullName()); return std::string(s,s.size()-13); }); \
- SENF_LOG_DEFAULT_AREA(SenfLogArea)
-
+///\}
+///\}
///////////////////////////////hh.e////////////////////////////////////////
//#include "Parameters.cci"
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/fold.hpp>
-#include "Defaults.hh"
#include "../mpl.hh"
-#include "Stream.hh"
-#include "Area.hh"
-#include "Levels.hh"
#include "Config.hh"
///////////////////////////////ih.p////////////////////////////////////////
# define _senf_LOG_STREAM std::cerr
#endif
-typedef senf::log::Debug SENFLogDefaultStream;
-typedef senf::log::DefaultArea SENFLogDefaultArea;
-typedef senf::log::NONE SENFLogDefaultLevel;
-
namespace senf {
namespace log {
+
+ class DefaultArea;
+ class Debug;
+ class NONE;
+
namespace detail {
- struct AliasBase {};
+ class StreamBase;
+ class AreaBase;
+ class LevelBase;
+ class AliasBase;
+ /// Internal: Parameter extractor
template <class Base, class Param, unsigned N>
struct Parameters_ {};
+#ifndef DOXYGEN
+
senf::mpl::rv<1> Parameters_select_(StreamBase *);
template <class Base, class Param>
struct Parameters_<Base,Param,1> : public Base
: public Param::template apply<Base>::type
{};
+ // This trick makes any class with a SENFLogArea typedef member usable as area. A typedef of
+ // this name is created by SENF_LOG_CLASS_AREA()
+ template <class T>
+ senf::mpl::rv<6> Parameters_select_(
+ T *,
+ typename boost::disable_if< boost::is_convertible<T*,StreamBase*> >::type * = 0,
+ typename boost::disable_if< boost::is_convertible<T*,AreaBase*> >::type * = 0,
+ typename boost::disable_if< boost::is_convertible<T*,LevelBase*> >::type * = 0,
+ typename boost::disable_if< boost::is_convertible<T*,AliasBase*> >::type * = 0);
+ template <class Base, class Param>
+ struct Parameters_<Base,Param,6> : public Base
+ { typedef typename Param::SENFLogArea area; };
+
+#endif
+
+ /// Internal: Log message parameter collection
template <class Base>
struct Parameters : public Base
{
-
static bool const compile_enabled = senf::log::Enabled<
typename Base::stream,
typename Base::area,
static std::ostream & log_stream() { return _senf_LOG_STREAM; }
};
+ /// Internal: Empty base class
struct empty {};
- struct Parameters_Merge_
+ /// Internal: Merge log message parameter list
+ struct Parameters_Merge
{
+ /// Internal: Embedded mpl template meta-function
template <class Base, class Param>
struct apply {
typedef Parameters_<
}}}
+typedef senf::log::Debug SENFLogDefaultStream;
+typedef senf::log::DefaultArea SENFLogDefaultArea;
+typedef senf::log::NONE SENFLogDefaultLevel;
+
#define SENF_LOG_MERGE_ARG(r, data, i, elem) BOOST_PP_COMMA_IF(i) elem
#define SENF_LOG_MERGE_PARAMETERS_I(base, args) \
boost::mpl::fold< \
boost::mpl::vector< BOOST_PP_SEQ_FOR_EACH_I(SENF_LOG_MERGE_ARG, _, args) >, \
base, \
- senf::log::detail::Parameters_Merge_ >::type
+ senf::log::detail::Parameters_Merge >::type
#define SENF_LOG_MERGE_PARAMETERS(args) \
senf::log::detail::Parameters< SENF_LOG_MERGE_PARAMETERS_I( \
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Stream non-inline non-template implementation */
+ \brief StreamRegistry non-inline non-template implementation */
-#include "Stream.hh"
-#include "Stream.ih"
+#include "StreamRegistry.hh"
+#include "StreamRegistry.ih"
// Custom includes
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Stream inline non-template implementation */
+ \brief StreamRegistry inline non-template implementation */
-#include "Stream.ih"
+#include "StreamRegistry.ih"
// Custom includes
#include "../TypeInfo.hh"
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Stream public header */
+ \brief StreamRegistry public header */
-#ifndef HH_Stream_
-#define HH_Stream_ 1
+#ifndef HH_StreamRegistry_
+#define HH_StreamRegistry_ 1
// Custom includes
#include <map>
#include "Levels.hh"
#include "../singleton.hh"
-//#include "Stream.mpp"
+//#include "StreamRegistry.mpp"
+#include "StreamRegistry.ih"
///////////////////////////////hh.p////////////////////////////////////////
-/** \brief Define log stream
-
- Defines a new log stream named \a stream. The stream is defined as a symbol in the current
- scope.
-
- \a defaultLevel defines the default log level for messages posted to this stream. \a
- runtimeLimit defines the default log limit. Messages with a level below this will not be
- output. \a compileLimit defines the default log level limit at compile time: Messages
- posted with a level below \a compileLimit will be discarded at compile time.
-
- \hideinitializer
- */
-#define SENF_LOG_DEF_STREAM(stream, defaultLevel_, runtimeLimit_, compileLimit_) \
- struct stream \
- : public senf::log::detail::StreamBase, public senf::singleton<stream> \
- { \
- typedef defaultLevel_ defaultLevel; \
- typedef runtimeLimit_ runtimeLimit; \
- typedef compileLimit_ compileLimit; \
- static std::string name() { return instance().v_name(); } \
- private: \
- stream() { init(); } \
- friend class senf::singleton<stream>; \
- }
-
namespace senf {
namespace log {
namespace detail { struct StreamBase; }
+ /** \brief Stream registry
+
+ The stream registry keeps track of all streams defined. stream classes are defined as
+ singletons and will automatically register with this registry.
+
+ The stream registry exposes a forward sequence interface which is a sequence of the names of
+ all registered streams.
+ */
class StreamRegistry
: public senf::singleton<StreamRegistry>
{
public:
typedef boost::transform_iterator<SelectName, Registry::const_iterator> iterator;
+# ifdef DOXYGEN
+ // Hmm ... doxygen does not understand using declarations ...
+ /// Access stream registry singleton instance
+ static AreaRegistry & instance();
+# endif
+
using senf::singleton<StreamRegistry>::instance;
iterator begin();
}}
///////////////////////////////hh.e////////////////////////////////////////#
-#include "Stream.cci"
-//#include "Stream.ct"
-//#include "Stream.cti"
+#include "StreamRegistry.cci"
+//#include "StreamRegistry.ct"
+//#include "StreamRegistry.cti"
#endif
\f
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Stream internal header */
+ \brief StreamRegistry internal header */
-#ifndef IH_Stream_
-#define IH_Stream_ 1
+#ifndef IH_StreamRegistry_
+#define IH_StreamRegistry_ 1
// Custom includes
#include <string>
namespace log {
namespace detail {
+ /// Internal: Log stream base class
struct StreamBase
{
StreamBase();
// Custom includes
#include "../singleton.hh"
-#include "Stream.hh"
-#include "Area.hh"
+#include "StreamRegistry.hh"
+#include "AreaRegistry.hh"
//#include "Target.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
namespace log {
- /** \brief
+ /** \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).
*/
class Target
: public senf::singleton<Target>
"SENF_PARSER_VARIANT(name,chooser,types)=senf::Parse_Variant_Direct<chooser ## _t,?,types>::parser name() const" \
"SENF_PARSER_PRIVATE_VARIANT(name,chooser,types)=private: senf::Parse_Variant_Direct<chooser ## _t,?,types>::parser name() const; public:" \
"SENF_PARSER_VEC_N(name,elt_type,size_type)=senf::Parse_VectorN<elt_type,size_type> name() const"
-EXPAND_AS_DEFINED = prefix_
+EXPAND_AS_DEFINED = prefix_ SENF_LOG_DEF_STREAM SENF_LOG_DEF_AREA SENF_LOG_DEF_AREA_I
HTML_HEADER = "$(TOPDIR)/doclib/doxy-header.html"
HTML_FOOTER = "$(TOPDIR)/doclib/doxy-footer.html"
font-weight: bold;
}
+table.ebnf {
+ margin: 0;
+ padding: 0;
+ border-spacing: 0;
+ border: none;
+ font-size: 120%; /* ???????? Why is THIS needed ?? */
+}
+
+table.ebnf td {
+ text-align: left;
+ border: none;
+ padding: 0;
+}
+
+table.ebnf td:first-child {
+ width: 1%;
+ padding-right: 1ex;
+ font-style: italic;
+}
+
dl.xref-bug, dl.xref-fix, dl.xref-todo, dl.xref-idea {
border: 1px solid #CC8888;
padding: 2px 3px;
aListCollection
alloc
arg
+args
async
autoThrottling
aVectorCollection
dd
de
DebugModules
+DefaultArea
DefaultBundle
defaultInit
defgroup
FooParser
ForwardingRoute
fraunhofer
+FroblizerArea
fuer
GlobalScope
hangup