9065ef4c4075a511344665c906ab4478700702f4
[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) const;
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         typedef RIB::size_type size_type;
183
184         ///////////////////////////////////////////////////////////////////////////
185         ///\name Structors and default members
186         ///@{
187
188         Target();
189         virtual ~Target();
190
191         ///@}
192         ///////////////////////////////////////////////////////////////////////////
193         ///\name Routing
194         ///\{
195
196 #       ifdef DOXYGEN
197
198         template <class Stream, class Area, class Level> void route(
199             action_t action = ACCEPT, int index = -1); ///< Add route (static)
200                                         /**< Add a route for the given combination of \a Stream, \a
201                                              Area and \a Level. All parameters (\a Stream, \a Area
202                                              and \a Level) are optional (the template signature is
203                                              shown simplified here). So possible commands are:
204                                              \code
205                                              target.route();
206                                              target.route<SomeStream>();
207                                              target.route<SomeArea>();
208                                              target.route<SomeLevel>();
209                                              target.route<SomeStream, SomeArea>();
210                                              target.route<SomeStream, SomeLevel>();
211                                              target.route<SomeArea, SomeLevel>();
212                                              target.route<SomeStream, SomeArea, SomeLevel>();
213                                              \endcode
214
215                                              See the class description for information on the \a
216                                              action and \a index parameters
217
218                                              \tparam Stream stream to match
219                                              \tparam Area area to match
220                                              \tparam Level level, matches messages with
221                                                  at least the given level.
222                                              \param[in] action routing action to take
223                                              \param[in] index position of new route in the routing
224                                                  table */
225
226 #       endif
227
228         void route(std::string const & stream, std::string const & area = "",
229                    unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
230                                         ///< Add route (dynamic)
231                                         /**< Add a route for the given combination of \a stream, \a
232                                              area and \a level. All parameters (\a Stream, \a Area
233                                              and \a Level) are optional and may be omitted by
234                                              setting them to the empty string or the
235                                              senf::log::NONE::value respectively.
236
237                                              See the class description for information on the \a
238                                              action and \a index parameters
239
240                                              \throws InvalidStreamException if the given \a stream
241                                                  is not found in the StreamRegistry
242                                              \throws InvalidAreaException if the given \a area is
243                                                  not found in the AreaRegistry
244
245                                              \param[in] stream stream to match
246                                              \param[in] area area to match
247                                              \param[in] level level, matches messages with at least
248                                                  the given level.
249                                              \param[in] action routing action to take
250                                              \param[in] index position of new route in the routing
251                                                  table */
252
253 #       ifdef DOXYGEN
254
255         template <class Stream, class Area, class Level>
256         void unroute(action_t action = ACCEPT);
257                                         ///< Remove route (static)
258                                         /**< This member removes an arbitrary routing entry. The
259                                              template parameters are the same as for the
260                                              corresponding \ref route() call.
261
262                                              The routing table is searched for a route exactly
263                                              matching the given specification. If such a route is
264                                              found, it will be removed, otherwise the call will be
265                                              ignored
266
267                                              \tparam Stream stream to match
268                                              \tparam Area area to match
269                                              \tparam Level level, matches messages with
270                                                  at least the given level.
271                                              \param[in] action routing action to take */
272
273 #       endif
274
275         void unroute(std::string const & stream, std::string const & area = "",
276                      unsigned level = NONE::value, action_t action = ACCEPT);
277                                         ///< Remove route (dynamic)
278                                         /**< This member removes an arbitrary routing entry. The \a
279                                              stream parameter is mandatory while either \a area or
280                                              \a level may be left unspecified by setting them to the
281                                              empty string or senf::log::NONE::value respectively.
282
283                                              The routing table is searched for a route exactly
284                                              matching the given specification. If such a route is
285                                              found, it will be removed, otherwise the call will be
286                                              ignored
287
288                                              \param[in] stream stream to match
289                                              \param[in] area area to match
290                                              \param[in] level level, matches messages with at least
291                                                  the given level.
292                                              \param[in] action routing action to take */
293         void unroute(int index=-1);     ///< Remove route (indexed)
294                                         /**< This call will remove the route with the given index.
295
296                                              See the class documentation for more information on
297                                              indexing.
298
299                                              \param[in] index index of routing entry to remove */
300
301 #       ifndef DOXYGEN
302
303         void route(action_t action = ACCEPT, int index = -1);
304         template <class A1>
305         void route(action_t action = ACCEPT, int index = -1);
306         template <class A1, class A2>
307         void route(action_t action = ACCEPT, int index = -1);
308         template <class A1, class A2, class A3>
309         void route(action_t action = ACCEPT, int index = -1);
310
311         void unroute(action_t action = ACCEPT);
312         template <class A1>
313         void unroute(action_t action = ACCEPT);
314         template <class A1, class A2>
315         void unroute(action_t action = ACCEPT);
316         template <class A1, class A2, class A3>
317         void unroute(action_t action = ACCEPT);
318
319 #       endif
320
321         ///\}
322
323         /** \brief Exception: Invalid stream */
324         struct InvalidStreamException : public senf::Exception
325         { InvalidStreamException()
326               : senf::Exception("senf::log::Target::InvalidStreamException"){} };
327
328         /** \brief Exception: Invalid area */
329         struct InvalidAreaException : public senf::Exception
330         { InvalidAreaException()
331               : senf::Exception("senf::log::Target::InvalidAreaException"){} };
332
333         iterator begin() const;         ///< Iterator to beginning of routing table
334         iterator end() const;           ///< Iterator past the end of routing table
335
336         RoutingEntry const & operator[](size_type i) const; ///< Access routing entry
337
338         size_type size() const;         ///< Number of routing table entries
339         bool empty() const;             ///< \c true, if routing table empty, \c false otherwise
340
341         void flush();                   ///< Clear routing table
342
343     private:
344         void route(detail::StreamBase const * stream, detail::AreaBase const * area,
345                    unsigned level, action_t action, int index);
346         void unroute(detail::StreamBase const * stream, detail::AreaBase const * area,
347                      unsigned level, action_t action);
348
349         void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
350
351         void write(time_type timestamp, detail::StreamBase const & stream,
352                    detail::AreaBase const & area, unsigned level, std::string const & message);
353
354 #   ifdef DOXYGEN
355     protected:
356 #   endif
357
358         virtual void v_write(time_type timestamp, std::string const & stream,
359                              std::string const & area, unsigned level,
360                              std::string const & message) = 0;
361                                         ///< Called to write out the routing message
362                                         /**< This member must be defined in the derived class to
363                                              somehow format and write the %log message.
364
365                                              Every %log message always possesses a complete set of
366                                              meta information (\a stream, \a area and \a level).
367
368                                              \note This member must \e not block since it may be
369                                                  called from any unknown context. This prohibits
370                                                  simple logging over NFS or many other network
371                                                  protocols.
372
373                                              \param[in] timestamp %log message timing information
374                                              \param[in] stream message stream
375                                              \param[in] area message area
376                                              \param[in] level message level
377                                              \param[in] message the message string */
378
379 #   ifdef DOXYGEN
380     private:
381 #   endif
382
383         RIB rib_;
384
385         friend class detail::AreaBase;
386         friend class detail::TargetRegistry;
387     };
388
389     /** \brief Write route action
390         \related Target
391      */
392     std::ostream & operator<<(std::ostream & os, Target::action_t const & action);
393
394 }}
395
396 ///////////////////////////////hh.e////////////////////////////////////////
397 #include "Target.cci"
398 //#include "Target.ct"
399 #include "Target.cti"
400 #endif
401
402
403 // Local Variables:
404 // mode: c++
405 // fill-column: 100
406 // comment-column: 40
407 // c-file-style: "senf"
408 // indent-tabs-mode: nil
409 // ispell-local-dictionary: "american"
410 // compile-command: "scons -u test"
411 // End: