3082632ad73b3df8a519ed51079d794befba5805
[senf.git] / Utils / Logger.hh
1 // Copyright (C) 2007 
2 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
3 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
4 //     Stefan Bund <g0dil@berlios.de>
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the
18 // Free Software Foundation, Inc.,
19 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 /** \file
22     \brief Logger public header */
23
24 /** \defgroup logger The SENF Logger
25     
26     The Loggger infrastructure shall implement a highliy flexible compile- and run-time configurable
27     logging infrastructure supporting multiple streams, user defineable log areas and fine grained
28     log levels. Logging can be configured at compile and runtime on any combination of above
29     parameters. The library supports a host of log targets and messages can be routed into multiple
30     targets at the same time. To allow concise usage of the libarary, a utlity to define logging
31     defaults for any scope is provided.
32
33     An important basic concept of the library is, that most of the macros take a variable number of
34     arguments. Since this is not supported in the needed manner by the C++ preprocessor, the
35     arguments are encoded into a <a
36     href="http://www.boost.org/libs/preprocessor/doc/index.html">Boost.Preprocessor</a> like
37     sequence:
38     
39     \code
40     SENF_LOG( (senf::log::Debug)(senf::log::NOTICE)(FroblizerArea)("The log message") );
41     \endcode
42     
43     The last sequence element always is the log message. Before that we have a number of log
44     parameters <it>in arbitrary order</it>. Since giving all the parameters in every log message is
45     to verbose, there are two helpful constructs to reduce the verbosity. Using \ref SENF_LOG_DEFAULTS it
46     is possible to define the default logging parameters to be used within a given scope. Using
47     \ref SENF_LOG_DEF_ALIAS you can define an alias (which is a scoped symbol) as an arbitrary
48     combination of parameters.
49
50     \code
51     SENF_LOG_DEF_STREAM(userLog);
52     
53     class Froblizer 
54     {
55         // Define a new log area
56         SENF_LOG_DEF_AREA(FroblizerArea);
57
58         // Set default log parameters for this scope
59         SENF_LOG_DEFAULTS( (senf::log::Debug) (senf::log::NOTICE) (FroblizerArea) );
60
61         // Define an alias for emergency messages to the sysadmin.
62         // The log area is inherited from the default at the place, where this
63         // alias is used *not* where it is defined
64         SENF_LOG_DEF_ALIAS(LogEmerg, (userLog) (senf::log::CRITICAL));
65
66         void test();
67
68     public:
69         void froblize();
70     };
71
72     void Froblizer::froblize()
73     {
74         SENF_LOG(("This is the Debug stream at level NOTICE in the FroblizeArea"));
75         SENF_LOG((senf::log::WARNING) ("Same stream and area but at warning level"));
76         SENF_LOG((LogEmerg) ("This goes to the userLog at level CRITICAL in the FroblizerArea"));
77     }
78
79     void Froblizer::test()
80     {
81         // Change the default log level for this method. stream and area are taken
82         // from the next scope up
83         SENF_LOG_DEFAULTS((senf::log::DEBUG));
84
85         SENF_LOG(("Log to Debug stream in Froblizer area however at DEBUG level"));
86     }
87     \endcode
88
89     Currently, the library is not implemented in any way. The interface has been defined up to a
90     point and we have dummy implementations of the 'in-code' part ot the interface. This is the
91     part, which is called throughout the code. The configuration API is defined but we don't even
92     have a template implementation. However, this allows starting to use the SENF Logger in newly
93     developed code. Even though this code will unconditionally log everything to \c std::cerr for
94     now and errors in the parameter specification will not be caught (since they are just ignored)
95     the logging should work automatically as advertised as soon as the logger is completely
96     implemented.
97
98     \implementation I would have much preferred a more C++ like implementation. However given the
99     design goals
100     \li Flexible configuration at compile and runtime
101     \li Concise usage and simple interface
102     \li Zero overhead for compile-time disabled log messages
103
104     I did not find any implementation which was not either completely convoluted, unusable or
105     slow. So I turned to a macro based implementation which can provide all the design goals stated
106     above.
107  */
108
109 #ifndef HH_Logger_
110 #define HH_Logger_ 1
111
112 // Custom includes
113 #include <iostream>
114 #include <boost/preprocessor/seq/size.hpp>
115 #include <boost/preprocessor/dec.hpp>
116 #include <boost/preprocessor/seq/elem.hpp>
117
118 //#include "Logger.mpp"
119 ///////////////////////////////hh.p////////////////////////////////////////
120
121 namespace senf {
122
123 #   ifndef _senf_LOG_STREAM
124 #     define _senf_LOG_STREAM std::cerr
125 #   endif
126    
127     /// \addtogroup logger
128     /// @{
129
130     /** \brief Write log message
131         
132         This macro will write it's last argument to the log stream. The last argument must be an
133         expression which will be placed after a streaming \c operator<< (like
134         <it>some-log-sttream</it> \c << <it>last-macro-arg</it>).
135         \code
136         BOOST_LOG((parameters...)("log message " << args << ...));
137         \endcode
138
139         \hideinitializer
140      */
141 #   define SENF_LOG(args)                                                                       \
142         _senf_LOG_STREAM << BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(args)),args)       \
143                          << std::endl;
144
145     /** \brief Enable block based on logging parameters
146         
147         This macro is like SENF_LOG, however instead of writing a simple message, this macro allows
148         to specify a complete block of code to be executed if the log message is enabled.
149         \code
150         BOOST_LOG_BLOCK((parameters...)({
151            // arbitrary code using 'log' for logging
152            log << "log message";
153         }));
154         \endcode
155
156         \hideinitializer
157      */
158 #   define SENF_LOG_BLOCK(args)                                                 \
159         do {                                                                    \
160             std::ostream & log (_senf_LOG_STREAM);                              \
161             BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(args)),args)       \
162             log << std::endl;                                                   \
163         } while (0)
164
165     /** \brief Set scope default log parameters
166
167         Sets the default log parameters for the current scope
168         \code
169         BOOST_LOG_DEFAULTS((parameters...));
170         \endcode
171
172         \hideinitializer
173      */
174 #   define SENF_LOG_DEFAULTS(args)
175
176     /** \brief Define log area
177         
178         Defines a new log area named \a area. The area is defined as a symbol in the current scope.
179
180         \hideinitializer
181      */
182 #   define SENF_LOG_DEF_AREA(area)
183
184     /** \brief Define log stream
185         
186         Defines a new log stream named \a stream. The stream is defined as a symbol in the current
187         scope.
188
189         \hideinitializer
190      */
191 #   define SENF_LOG_DEF_STREAM(stream)
192
193     /** \brief Define log parameter alias
194         
195         Defines a new parameter alias named \a alias as an alias for the parameters in \a args. The
196         alias is defined as a symbol in the current scope.
197
198         \hideinitializer
199      */
200 #   define SENF_LOG_DEF_ALIAS(alias,args)
201
202     /// @}
203
204 }
205
206 ///////////////////////////////hh.e////////////////////////////////////////
207 //#include "Logger.cci"
208 //#include "Logger.ct"
209 //#include "Logger.cti"
210 #endif
211
212 \f
213 // Local Variables:
214 // mode: c++
215 // fill-column: 100
216 // c-file-style: "senf"
217 // ispell-local-dictionary: "american"
218 // End: