switch to new MPL based Fraunhofer FOKUS Public License
[senf.git] / senf / Utils / Logger / Target.hh
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief Target public header */
30
31 #ifndef HH_SENF_Utils_Logger_Target_
32 #define HH_SENF_Utils_Logger_Target_ 1
33
34 // Custom includes
35 #include <vector>
36 #include <boost/utility.hpp>
37 #include <senf/Utils/Exception.hh>
38 #include <senf/Utils/Console/LazyDirectory.hh>
39 #include "TimeSource.hh"
40 #include "Levels.hh"
41
42 //#include "Target.mpp"
43 //-/////////////////////////////////////////////////////////////////////////////////////////////////
44
45 /** \defgroup targets Targets
46
47     Targets receive log messages and write them to some destination: The console, a log file, an SQL
48     DB and so on. Every target is derived from the \ref senf::log::Target base class. This base
49     class provides the target with the necessary routing infrastructure. The different targets only
50     differ in the way, they write the data.
51
52     \see senf::log::Target
53  */
54
55 namespace senf {
56 namespace log {
57
58     namespace detail { class TargetRegistry; }
59     namespace detail { class AreaBase; }
60     namespace detail { struct LogParameters; }
61     namespace detail { struct StreamBase; }
62
63     /** \brief Logging target base class
64
65         Targets are the final destination of %log messages. Every message is eventually routed to
66         one or several targets.
67
68         \section target_routing Routing
69
70         Each target manages a routing table. The message meta-data (stream, area and level) is
71         matched against this table. If an entry matches, the action associated with this entry is
72         taken (either \c ACCEPT or \c REJECT).
73
74         Every target manages it's own routing table. Conceptually, every message will be routed to
75         every target where it will then be matched against each targets routing table (the
76         implementation is more efficient and utilizes a routing cache).
77
78         Each routing entry consists of the following parameters
79         \li (optional) \e stream. If specified, the entry will match only messages directed at that
80             stream
81         \li (optional) \e area. If the area is specified, only messages directed at that area are
82             matched, otherwise any area will be allowed
83         \li (optional) \e level. If the %log level is specified, messages will be accepted if their
84             level is at least that value. If the value is not specified, the limit will be taken
85             from the stream's default value.
86
87         Each parameter (stream, area and level) has two representations: A static (compile time
88         constant) representation, which is the representation also used in the %log statements, and a
89         dynamic (runtime) representation.
90
91         The static representation is used, when passing routing parameters via template arguments:
92         \code
93         target.route<foo::SomeStream, senf::log::NOTICE>(senf::log::Target::REJECT);
94         target.route<foo::SomeStream>();
95         target.route();
96         \endcode
97         The identical routing statements may be expressed using dynamic routing via:
98         \code
99         target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT);
100         target.route("foo::SomeStream");
101         target.route();
102         \endcode
103         The static representation has the benefit of being compile-time type checked: Invalid
104         routing parameters will be caught while compiling the code. The dynamic representation is
105         more flexible as it allows to adjust routing from user input (e.g. configuration files).
106
107         The different object representations are:
108         \li The \e streams is statically represented by it's name, which is the name of a class
109             defined with \ref SENF_LOG_DEFINE_STREAM. The dynamic representation is a string
110             representation of this name.
111         \li The \e area is statically represented by it's name, which again is the name of a class
112             defined with \ref SENF_LOG_DEFINE_STREAM. The dynamic representation again is a string
113             representation of this class's name. The dynamic representation represents an absent
114             area with the empty string.
115         \li The \e level is statically represented by a level class from \ref
116             loglevels. Dynamically, it is represented by an unsigned integer number, the \c value
117             member of that class.
118
119         \subsection target_routing_processing Ordering routing entries and route processing
120
121         The routing table is processed from first route to last route, the first matching entry
122         determines the fate of a log messages. Therefore, the ordering of routing entries is
123         important.
124
125         If no position is explicitly specified, new routing entries are added to the end of the
126         routing table. All routing statements however take an index as optional argument to
127         explicitly specify the position of the new routing entry.
128
129         The index value starts from 0 for the first route. The value gives the position the new
130         routing entry will have after it has been added. An index of 0 will thus insert the new
131         routing entry at the beginning of the table. Negative values count from the back, -1 being
132         the last entry.
133
134         \section target_impl Implementing new targets
135
136         To implement a new target type, you need to derive from senf::log::Target and implement the
137         single \c v_write member. This member will be called whenever a message should be output.
138
139         The target may process the message in any arbitrary way: reformat it, write it into an SQL
140         DB, whatever can be envisioned. However, there is one important limitation: The \c v_write
141         call must \e not block. So for more complex scenarios, additional measures must be taken
142         (e.g. writing a %log backend daemon which receives the messages via UDP and processes
143         them). Of course, in rare cases messages might be lost but this cannot be avoided.
144
145         \see \ref targets
146       */
147     class Target : private boost::noncopyable
148     {
149     public:
150         //-////////////////////////////////////////////////////////////////////////
151         // Types
152
153         /** \brief Routing action
154
155             Every routing entry is associated with a routing action. This action is final (for this
156             target. Each target is processed independently).
157          */
158         enum action_t {
159             ACCEPT /** Output message */
160           , REJECT /** Suppress message output */
161         };
162
163         /** \brief Target routing entry
164
165             A single routing entry matches messages against their \e stream, \e area and \e
166             level. If the entry matches, the given \e action is performed.
167
168             \see senf::log::Target
169          */
170         struct RoutingEntry
171         {
172             std::string stream() const; ///< Stream to match
173             std::string area() const;   ///< Area to match (empty of unspecified)
174             unsigned level() const;     ///< Level to match (senf::log::NONE::value if unspecified)
175             action_t action() const;    ///< Action to take
176
177 #           ifdef DOXYGEN
178         private:
179 #           endif
180
181             RoutingEntry();
182             bool operator==(RoutingEntry const & other) const;
183
184         private:
185             RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area,
186                          unsigned level, action_t action);
187
188             detail::StreamBase const * stream_;
189             detail::AreaBase const * area_;
190             unsigned level_;
191             action_t action_;
192
193             friend class Target;
194         };
195
196     private:
197         typedef std::vector<RoutingEntry> RIB;
198
199     public:
200         typedef RIB::const_iterator iterator; ///< Routing table iterator
201         typedef RIB::size_type size_type;
202
203         //-////////////////////////////////////////////////////////////////////////
204         ///\name Structors and default members
205         //\{
206
207         explicit Target(std::string const & name);
208         virtual ~Target();
209
210         //\}
211         //-////////////////////////////////////////////////////////////////////////
212         ///\name Routing
213         //\{
214
215 #       ifdef DOXYGEN
216
217         template <class Stream, class Area, class Level> void route(
218             action_t action = ACCEPT, int index = -1); ///< Add route (static)
219                                         /**< Add a route for the given combination of \a Stream, \a
220                                              Area and \a Level. All parameters (\a Stream, \a Area
221                                              and \a Level) are optional (the template signature is
222                                              shown simplified here). So possible commands are:
223                                              \code
224                                              target.route();
225                                              target.route<SomeStream>();
226                                              target.route<SomeArea>();
227                                              target.route<SomeLevel>();
228                                              target.route<SomeStream, SomeArea>();
229                                              target.route<SomeStream, SomeLevel>();
230                                              target.route<SomeArea, SomeLevel>();
231                                              target.route<SomeStream, SomeArea, SomeLevel>();
232                                              \endcode
233
234                                              See the class description for information on the \a
235                                              action and \a index parameters
236
237                                              \tparam Stream stream to match
238                                              \tparam Area area to match
239                                              \tparam Level level, matches messages with
240                                                  at least 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 #       endif
246
247         void route(std::string const & stream, std::string const & area = "",
248                    unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
249                                         ///< Add route (dynamic)
250                                         /**< Add a route for the given combination of \a stream, \a
251                                              area and \a level. All parameters (\a Stream, \a Area
252                                              and \a Level) are optional and may be omitted by
253                                              setting them to the empty string or the
254                                              senf::log::NONE::value respectively.
255
256                                              See the class description for information on the \a
257                                              action and \a index parameters
258
259                                              \throws InvalidStreamException if the given \a stream
260                                                  is not found in the StreamRegistry
261                                              \throws InvalidAreaException if the given \a area is
262                                                  not found in the AreaRegistry
263
264                                              \param[in] stream stream to match
265                                              \param[in] area area to match
266                                              \param[in] level level, matches messages with at least
267                                                  the given level.
268                                              \param[in] action routing action to take
269                                              \param[in] index position of new route in the routing
270                                                  table */
271
272 #       ifdef DOXYGEN
273
274         template <class Stream, class Area, class Level>
275         void unroute(action_t action = ACCEPT);
276                                         ///< Remove route (static)
277                                         /**< This member removes an arbitrary routing entry. The
278                                              template parameters are the same as for the
279                                              corresponding \ref route() call.
280
281                                              The routing table is searched for a route exactly
282                                              matching the given specification. If such a route is
283                                              found, it will be removed, otherwise the call will be
284                                              ignored
285
286                                              \tparam Stream stream to match
287                                              \tparam Area area to match
288                                              \tparam Level level, matches messages with
289                                                  at least the given level.
290                                              \param[in] action routing action to take */
291
292 #       endif
293
294         void unroute(std::string const & stream, std::string const & area = "",
295                      unsigned level = NONE::value, action_t action = ACCEPT);
296                                         ///< Remove route (dynamic)
297                                         /**< This member removes an arbitrary routing entry. The \a
298                                              stream parameter is mandatory while either \a area or
299                                              \a level may be left unspecified by setting them to the
300                                              empty string or senf::log::NONE::value respectively.
301
302                                              The routing table is searched for a route exactly
303                                              matching the given specification. If such a route is
304                                              found, it will be removed, otherwise the call will be
305                                              ignored
306
307                                              \param[in] stream stream to match
308                                              \param[in] area area to match
309                                              \param[in] level level, matches messages with at least
310                                                  the given level.
311                                              \param[in] action routing action to take */
312         void unroute(int index=-1);     ///< Remove route (indexed)
313                                         /**< This call will remove the route with the given index.
314
315                                              See the class documentation for more information on
316                                              indexing.
317
318                                              \param[in] index index of routing entry to remove */
319
320 #       ifndef DOXYGEN
321
322         void route(action_t action = ACCEPT, int index = -1);
323         template <class A1>
324         void route(action_t action = ACCEPT, int index = -1);
325         template <class A1, class A2>
326         void route(action_t action = ACCEPT, int index = -1);
327         template <class A1, class A2, class A3>
328         void route(action_t action = ACCEPT, int index = -1);
329
330         void unroute(action_t action = ACCEPT);
331         template <class A1>
332         void unroute(action_t action = ACCEPT);
333         template <class A1, class A2>
334         void unroute(action_t action = ACCEPT);
335         template <class A1, class A2, class A3>
336         void unroute(action_t action = ACCEPT);
337
338 #       endif
339
340         //\}
341
342         /** \brief Exception: Invalid stream */
343         struct InvalidStreamException : public senf::Exception
344         { InvalidStreamException()
345               : senf::Exception("senf::log::Target::InvalidStreamException") {} };
346
347         /** \brief Exception: Invalid area */
348         struct InvalidAreaException : public senf::Exception
349         { InvalidAreaException()
350               : senf::Exception("senf::log::Target::InvalidAreaException") {} };
351
352         iterator begin() const;         ///< Iterator to beginning of routing table
353         iterator end() const;           ///< Iterator past the end of routing table
354
355         RoutingEntry const & operator[](size_type i) const; ///< Access routing entry
356
357         size_type size() const;         ///< Number of routing table entries
358         bool empty() const;             ///< \c true, if routing table empty, \c false otherwise
359
360         void flush();                   ///< Clear routing table
361
362         senf::console::ScopedDirectory<> & consoleDir(); ///< Get console/config directory
363
364     private:
365         void route(detail::StreamBase const * stream, detail::AreaBase const * area,
366                    unsigned level, action_t action, int index);
367         void unroute(detail::StreamBase const * stream, detail::AreaBase const * area,
368                      unsigned level, action_t action);
369
370         void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
371
372         void write(time_type timestamp, detail::StreamBase const & stream,
373                    detail::AreaBase const & area, unsigned level, std::string const & message);
374
375         void consoleList(std::ostream & os);
376         void consoleRoute(int index, detail::LogParameters const & pm, action_t action);
377         void consoleUnroute(detail::LogParameters const & pm, action_t action);
378
379 #   ifdef DOXYGEN
380     protected:
381 #   endif
382
383         virtual void v_write(time_type timestamp, std::string const & stream,
384                              std::string const & area, unsigned level,
385                              std::string const & message) = 0;
386                                         ///< Called to write out the routing message
387                                         /**< This member must be defined in the derived class to
388                                              somehow format and write the %log message.
389
390                                              Every %log message always possesses a complete set of
391                                              meta information (\a stream, \a area and \a level).
392
393                                              \note This member must \e not block since it may be
394                                                  called from any unknown context. This prohibits
395                                                  simple logging over NFS or many other network
396                                                  protocols.
397
398                                              \param[in] timestamp %log message timing information
399                                              \param[in] stream message stream
400                                              \param[in] area message area
401                                              \param[in] level message level
402                                              \param[in] message the message string */
403
404 #   ifdef DOXYGEN
405     private:
406 #   endif
407
408         RIB rib_;
409
410         console::LazyDirectory consoleDir_;
411
412         friend class detail::AreaBase;
413         friend class detail::TargetRegistry;
414     };
415
416     /** \brief Write route action
417         \related Target
418      */
419     std::ostream & operator<<(std::ostream & os, Target::action_t const & action);
420
421 }}
422
423 //-/////////////////////////////////////////////////////////////////////////////////////////////////
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: