Utils/Logger: Completed documentation
[senf.git] / Utils / Logger / Target.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 Target public header */
25
26 #ifndef HH_Target_
27 #define HH_Target_ 1
28
29 // Custom includes
30 #include <set>
31 #include <boost/date_time/posix_time/posix_time.hpp>
32 #include <boost/utility.hpp>
33 #include <boost/type_traits/is_convertible.hpp>
34 #include "../singleton.hh"
35 #include "../mpl.hh"
36 #include "StreamRegistry.hh"
37 #include "AreaRegistry.hh"
38
39 //#include "Target.mpp"
40 ///////////////////////////////hh.p////////////////////////////////////////
41
42 /** \defgroup targets Targets
43
44     Targets receive log messages and write them to some destination: The console, a log file, an SQL
45     DB and so on. Every target is derived from the \ref senf::log::Target base class. This base
46     class provides the target with the necessary routing infrastructure. The different targets only
47     differ in the way, they write the data.
48
49     \see senf::log::Target
50  */
51
52 namespace senf {
53 namespace log {
54
55     class TargetRegistry;
56
57     /** \brief Logging target base class
58         
59         Targets are the final destination of log messages. Every message is eventually routed to one
60         or several targets.
61
62         \section target_routing Routing
63
64         Each target manages a routing table. The message meta-data (stream, area and level) is
65         matched against this table. If an entry matches, the action associated with this entry is
66         taken (either \c ACCEPT or \c REJECT).
67
68         Every target manages it's own routing table. Conceptually, every routing message will be
69         routed to every target where it will then be matched against each targets routing table (the
70         implementation is more efficient and utilizes a routing cache).
71
72         Each routing entry consists of the following parameters
73         \li (mandatory) \e stream. The entry will match only messages directed at that stream
74         \li (optional) \e area. If the area is specified, only messages directed at that area are
75             matched, otherwise any area will be allowed
76         \li (optional) \e level. If the log level is specified, messages will be accepted if their
77             level is at least that value. If the value is not specified, the limit will be taken
78             from the stream's default value.
79
80         Each parameter (stream, area and level) has two representations: A static (compile time
81         constant) representation, which is the representation also used in the log statements, and a
82         dynamic representation, which may be used for manipulating the routing table.
83
84         The static representation is used, when passing routing parameters via template arguments:
85         \code
86         target.route<foo::SomeStream, senf::log::NOTICE>(senf::log::Target::REJECT);
87         target.route<foo::SomeStream>();
88         \endcode
89         The identical routing statements may be expressed using dynamic routing via:
90         \code
91         target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT);
92         target.route("foo::SomeStream");
93         \endcode
94         The static representation has the benefit of being compile-time type checked: Invalid
95         routing parameters will be caught while compiling the code. The dynamic representation is
96         more flexible as it allows to adjust routing from user input (e.g. configuration files).
97
98         The different object representations are:
99         \li The \e streams is statically represented by it's name, which is the name of a class
100             defined with \ref SENF_LOG_DEF_STREAM. The dynamic representation is a string
101             representation of this name.
102         \li The \e area is statically represented by it's name, which again is the name of a class
103             defined with \ref SENF_LOG_DEF_STREAM. The dynamic representation again is a string
104             representation of this class's name. The dynamic representation represents an absent
105             area with the empty string.
106         \li The \e level is statically represented by a level class from \ref
107             loglevels. Dynamically, it is represented by an unsigned integer number, the \c value
108             member of that class.
109
110         \section target_impl Implementing new targets
111
112         To implement a new target type, you need to derive from senf::log::Target and implement the
113         single \c v_write member. This member will be called whenever a message should be output. 
114
115         The target may process in any arbitrary way: reformat, writing it into an SQL DB, whatever
116         can be envisioned. However, there is one important limitation: The \c v_write call must not
117         block. So for more complex scenarios, additional measures must be taken (e.g. writing a log
118         backend daemon which receives the messages via UDP and processes them). Of course, in rare
119         cases messages might be lost but this cannot be avoided.
120
121         \see \ref targets
122
123         \fixme optionally Integrate with Scheduler / ClockService to reduce number of gettimeofday()
124             calls.
125       */
126     class Target : private boost::noncopyable
127     {
128     public:
129         ///////////////////////////////////////////////////////////////////////////
130         // Types
131
132         /** \brief Routing action
133
134             Every routing entry is associated with a routing action. This action is final (for this
135             target. Each target is processed independently).
136          */
137         enum action_t { 
138             ACCEPT /** Output message */
139           , REJECT /** Suppress message output */
140         };
141
142         /** \brief Target routing entry
143
144             A single routing entry matches messages against their \e stream, \e area and \e
145             level. If the entry matches, the given \e action is performed.
146
147             \see senf::log::Target
148          */
149         struct RoutingEntry 
150         {
151             std::string stream() const; ///< Stream to match
152             std::string area() const;   ///< Area to match (empty of unspecified)
153             unsigned level() const;     ///< Level to match (senf::log::NONE::value if unspecified)
154             action_t action() const;    ///< Action to take
155             
156 #           ifdef DOXYGEN
157         private:
158 #           endif
159
160             RoutingEntry();
161             bool operator==(RoutingEntry const & other);
162
163         private:
164             RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area, 
165                          unsigned level, action_t action);
166
167             detail::StreamBase const * stream_;
168             detail::AreaBase const * area_;
169             unsigned level_;
170             action_t action_;
171             
172             friend class Target;
173         };
174
175     private:
176         typedef std::vector<RoutingEntry> RIB;
177
178     public:
179         typedef RIB::const_iterator iterator; ///< Routing table iterator
180
181         ///////////////////////////////////////////////////////////////////////////
182         ///\name Structors and default members
183         ///@{
184
185         Target();
186         virtual ~Target();
187
188         ///@}
189         ///////////////////////////////////////////////////////////////////////////
190         ///\name Routing
191         ///\{
192
193 #       ifdef DOXYGEN
194
195         template <class Stream, class Area, class Level> void route(
196             action_t action = ACCEPT, int index = -1); ///< Add route (static)
197                                         /**< Add a route for the given combination of \a Stream, \a
198                                              Area and \a Level. The \a Stream parameter is mandatory
199                                              while either \a Area or \a Level are optional (the
200                                              template signature is shown simplified here):
201                                              \code
202                                              target.route<SomeStream>();
203                                              target.route<SomeStream, SomeLevel>();
204                                              target.route<SomeStream, SomeArea>();
205                                              target.route<SomeStream, SomeArea, SomeLevel>();
206                                              \endcode
207
208                                              See the class description for information on the \a
209                                              action and \a index parameters 
210
211                                              \param[in] Stream mandatory stream to match
212                                              \param[in] Area optional area to match
213                                              \param[in] Level optional level, matches messages with
214                                                  at least the given level. 
215                                              \param[in] action routing action to take
216                                              \param[in] index position of new route in the routing
217                                                  table */
218
219 #       endif
220
221         void route(std::string const & stream, std::string const & area = "", 
222                    unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
223                                         ///< Add route (dynamic)
224                                         /**< Add a route for the given combination of \a stream, \a
225                                              area and \a level. The \a stream parameter is mandatory
226                                              while either \a area or \a level may be left
227                                              unspecified by setting them to the empty string or
228                                              senf::log::NONE::value respectively.
229
230                                              See the class description for information on the \a
231                                              action and \a index parameters 
232
233                                              \throws InvalidStreamException if the given \a stream
234                                                  is not found in the StreamRegistry
235                                              \throws InvalidAreaException if the given \a area is
236                                                  not found in the AreaRegistry
237
238                                              \param[in] stream mandatory stream to match
239                                              \param[in] area optional area to match
240                                              \param[in] level optional level, matches messages with
241                                                  at least the given level.
242                                              \param[in] action routing action to take
243                                              \param[in] index position of new route in the routing
244                                                  table */
245
246 #       ifdef DOXYGEN
247
248         template <class Stream, class Area, class Level> 
249         void unroute(action_t action = ACCEPT);
250                                         ///< Remove route (static)
251                                         /**< This member removes an arbitrary routing entry. The
252                                              template parameters are the same as for the
253                                              corresponding \ref route() call.
254
255                                              The routing table is searched for a route exactly
256                                              matching the given specification. If such a route is
257                                              found, it will be removed, otherwise the call will be
258                                              ignored
259
260                                              \param[in] Stream mandatory stream to match
261                                              \param[in] Area optional area to match
262                                              \param[in] Level optional level, matches messages with
263                                                  at least the given level. 
264                                              \param[in] action routing action to take */
265
266 #       endif
267
268         void unroute(std::string const & stream, std::string const & area = "", 
269                      unsigned level = NONE::value, action_t action = ACCEPT);
270                                         ///< Remove route (dynamic)
271                                         /**< This member removes an arbitrary routing entry. The \a
272                                              stream parameter is mandatory while either \a area or
273                                              \a level may be left unspecified by setting them to the
274                                              empty string or senf::log::NONE::value respectively.
275
276                                              The routing table is searched for a route exactly
277                                              matching the given specification. If such a route is
278                                              found, it will be removed, otherwise the call will be
279                                              ignored
280
281                                              \param[in] stream mandatory stream to match
282                                              \param[in] area optional area to match
283                                              \param[in] level optional level, matches messages with
284                                                  at least the given level.
285                                              \param[in] action routing action to take */
286         void unroute(int index=-1);     ///< Remove route (indexed)
287                                         /**< This call will remove the route with the given index.
288                                              
289                                              See the class documentation for more information on
290                                              indexing. 
291
292                                              \param[in] index index of routing entry to remove */
293
294 #       ifndef DOXYGEN
295
296         template <class Stream> void route(
297             action_t action = ACCEPT, int index = -1);
298         template <class Stream, class Level> void route(
299             action_t action = ACCEPT, int index = -1,
300             typename boost::enable_if< boost::is_convertible<Level*,
301                                                              detail::LevelBase *> >::type * = 0);
302         template <class Stream, class Area> void route(
303             action_t action = ACCEPT, int index = -1,
304             typename boost::enable_if< boost::is_convertible<Area*,
305                                                              detail::AreaBase *> >::type * = 0);
306         template <class Stream, class AreaClass> void route(
307             action_t action = ACCEPT, int index = -1,
308             typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
309                                                              detail::AreaBase *> >::type * = 0);
310         template <class Stream, class Area, class Level> void route(
311             action_t action = ACCEPT, int index = -1,
312             typename boost::enable_if< boost::is_convertible<Area *,
313                                                              detail::AreaBase *> >::type * = 0);
314         template <class Stream, class AreaClass, class Level> void route(
315             action_t action = ACCEPT, int index = -1,
316             typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
317                                                              detail::AreaBase *> >::type * = 0);
318
319         template <class Stream> void unroute(
320             action_t action = ACCEPT);
321         template <class Stream, class Level> void unroute(
322             action_t action = ACCEPT,
323             typename boost::enable_if< boost::is_convertible<Level*,
324                                                              detail::LevelBase *> >::type * = 0);
325         template <class Stream, class Area> void unroute(
326             action_t action = ACCEPT,
327             typename boost::enable_if< boost::is_convertible<Area*,
328                                                              detail::AreaBase *> >::type * = 0);
329         template <class Stream, class AreaClass> void unroute(
330             action_t action = ACCEPT,
331             typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
332                                                              detail::AreaBase *> >::type * = 0);
333         template <class Stream, class Area, class Level> void unroute(
334             action_t action = ACCEPT,
335             typename boost::enable_if< boost::is_convertible<Area*,
336                                                              detail::AreaBase *> >::type * = 0);
337         template <class Stream, class AreaClass, class Level> void unroute(
338             action_t action = ACCEPT,
339             typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
340                                                              detail::AreaBase *> >::type * = 0);
341
342 #       endif
343
344         ///\}
345
346         /** \brief Exception: Invalid stream */
347         struct InvalidStreamException : public std::exception
348         { virtual char const * what() const throw() 
349                 { return "senf::log::Target::InvalidStreamException"; } };
350         
351         /** \brief Exception: Invalid area */
352         struct InvalidAreaException : public std::exception
353         { virtual char const * what() const throw() 
354                 { return "senf::log::Target::InvalidAreaException"; } };
355
356         iterator begin() const;         ///< Iterator to beginning of routing table
357         iterator end() const;           ///< Iterator past the end of routing table
358         
359     private:
360         void route(detail::StreamBase const * stream, detail::AreaBase const * area, 
361                    unsigned level, action_t action, int index);
362         void unroute(detail::StreamBase const * stream, detail::AreaBase const * area, 
363                      unsigned level, action_t action);
364
365         void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
366
367         void write(boost::posix_time::ptime timestamp, detail::StreamBase const & stream,
368                    detail::AreaBase const & area, unsigned level, std::string const & message);
369
370 #   ifdef DOXYGEN
371     protected:
372 #   endif
373
374         virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream, 
375                              std::string const & area, unsigned level, 
376                              std::string const & message) = 0;
377                                         ///< Called to write out the routing message
378                                         /**< This member must be defined in the derived class to
379                                              somehow format and write the log message. 
380
381                                              Every log message always possesses a complete set of
382                                              meta information (\a stream, \a area and \a level). The
383                                              \a area may be an empty string if the message was
384                                              written from the senf::log::DefaultArea.
385
386                                              \note This member must \e not block since it may be
387                                                  called from any unknown context. This prohibits
388                                                  simple logging over NFS or many other network
389                                                  protocols.
390
391                                              \param[in] timestamp log message timing information
392                                              \param[in] stream message stream
393                                              \param[in] area message area
394                                              \param[in] level message level
395                                              \param[in] message the message string */
396
397 #   ifdef DOXYGEN
398     private:
399 #   endif
400
401         RIB rib_;
402         
403         friend class detail::AreaBase;
404     };
405
406 }}
407
408 ///////////////////////////////hh.e////////////////////////////////////////
409 #include "Target.cci"
410 //#include "Target.ct"
411 #include "Target.cti"
412 #endif
413
414 \f
415 // Local Variables:
416 // mode: c++
417 // fill-column: 100
418 // comment-column: 40
419 // c-file-style: "senf"
420 // indent-tabs-mode: nil
421 // ispell-local-dictionary: "american"
422 // compile-command: "scons -u test"
423 // End: