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