removed some useless spaces; not very important, I know :)
[senf.git] / Utils / Logger / Target.hh
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
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     namespace detail { 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     class Target : private boost::noncopyable
124     {
125     public:
126         ///////////////////////////////////////////////////////////////////////////
127         // Types
128
129         /** \brief Routing action
130
131             Every routing entry is associated with a routing action. This action is final (for this
132             target. Each target is processed independently).
133          */
134         enum action_t { 
135             ACCEPT /** Output message */
136           , REJECT /** Suppress message output */
137         };
138
139         /** \brief Target routing entry
140
141             A single routing entry matches messages against their \e stream, \e area and \e
142             level. If the entry matches, the given \e action is performed.
143
144             \see senf::log::Target
145          */
146         struct RoutingEntry 
147         {
148             std::string stream() const; ///< Stream to match
149             std::string area() const;   ///< Area to match (empty of unspecified)
150             unsigned level() const;     ///< Level to match (senf::log::NONE::value if unspecified)
151             action_t action() const;    ///< Action to take
152             
153 #           ifdef DOXYGEN
154         private:
155 #           endif
156
157             RoutingEntry();
158             bool operator==(RoutingEntry const & other);
159
160         private:
161             RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area, 
162                          unsigned level, action_t action);
163
164             detail::StreamBase const * stream_;
165             detail::AreaBase const * area_;
166             unsigned level_;
167             action_t action_;
168             
169             friend class Target;
170         };
171
172     private:
173         typedef std::vector<RoutingEntry> RIB;
174
175     public:
176         typedef RIB::const_iterator iterator; ///< Routing table iterator
177
178         ///////////////////////////////////////////////////////////////////////////
179         ///\name Structors and default members
180         ///@{
181
182         Target();
183         virtual ~Target();
184
185         ///@}
186         ///////////////////////////////////////////////////////////////////////////
187         ///\name Routing
188         ///\{
189
190 #       ifdef DOXYGEN
191
192         template <class Stream, class Area, class Level> void route(
193             action_t action = ACCEPT, int index = -1); ///< Add route (static)
194                                         /**< Add a route for the given combination of \a Stream, \a
195                                              Area and \a Level. The \a Stream parameter is mandatory
196                                              while either \a Area or \a Level are optional (the
197                                              template signature is shown simplified here):
198                                              \code
199                                              target.route<SomeStream>();
200                                              target.route<SomeStream, SomeLevel>();
201                                              target.route<SomeStream, SomeArea>();
202                                              target.route<SomeStream, SomeArea, SomeLevel>();
203                                              \endcode
204
205                                              See the class description for information on the \a
206                                              action and \a index parameters 
207
208                                              \param[in] Stream mandatory stream to match
209                                              \param[in] Area optional area to match
210                                              \param[in] Level optional level, matches messages with
211                                                  at least the given level. 
212                                              \param[in] action routing action to take
213                                              \param[in] index position of new route in the routing
214                                                  table */
215
216 #       endif
217
218         void route(std::string const & stream, std::string const & area = "", 
219                    unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
220                                         ///< Add route (dynamic)
221                                         /**< Add a route for the given combination of \a stream, \a
222                                              area and \a level. The \a stream parameter is mandatory
223                                              while either \a area or \a level may be left
224                                              unspecified by setting them to the empty string or
225                                              senf::log::NONE::value respectively.
226
227                                              See the class description for information on the \a
228                                              action and \a index parameters 
229
230                                              \throws InvalidStreamException if the given \a stream
231                                                  is not found in the StreamRegistry
232                                              \throws InvalidAreaException if the given \a area is
233                                                  not found in the AreaRegistry
234
235                                              \param[in] stream mandatory stream to match
236                                              \param[in] area optional area to match
237                                              \param[in] level optional level, matches messages with
238                                                  at least the given level.
239                                              \param[in] action routing action to take
240                                              \param[in] index position of new route in the routing
241                                                  table */
242
243 #       ifdef DOXYGEN
244
245         template <class Stream, class Area, class Level> 
246         void unroute(action_t action = ACCEPT);
247                                         ///< Remove route (static)
248                                         /**< This member removes an arbitrary routing entry. The
249                                              template parameters are the same as for the
250                                              corresponding \ref route() call.
251
252                                              The routing table is searched for a route exactly
253                                              matching the given specification. If such a route is
254                                              found, it will be removed, otherwise the call will be
255                                              ignored
256
257                                              \param[in] Stream mandatory stream to match
258                                              \param[in] Area optional area to match
259                                              \param[in] Level optional level, matches messages with
260                                                  at least the given level. 
261                                              \param[in] action routing action to take */
262
263 #       endif
264
265         void unroute(std::string const & stream, std::string const & area = "", 
266                      unsigned level = NONE::value, action_t action = ACCEPT);
267                                         ///< Remove route (dynamic)
268                                         /**< This member removes an arbitrary routing entry. The \a
269                                              stream parameter is mandatory while either \a area or
270                                              \a level may be left unspecified by setting them to the
271                                              empty string or senf::log::NONE::value respectively.
272
273                                              The routing table is searched for a route exactly
274                                              matching the given specification. If such a route is
275                                              found, it will be removed, otherwise the call will be
276                                              ignored
277
278                                              \param[in] stream mandatory stream to match
279                                              \param[in] area optional area to match
280                                              \param[in] level optional level, matches messages with
281                                                  at least the given level.
282                                              \param[in] action routing action to take */
283         void unroute(int index=-1);     ///< Remove route (indexed)
284                                         /**< This call will remove the route with the given index.
285                                              
286                                              See the class documentation for more information on
287                                              indexing. 
288
289                                              \param[in] index index of routing entry to remove */
290
291 #       ifndef DOXYGEN
292
293         template <class Stream> void route(
294             action_t action = ACCEPT, int index = -1);
295         template <class Stream, class Level> void route(
296             action_t action = ACCEPT, int index = -1,
297             typename boost::enable_if< boost::is_convertible<Level*,
298                                                              detail::LevelBase *> >::type * = 0);
299         template <class Stream, class Area> void route(
300             action_t action = ACCEPT, int index = -1,
301             typename boost::enable_if< boost::is_convertible<Area*,
302                                                              detail::AreaBase *> >::type * = 0);
303         template <class Stream, class AreaClass> void route(
304             action_t action = ACCEPT, int index = -1,
305             typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
306                                                              detail::AreaBase *> >::type * = 0);
307         template <class Stream, class Area, class Level> void route(
308             action_t action = ACCEPT, int index = -1,
309             typename boost::enable_if< boost::is_convertible<Area *,
310                                                              detail::AreaBase *> >::type * = 0);
311         template <class Stream, class AreaClass, class Level> void route(
312             action_t action = ACCEPT, int index = -1,
313             typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
314                                                              detail::AreaBase *> >::type * = 0);
315
316         template <class Stream> void unroute(
317             action_t action = ACCEPT);
318         template <class Stream, class Level> void unroute(
319             action_t action = ACCEPT,
320             typename boost::enable_if< boost::is_convertible<Level*,
321                                                              detail::LevelBase *> >::type * = 0);
322         template <class Stream, class Area> void unroute(
323             action_t action = ACCEPT,
324             typename boost::enable_if< boost::is_convertible<Area*,
325                                                              detail::AreaBase *> >::type * = 0);
326         template <class Stream, class AreaClass> void unroute(
327             action_t action = ACCEPT,
328             typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
329                                                              detail::AreaBase *> >::type * = 0);
330         template <class Stream, class Area, class Level> void unroute(
331             action_t action = ACCEPT,
332             typename boost::enable_if< boost::is_convertible<Area*,
333                                                              detail::AreaBase *> >::type * = 0);
334         template <class Stream, class AreaClass, class Level> void unroute(
335             action_t action = ACCEPT,
336             typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
337                                                              detail::AreaBase *> >::type * = 0);
338
339 #       endif
340
341         ///\}
342
343         /** \brief Exception: Invalid stream */
344         struct InvalidStreamException : public std::exception
345         { virtual char const * what() const throw() 
346                 { return "senf::log::Target::InvalidStreamException"; } };
347         
348         /** \brief Exception: Invalid area */
349         struct InvalidAreaException : public std::exception
350         { virtual char const * what() const throw() 
351                 { return "senf::log::Target::InvalidAreaException"; } };
352
353         iterator begin() const;         ///< Iterator to beginning of routing table
354         iterator end() const;           ///< Iterator past the end of routing table
355         
356     private:
357         void route(detail::StreamBase const * stream, detail::AreaBase const * area, 
358                    unsigned level, action_t action, int index);
359         void unroute(detail::StreamBase const * stream, detail::AreaBase const * area, 
360                      unsigned level, action_t action);
361
362         void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
363
364         void write(boost::posix_time::ptime timestamp, detail::StreamBase const & stream,
365                    detail::AreaBase const & area, unsigned level, std::string const & message);
366
367 #   ifdef DOXYGEN
368     protected:
369 #   endif
370
371         virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream, 
372                              std::string const & area, unsigned level, 
373                              std::string const & message) = 0;
374                                         ///< Called to write out the routing message
375                                         /**< This member must be defined in the derived class to
376                                              somehow format and write the log message. 
377
378                                              Every log message always possesses a complete set of
379                                              meta information (\a stream, \a area and \a level).
380
381                                              \note This member must \e not block since it may be
382                                                  called from any unknown context. This prohibits
383                                                  simple logging over NFS or many other network
384                                                  protocols.
385
386                                              \param[in] timestamp %log message timing information
387                                              \param[in] stream message stream
388                                              \param[in] area message area
389                                              \param[in] level message level
390                                              \param[in] message the message string */
391
392 #   ifdef DOXYGEN
393     private:
394 #   endif
395
396         RIB rib_;
397         
398         friend class detail::AreaBase;
399         friend class detail::TargetRegistry;
400     };
401
402     /** \brief Log message time source abstract base class
403
404         Instances derived from TimeSource provide the Logging library with the current date/time
405         value. The \c operator() member must be implemented to return the current universal time
406         (UTC).
407
408         A new TimeSource may be installed using \ref senf::log::timeSource().
409
410         \ingroup config
411      */
412     struct TimeSource
413     {
414         virtual ~TimeSource();
415         virtual boost::posix_time::ptime operator()() const = 0;
416     };
417
418     /** \brief Default %log message time source
419
420         This time source is installed by default and uses gettimeofday() (via the Boost.DateTime
421         library) to get the current universal time.
422         
423         \ingroup config
424      */
425     struct SystemTimeSource : public TimeSource
426     {
427         virtual boost::posix_time::ptime operator()() const;
428     };
429
430     /** \brief Change log message time source
431
432         Set the log message time source to \a source. The logging library will take ownership of \e
433         source and will take care to free it, if necessary.
434
435         Since the time source class will in almost all cases be default constructible, see the
436         template overload for a simpler interface.
437
438         \ingroup config
439      */
440     void timeSource(std::auto_ptr<TimeSource> source);
441
442     /** \brief Change log message time source
443
444         Set the log message time source to (an instance of) \a Source.  \a Source must be default
445         constructible, otherwise use the non-template senf::log::timeSource() overload.
446
447         \ingroup config
448      */
449     template <class Source> void timeSource();
450
451 }}
452
453 ///////////////////////////////hh.e////////////////////////////////////////
454 #include "Target.cci"
455 //#include "Target.ct"
456 #include "Target.cti"
457 #endif
458
459 \f
460 // Local Variables:
461 // mode: c++
462 // fill-column: 100
463 // comment-column: 40
464 // c-file-style: "senf"
465 // indent-tabs-mode: nil
466 // ispell-local-dictionary: "american"
467 // compile-command: "scons -u test"
468 // End: