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