4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
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.
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.
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.
24 \brief Target public header */
26 #ifndef HH_SENF_Utils_Logger_Target_
27 #define HH_SENF_Utils_Logger_Target_ 1
32 #include <boost/utility.hpp>
33 #include <boost/type_traits/is_convertible.hpp>
34 #include "../singleton.hh"
36 #include "StreamRegistry.hh"
37 #include "../Exception.hh"
38 #include "TimeSource.hh"
39 #include "../Console/LazyDirectory.hh"
41 //#include "Target.mpp"
42 ///////////////////////////////hh.p////////////////////////////////////////
44 /** \defgroup targets Targets
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.
51 \see senf::log::Target
57 namespace detail { class TargetRegistry; }
58 namespace detail { class AreaBase; }
59 namespace detail { struct LogParameters; }
61 /** \brief Logging target base class
63 Targets are the final destination of %log messages. Every message is eventually routed to
64 one or several targets.
66 \section target_routing Routing
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).
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).
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
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.
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.
89 The static representation is used, when passing routing parameters via template arguments:
91 target.route<foo::SomeStream, senf::log::NOTICE>(senf::log::Target::REJECT);
92 target.route<foo::SomeStream>();
95 The identical routing statements may be expressed using dynamic routing via:
97 target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT);
98 target.route("foo::SomeStream");
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).
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.
117 \section target_impl Implementing new targets
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.
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.
130 class Target : private boost::noncopyable
133 ///////////////////////////////////////////////////////////////////////////
136 /** \brief Routing action
138 Every routing entry is associated with a routing action. This action is final (for this
139 target. Each target is processed independently).
142 ACCEPT /** Output message */
143 , REJECT /** Suppress message output */
146 /** \brief Target routing entry
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.
151 \see senf::log::Target
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
165 bool operator==(RoutingEntry const & other) const;
168 RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area,
169 unsigned level, action_t action);
171 detail::StreamBase const * stream_;
172 detail::AreaBase const * area_;
180 typedef std::vector<RoutingEntry> RIB;
183 typedef RIB::const_iterator iterator; ///< Routing table iterator
184 typedef RIB::size_type size_type;
186 ///////////////////////////////////////////////////////////////////////////
187 ///\name Structors and default members
190 explicit Target(std::string const & name);
194 ///////////////////////////////////////////////////////////////////////////
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:
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>();
217 See the class description for information on the \a
218 action and \a index parameters
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
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.
239 See the class description for information on the \a
240 action and \a index parameters
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
247 \param[in] stream stream to match
248 \param[in] area area to match
249 \param[in] level level, matches messages with at least
251 \param[in] action routing action to take
252 \param[in] index position of new route in the routing
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.
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
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 */
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.
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
290 \param[in] stream stream to match
291 \param[in] area area to match
292 \param[in] level level, matches messages with at least
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.
298 See the class documentation for more information on
301 \param[in] index index of routing entry to remove */
305 void route(action_t action = ACCEPT, int index = -1);
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);
313 void unroute(action_t action = ACCEPT);
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);
325 /** \brief Exception: Invalid stream */
326 struct InvalidStreamException : public senf::Exception
327 { InvalidStreamException()
328 : senf::Exception("senf::log::Target::InvalidStreamException"){} };
330 /** \brief Exception: Invalid area */
331 struct InvalidAreaException : public senf::Exception
332 { InvalidAreaException()
333 : senf::Exception("senf::log::Target::InvalidAreaException"){} };
335 iterator begin() const; ///< Iterator to beginning of routing table
336 iterator end() const; ///< Iterator past the end of routing table
338 RoutingEntry const & operator[](size_type i) const; ///< Access routing entry
340 size_type size() const; ///< Number of routing table entries
341 bool empty() const; ///< \c true, if routing table empty, \c false otherwise
343 void flush(); ///< Clear routing table
345 senf::console::ScopedDirectory<> & consoleDir(); ///< Get console/config directory
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);
353 void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
355 void write(time_type timestamp, detail::StreamBase const & stream,
356 detail::AreaBase const & area, unsigned level, std::string const & message);
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);
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.
373 Every %log message always possesses a complete set of
374 meta information (\a stream, \a area and \a level).
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
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 */
393 console::LazyDirectory consoleDir_;
395 friend class detail::AreaBase;
396 friend class detail::TargetRegistry;
399 /** \brief Write route action
402 std::ostream & operator<<(std::ostream & os, Target::action_t const & action);
406 ///////////////////////////////hh.e////////////////////////////////////////
407 #include "Target.cci"
408 //#include "Target.ct"
409 #include "Target.cti"
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"