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