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