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