Utils/Logger: Remove dependency on libboost_datetime
[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 <vector>
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 "../Exception.hh"
38 #include "TimeSource.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     namespace detail { class AreaBase; }
58
59     /** \brief Logging target base class
60         
61         Targets are the final destination of %log messages. Every message is eventually routed to one
62         or several targets.
63
64         \section target_routing Routing
65
66         Each target manages a routing table. The message meta-data (stream, area and level) is
67         matched against this table. If an entry matches, the action associated with this entry is
68         taken (either \c ACCEPT or \c REJECT).
69
70         Every target manages it's own routing table. Conceptually, every routing message will be
71         routed to every target where it will then be matched against each targets routing table (the
72         implementation is more efficient and utilizes a routing cache).
73
74         Each routing entry consists of the following parameters
75         \li (optional) \e stream. The entry will match only messages directed at that stream
76         \li (optional) \e area. If the area is specified, only messages directed at that area are
77             matched, otherwise any area will be allowed
78         \li (optional) \e level. If the log level is specified, messages will be accepted if their
79             level is at least that value. If the value is not specified, the limit will be taken
80             from the stream's default value.
81
82         Each parameter (stream, area and level) has two representations: A static (compile time
83         constant) representation, which is the representation also used in the log statements, and a
84         dynamic representation, which may be used for manipulating the routing table.
85
86         The static representation is used, when passing routing parameters via template arguments:
87         \code
88         target.route<foo::SomeStream, senf::log::NOTICE>(senf::log::Target::REJECT);
89         target.route<foo::SomeStream>();
90         \endcode
91         The identical routing statements may be expressed using dynamic routing via:
92         \code
93         target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT);
94         target.route("foo::SomeStream");
95         \endcode
96         The static representation has the benefit of being compile-time type checked: Invalid
97         routing parameters will be caught while compiling the code. The dynamic representation is
98         more flexible as it allows to adjust routing from user input (e.g. configuration files).
99
100         The different object representations are:
101         \li The \e streams is statically represented by it's name, which is the name of a class
102             defined with \ref SENF_LOG_DEFINE_STREAM. The dynamic representation is a string
103             representation of this name.
104         \li The \e area is statically represented by it's name, which again is the name of a class
105             defined with \ref SENF_LOG_DEFINE_STREAM. The dynamic representation again is a string
106             representation of this class's name. The dynamic representation represents an absent
107             area with the empty string.
108         \li The \e level is statically represented by a level class from \ref
109             loglevels. Dynamically, it is represented by an unsigned integer number, the \c value
110             member of that class.
111
112         \section target_impl Implementing new targets
113
114         To implement a new target type, you need to derive from senf::log::Target and implement the
115         single \c v_write member. This member will be called whenever a message should be output. 
116
117         The target may process in any arbitrary way: reformat, writing it into an SQL DB, whatever
118         can be envisioned. However, there is one important limitation: The \c v_write call must not
119         block. So for more complex scenarios, additional measures must be taken (e.g. writing a %log
120         backend daemon which receives the messages via UDP and processes them). Of course, in rare
121         cases messages might be lost but this cannot be avoided.
122
123         \see \ref targets
124       */
125     class Target : private boost::noncopyable
126     {
127     public:
128         ///////////////////////////////////////////////////////////////////////////
129         // Types
130
131         /** \brief Routing action
132
133             Every routing entry is associated with a routing action. This action is final (for this
134             target. Each target is processed independently).
135          */
136         enum action_t { 
137             ACCEPT /** Output message */
138           , REJECT /** Suppress message output */
139         };
140
141         /** \brief Target routing entry
142
143             A single routing entry matches messages against their \e stream, \e area and \e
144             level. If the entry matches, the given \e action is performed.
145
146             \see senf::log::Target
147          */
148         struct RoutingEntry 
149         {
150             std::string stream() const; ///< Stream to match
151             std::string area() const;   ///< Area to match (empty of unspecified)
152             unsigned level() const;     ///< Level to match (senf::log::NONE::value if unspecified)
153             action_t action() const;    ///< Action to take
154             
155 #           ifdef DOXYGEN
156         private:
157 #           endif
158
159             RoutingEntry();
160             bool operator==(RoutingEntry const & other);
161
162         private:
163             RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area, 
164                          unsigned level, action_t action);
165
166             detail::StreamBase const * stream_;
167             detail::AreaBase const * area_;
168             unsigned level_;
169             action_t action_;
170             
171             friend class Target;
172         };
173
174     private:
175         typedef std::vector<RoutingEntry> RIB;
176
177     public:
178         typedef RIB::const_iterator iterator; ///< Routing table iterator
179
180         ///////////////////////////////////////////////////////////////////////////
181         ///\name Structors and default members
182         ///@{
183
184         Target();
185         virtual ~Target();
186
187         ///@}
188         ///////////////////////////////////////////////////////////////////////////
189         ///\name Routing
190         ///\{
191
192 #       ifdef DOXYGEN
193
194         template <class Stream, class Area, class Level> void route(
195             action_t action = ACCEPT, int index = -1); ///< Add route (static)
196                                         /**< Add a route for the given combination of \a Stream, \a
197                                              Area and \a Level. All parameters (\a Stream, \a Area
198                                              and \a Level) are optional (the template signature is
199                                              shown simplified here). Examples:
200                                              \code
201                                              target.route<SomeLevel>();
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                                              \tparam Stream stream to match
212                                              \tparam Area area to match
213                                              \tparam Level 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. All parameters (\a Stream, \a Area
226                                              and \a Level) are optional and may be omitted by
227                                              setting them to the empty string or the
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 stream to match
239                                              \param[in] area area to match
240                                              \param[in] level level, matches messages with at least
241                                                  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                                              \tparam Stream stream to match
261                                              \tparam Area area to match
262                                              \tparam Level 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 stream to match
282                                              \param[in] area area to match
283                                              \param[in] level level, matches messages with at least
284                                                  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 A1>
297         void route(action_t action = ACCEPT, int index = -1);
298         template <class A1, class A2>
299         void route(action_t action = ACCEPT, int index = -1);
300         template <class A1, class A2, class A3>
301         void route(action_t action = ACCEPT, int index = -1);
302
303         template <class A1>
304         void unroute(action_t action = ACCEPT);
305         template <class A1, class A2>
306         void unroute(action_t action = ACCEPT);
307         template <class A1, class A2, class A3>
308         void unroute(action_t action = ACCEPT);
309
310 #       endif
311
312         ///\}
313
314         /** \brief Exception: Invalid stream */
315         struct InvalidStreamException : public senf::Exception
316         { InvalidStreamException() 
317               : senf::Exception("senf::log::Target::InvalidStreamException"){} };
318         
319         /** \brief Exception: Invalid area */
320         struct InvalidAreaException : public senf::Exception
321         { InvalidAreaException() 
322               : senf::Exception("senf::log::Target::InvalidAreaException"){} };
323
324         iterator begin() const;         ///< Iterator to beginning of routing table
325         iterator end() const;           ///< Iterator past the end of routing table
326         
327     private:
328         void route(detail::StreamBase const * stream, detail::AreaBase const * area, 
329                    unsigned level, action_t action, int index);
330         void unroute(detail::StreamBase const * stream, detail::AreaBase const * area, 
331                      unsigned level, action_t action);
332
333         void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
334
335         void write(time_type timestamp, detail::StreamBase const & stream,
336                    detail::AreaBase const & area, unsigned level, std::string const & message);
337
338 #   ifdef DOXYGEN
339     protected:
340 #   endif
341
342         virtual void v_write(time_type timestamp, std::string const & stream, 
343                              std::string const & area, unsigned level, 
344                              std::string const & message) = 0;
345                                         ///< Called to write out the routing message
346                                         /**< This member must be defined in the derived class to
347                                              somehow format and write the %log message. 
348
349                                              Every %log message always possesses a complete set of
350                                              meta information (\a stream, \a area and \a level).
351
352                                              \note This member must \e not block since it may be
353                                                  called from any unknown context. This prohibits
354                                                  simple logging over NFS or many other network
355                                                  protocols.
356
357                                              \param[in] timestamp %log message timing information
358                                              \param[in] stream message stream
359                                              \param[in] area message area
360                                              \param[in] level message level
361                                              \param[in] message the message string */
362
363 #   ifdef DOXYGEN
364     private:
365 #   endif
366
367         RIB rib_;
368         
369         friend class detail::AreaBase;
370         friend class detail::TargetRegistry;
371     };
372
373 }}
374
375 ///////////////////////////////hh.e////////////////////////////////////////
376 #include "Target.cci"
377 //#include "Target.ct"
378 #include "Target.cti"
379 #endif
380
381 \f
382 // Local Variables:
383 // mode: c++
384 // fill-column: 100
385 // comment-column: 40
386 // c-file-style: "senf"
387 // indent-tabs-mode: nil
388 // ispell-local-dictionary: "american"
389 // compile-command: "scons -u test"
390 // End: