From: g0dil Date: Wed, 24 Oct 2007 22:08:06 +0000 (+0000) Subject: Utils/Logger: Reorganize source code X-Git-Url: http://g0dil.de/git?p=senf.git;a=commitdiff_plain;h=61419d9a2e1060f7ede22fa19fd9d0b401bbc87a Utils/Logger: Reorganize source code Utils/Logger: Documentation Utils/Logger: Better SENF_LOG_CLASS_AREA integration Utils/Logger: Fix compile-time config bug for larger configurations git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@475 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Utils/Logger/Area.cci b/Utils/Logger/AreaRegistry.cci similarity index 96% rename from Utils/Logger/Area.cci rename to Utils/Logger/AreaRegistry.cci index 58a59cb..fa19ed5 100644 --- a/Utils/Logger/Area.cci +++ b/Utils/Logger/AreaRegistry.cci @@ -21,14 +21,14 @@ // 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/////////////////////////////////////// diff --git a/Utils/Logger/Area.hh b/Utils/Logger/AreaRegistry.hh similarity index 75% rename from Utils/Logger/Area.hh rename to Utils/Logger/AreaRegistry.hh index 648bd8c..6dd3d30 100644 --- a/Utils/Logger/Area.hh +++ b/Utils/Logger/AreaRegistry.hh @@ -21,10 +21,10 @@ // 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 @@ -32,22 +32,23 @@ #include #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 { @@ -62,6 +63,12 @@ namespace log { public: typedef boost::transform_iterator iterator; +# ifdef DOXYGEN + // Hmm ... doxygen does not understand using declarations ... + /// Access area registry singleton instance + static AreaRegistry & instance(); +# endif + using senf::singleton::instance; iterator begin(); @@ -82,9 +89,9 @@ namespace log { }} ///////////////////////////////hh.e//////////////////////////////////////// -#include "Area.cci" -//#include "Area.ct" -//#include "Area.cti" +#include "AreaRegistry.cci" +//#include "AreaRegistry.ct" +//#include "AreaRegistry.cti" #endif diff --git a/Utils/Logger/Defaults.hh b/Utils/Logger/AreaRegistry.ih similarity index 58% rename from Utils/Logger/Defaults.hh rename to Utils/Logger/AreaRegistry.ih index a6d6340..362c3f6 100644 --- a/Utils/Logger/Defaults.hh +++ b/Utils/Logger/AreaRegistry.ih @@ -21,32 +21,46 @@ // 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 +#include -//#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 StreamLimits; + // mutable since this is a cache and may therefore change at unexpected places ... + mutable StreamLimits streamLimits_; + }; + +}}} + + +///////////////////////////////ih.e//////////////////////////////////////// #endif diff --git a/Utils/Logger/Config.hh b/Utils/Logger/Config.hh index 0cc8362..a9bf7c7 100644 --- a/Utils/Logger/Config.hh +++ b/Utils/Logger/Config.hh @@ -33,9 +33,87 @@ #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. + + Compile-time 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. + + Runtime 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: +
+        g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Debug),(_),DISABLED ))
+                                 (( (senf)(log)(Debug),(foo)(SomeClass),(VERBOSE) ))
+                                 (( (foo)(Transactions),(_),NOTICE ))" ...
+        
+ (As this option can get quite long, you might want to use the '-imacros' option instead) + + The formal syntax of this option is: + + \par "" + + + + + + + + + +
conf ::= \e element \e element* \n
element ::= (( \e stream , \e optional_area , \e level )) \n
stream ::= \e scope_seq \n
optional_area::= (_) | \e scope_seq \n
level ::= \c VERBOSE | \c NOTICE | \c MESSAGE | \c IMPORTANT | \c CRITICAL | \c DISABLED \n
scope_seq ::= \e scope \e scope \e scope* \n
scope ::= ( \e name ) \n
name ::= arbitrary C++ identifier
+ + \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: foo::bar::baz is represented by + (foo)(bar)(baz). + */ +# 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::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 struct Enabled { @@ -44,6 +122,8 @@ namespace log { >= detail::Config::compileLimit::value ); }; + ///\} + }} ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Utils/Logger/Config.ih b/Utils/Logger/Config.ih index 10b9e4a..6fec502 100644 --- a/Utils/Logger/Config.ih +++ b/Utils/Logger/Config.ih @@ -41,24 +41,29 @@ namespace senf { namespace log { namespace detail { + /// Internal: Compile time configuration for given \a Stream and \a Area template struct Config { typedef typename Config::compileLimit compileLimit; }; +# ifndef DOXYGEN + template struct Config { 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 } @@ -86,11 +91,11 @@ namespace detail { #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 diff --git a/Utils/Logger/Definitions.hh b/Utils/Logger/Definitions.hh new file mode 100644 index 0000000..5e9d5cc --- /dev/null +++ b/Utils/Logger/Definitions.hh @@ -0,0 +1,134 @@ +// $Id$ +// +// Copyright (C) 2007 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer NETwork research (NET) +// Stefan Bund +// +// 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 \ + { \ + typedef defaultLevel_ defaultLevel; \ + typedef runtimeLimit_ runtimeLimit; \ + typedef compileLimit_ compileLimit; \ + static std::string name() { return instance().v_name(); } \ + private: \ + stream() { init(); } \ + friend class senf::singleton; \ + } + + /** \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 \ + 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 + + +// 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/Area.ih b/Utils/Logger/Definitions.ih similarity index 75% rename from Utils/Logger/Area.ih rename to Utils/Logger/Definitions.ih index 168ecb0..7e97381 100644 --- a/Utils/Logger/Area.ih +++ b/Utils/Logger/Definitions.ih @@ -2,7 +2,7 @@ // // Copyright (C) 2007 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) -// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) +// Kompetenzzentrum fuer NETwork research (NET) // Stefan Bund // // This program is free software; you can redistribute it and/or modify @@ -21,43 +21,15 @@ // 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 -#include ///////////////////////////////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 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 \ @@ -69,6 +41,15 @@ namespace detail { friend class senf::singleton; \ } +namespace senf { +namespace log { +namespace detail { + + /// Internal: Alias base class + struct AliasBase {}; + +}}} + ///////////////////////////////ih.e//////////////////////////////////////// #endif diff --git a/Utils/Logger/Levels.hh b/Utils/Logger/Levels.hh index 35aa048..7616843 100644 --- a/Utils/Logger/Levels.hh +++ b/Utils/Logger/Levels.hh @@ -35,7 +35,7 @@ namespace senf { namespace log { - /** \brief Log levels + /** \defgroup loglevels Log levels These are the valid log levels with some additional special values: @@ -44,15 +44,39 @@ namespace log { \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//////////////////////////////////////// diff --git a/Utils/Logger/Levels.ih b/Utils/Logger/Levels.ih index 442efd1..f507928 100644 --- a/Utils/Logger/Levels.ih +++ b/Utils/Logger/Levels.ih @@ -33,7 +33,8 @@ namespace senf { namespace log { namespace detail { - + + /// Internal: Log level base class struct LevelBase {}; }}} diff --git a/Utils/Logger/Log.hh b/Utils/Logger/Log.hh index 072e893..81b7703 100644 --- a/Utils/Logger/Log.hh +++ b/Utils/Logger/Log.hh @@ -34,13 +34,56 @@ #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 Boost.Preprocessor 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 log stream, + \li the log area, + \li the log level, + \li and the log message itself + + These parameters may be specified in arbitrary order 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 compile time constants (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 - some-log-sttream \c << last-macro-arg). + some-log-stream \c << last-macro-arg). \code SENF_LOG((parameters...)("log message " << args << ...)); \endcode @@ -51,6 +94,12 @@ 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); }) @@ -72,18 +121,18 @@ 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" diff --git a/Utils/Logger/Stream.ih b/Utils/Logger/Log.ih similarity index 60% copy from Utils/Logger/Stream.ih copy to Utils/Logger/Log.ih index a2db435..d669ff5 100644 --- a/Utils/Logger/Stream.ih +++ b/Utils/Logger/Log.ih @@ -2,7 +2,7 @@ // // Copyright (C) 2007 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) -// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) +// Kompetenzzentrum fuer NETwork research (NET) // Stefan Bund // // This program is free software; you can redistribute it and/or modify @@ -21,35 +21,23 @@ // 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 ///////////////////////////////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 diff --git a/Utils/Logger/Log.test.cc b/Utils/Logger/Log.test.cc index cc31c61..000164e 100644 --- a/Utils/Logger/Log.test.cc +++ b/Utils/Logger/Log.test.cc @@ -38,10 +38,7 @@ namespace { #define SENF_LOG_CONF (( (senf)(log)(Debug), (_), NOTICE )) -#include "Log.hh" -#include "Defaults.hh" -#include "Parameters.hh" -#include "Levels.hh" +#include "Logger.hh" #include #include @@ -49,12 +46,15 @@ namespace { #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -namespace { +namespace not_anonymous { - template 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) ); @@ -62,6 +62,7 @@ namespace { SENF_LOG_DEF_AREA( myArea ); } +using namespace not_anonymous; BOOST_AUTO_UNIT_TEST(logger) { @@ -81,15 +82,19 @@ 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(), @@ -99,7 +104,7 @@ BOOST_AUTO_UNIT_TEST(streamRegistry) 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(), diff --git a/Utils/Logger/Mainpage.dox b/Utils/Logger/Mainpage.dox index 9bd6118..f30c1fb 100644 --- a/Utils/Logger/Mainpage.dox +++ b/Utils/Logger/Mainpage.dox @@ -29,96 +29,69 @@ 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 Boost.Preprocessor 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 in arbitrary order. 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: -
-    g++ ... -DSENF_LOG_CONF="((senf::log::Debug)(_)(DISABLED)) \
-                             ((senf::log::Debug)(foo::FooArea)(VERBOSE))" ...
-    
- 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. */ diff --git a/Utils/Logger/Parameters.hh b/Utils/Logger/Parameters.hh index e811cb1..bdc43b2 100644 --- a/Utils/Logger/Parameters.hh +++ b/Utils/Logger/Parameters.hh @@ -27,12 +27,16 @@ #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 */ @@ -48,29 +52,8 @@ */ #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 \ - 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" diff --git a/Utils/Logger/Parameters.ih b/Utils/Logger/Parameters.ih index 882af7c..d323241 100644 --- a/Utils/Logger/Parameters.ih +++ b/Utils/Logger/Parameters.ih @@ -33,11 +33,7 @@ #include #include #include -#include "Defaults.hh" #include "../mpl.hh" -#include "Stream.hh" -#include "Area.hh" -#include "Levels.hh" #include "Config.hh" ///////////////////////////////ih.p//////////////////////////////////////// @@ -46,19 +42,26 @@ # 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 struct Parameters_ {}; +#ifndef DOXYGEN + senf::mpl::rv<1> Parameters_select_(StreamBase *); template struct Parameters_ : public Base @@ -85,10 +88,25 @@ namespace detail { : public Param::template apply::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 + senf::mpl::rv<6> Parameters_select_( + T *, + typename boost::disable_if< boost::is_convertible >::type * = 0, + typename boost::disable_if< boost::is_convertible >::type * = 0, + typename boost::disable_if< boost::is_convertible >::type * = 0, + typename boost::disable_if< boost::is_convertible >::type * = 0); + template + struct Parameters_ : public Base + { typedef typename Param::SENFLogArea area; }; + +#endif + + /// Internal: Log message parameter collection template struct Parameters : public Base { - static bool const compile_enabled = senf::log::Enabled< typename Base::stream, typename Base::area, @@ -98,10 +116,13 @@ namespace detail { 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 struct apply { typedef Parameters_< @@ -113,13 +134,17 @@ namespace detail { }}} +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( \ diff --git a/Utils/Logger/Stream.cc b/Utils/Logger/StreamRegistry.cc similarity index 91% rename from Utils/Logger/Stream.cc rename to Utils/Logger/StreamRegistry.cc index e3c37e0..6a36591 100644 --- a/Utils/Logger/Stream.cc +++ b/Utils/Logger/StreamRegistry.cc @@ -21,10 +21,10 @@ // 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 diff --git a/Utils/Logger/Stream.cci b/Utils/Logger/StreamRegistry.cci similarity index 96% rename from Utils/Logger/Stream.cci rename to Utils/Logger/StreamRegistry.cci index f106291..5bb5b74 100644 --- a/Utils/Logger/Stream.cci +++ b/Utils/Logger/StreamRegistry.cci @@ -21,9 +21,9 @@ // 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" diff --git a/Utils/Logger/Stream.hh b/Utils/Logger/StreamRegistry.hh similarity index 56% rename from Utils/Logger/Stream.hh rename to Utils/Logger/StreamRegistry.hh index d30d2ca..6fd6dcd 100644 --- a/Utils/Logger/Stream.hh +++ b/Utils/Logger/StreamRegistry.hh @@ -21,10 +21,10 @@ // 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 @@ -33,39 +33,23 @@ #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 \ - { \ - typedef defaultLevel_ defaultLevel; \ - typedef runtimeLimit_ runtimeLimit; \ - typedef compileLimit_ compileLimit; \ - static std::string name() { return instance().v_name(); } \ - private: \ - stream() { init(); } \ - friend class senf::singleton; \ - } - 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 { @@ -80,6 +64,12 @@ namespace log { public: typedef boost::transform_iterator iterator; +# ifdef DOXYGEN + // Hmm ... doxygen does not understand using declarations ... + /// Access stream registry singleton instance + static AreaRegistry & instance(); +# endif + using senf::singleton::instance; iterator begin(); @@ -100,9 +90,9 @@ namespace log { }} ///////////////////////////////hh.e////////////////////////////////////////# -#include "Stream.cci" -//#include "Stream.ct" -//#include "Stream.cti" +#include "StreamRegistry.cci" +//#include "StreamRegistry.ct" +//#include "StreamRegistry.cti" #endif diff --git a/Utils/Logger/Stream.ih b/Utils/Logger/StreamRegistry.ih similarity index 92% rename from Utils/Logger/Stream.ih rename to Utils/Logger/StreamRegistry.ih index a2db435..5eae6c2 100644 --- a/Utils/Logger/Stream.ih +++ b/Utils/Logger/StreamRegistry.ih @@ -21,10 +21,10 @@ // 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 @@ -35,6 +35,7 @@ namespace senf { namespace log { namespace detail { + /// Internal: Log stream base class struct StreamBase { StreamBase(); diff --git a/Utils/Logger/Target.hh b/Utils/Logger/Target.hh index 43ae954..6298800 100644 --- a/Utils/Logger/Target.hh +++ b/Utils/Logger/Target.hh @@ -28,8 +28,8 @@ // Custom includes #include "../singleton.hh" -#include "Stream.hh" -#include "Area.hh" +#include "StreamRegistry.hh" +#include "AreaRegistry.hh" //#include "Target.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -37,7 +37,13 @@ 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 diff --git a/doclib/Doxyfile.global b/doclib/Doxyfile.global index f4c8095..cbf545f 100644 --- a/doclib/Doxyfile.global +++ b/doclib/Doxyfile.global @@ -56,7 +56,7 @@ PREDEFINED = \ "SENF_PARSER_VARIANT(name,chooser,types)=senf::Parse_Variant_Direct::parser name() const" \ "SENF_PARSER_PRIVATE_VARIANT(name,chooser,types)=private: senf::Parse_Variant_Direct::parser name() const; public:" \ "SENF_PARSER_VEC_N(name,elt_type,size_type)=senf::Parse_VectorN 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" diff --git a/doclib/senf.css b/doclib/senf.css index 0515e1c..b1a8ab1 100644 --- a/doclib/senf.css +++ b/doclib/senf.css @@ -257,6 +257,26 @@ table.senf th { 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; diff --git a/senf.dict b/senf.dict index 1c6835c..8e2aca2 100644 --- a/senf.dict +++ b/senf.dict @@ -16,6 +16,7 @@ addtogroup aListCollection alloc arg +args async autoThrottling aVectorCollection @@ -50,6 +51,7 @@ DataPacket dd de DebugModules +DefaultArea DefaultBundle defaultInit defgroup @@ -101,6 +103,7 @@ foo FooParser ForwardingRoute fraunhofer +FroblizerArea fuer GlobalScope hangup