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