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 */
31 #include <boost/date_time/posix_time/posix_time.hpp>
32 #include <boost/utility.hpp>
33 #include <boost/type_traits/is_convertible.hpp>
34 #include "../singleton.hh"
36 #include "StreamRegistry.hh"
37 #include "AreaRegistry.hh"
39 //#include "Target.mpp"
40 ///////////////////////////////hh.p////////////////////////////////////////
42 /** \defgroup targets Targets
44 Targets receive log messages and write them to some destination: The console, a log file, an SQL
45 DB and so on. Every target is derived from the \ref senf::log::Target base class. This base
46 class provides the target with the necessary routing infrastructure. The different targets only
47 differ in the way, they write the data.
49 \see senf::log::Target
55 namespace detail { class TargetRegistry; }
57 /** \brief Logging target base class
59 Targets are the final destination of log messages. Every message is eventually routed to one
62 \section target_routing Routing
64 Each target manages a routing table. The message meta-data (stream, area and level) is
65 matched against this table. If an entry matches, the action associated with this entry is
66 taken (either \c ACCEPT or \c REJECT).
68 Every target manages it's own routing table. Conceptually, every routing message will be
69 routed to every target where it will then be matched against each targets routing table (the
70 implementation is more efficient and utilizes a routing cache).
72 Each routing entry consists of the following parameters
73 \li (mandatory) \e stream. The entry will match only messages directed at that stream
74 \li (optional) \e area. If the area is specified, only messages directed at that area are
75 matched, otherwise any area will be allowed
76 \li (optional) \e level. If the log level is specified, messages will be accepted if their
77 level is at least that value. If the value is not specified, the limit will be taken
78 from the stream's default value.
80 Each parameter (stream, area and level) has two representations: A static (compile time
81 constant) representation, which is the representation also used in the log statements, and a
82 dynamic representation, which may be used for manipulating the routing table.
84 The static representation is used, when passing routing parameters via template arguments:
86 target.route<foo::SomeStream, senf::log::NOTICE>(senf::log::Target::REJECT);
87 target.route<foo::SomeStream>();
89 The identical routing statements may be expressed using dynamic routing via:
91 target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT);
92 target.route("foo::SomeStream");
94 The static representation has the benefit of being compile-time type checked: Invalid
95 routing parameters will be caught while compiling the code. The dynamic representation is
96 more flexible as it allows to adjust routing from user input (e.g. configuration files).
98 The different object representations are:
99 \li The \e streams is statically represented by it's name, which is the name of a class
100 defined with \ref SENF_LOG_DEF_STREAM. The dynamic representation is a string
101 representation of this name.
102 \li The \e area is statically represented by it's name, which again is the name of a class
103 defined with \ref SENF_LOG_DEF_STREAM. The dynamic representation again is a string
104 representation of this class's name. The dynamic representation represents an absent
105 area with the empty string.
106 \li The \e level is statically represented by a level class from \ref
107 loglevels. Dynamically, it is represented by an unsigned integer number, the \c value
108 member of that class.
110 \section target_impl Implementing new targets
112 To implement a new target type, you need to derive from senf::log::Target and implement the
113 single \c v_write member. This member will be called whenever a message should be output.
115 The target may process in any arbitrary way: reformat, writing it into an SQL DB, whatever
116 can be envisioned. However, there is one important limitation: The \c v_write call must not
117 block. So for more complex scenarios, additional measures must be taken (e.g. writing a log
118 backend daemon which receives the messages via UDP and processes them). Of course, in rare
119 cases messages might be lost but this cannot be avoided.
123 class Target : private boost::noncopyable
126 ///////////////////////////////////////////////////////////////////////////
129 /** \brief Routing action
131 Every routing entry is associated with a routing action. This action is final (for this
132 target. Each target is processed independently).
135 ACCEPT /** Output message */
136 , REJECT /** Suppress message output */
139 /** \brief Target routing entry
141 A single routing entry matches messages against their \e stream, \e area and \e
142 level. If the entry matches, the given \e action is performed.
144 \see senf::log::Target
148 std::string stream() const; ///< Stream to match
149 std::string area() const; ///< Area to match (empty of unspecified)
150 unsigned level() const; ///< Level to match (senf::log::NONE::value if unspecified)
151 action_t action() const; ///< Action to take
158 bool operator==(RoutingEntry const & other);
161 RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area,
162 unsigned level, action_t action);
164 detail::StreamBase const * stream_;
165 detail::AreaBase const * area_;
173 typedef std::vector<RoutingEntry> RIB;
176 typedef RIB::const_iterator iterator; ///< Routing table iterator
178 ///////////////////////////////////////////////////////////////////////////
179 ///\name Structors and default members
186 ///////////////////////////////////////////////////////////////////////////
192 template <class Stream, class Area, class Level> void route(
193 action_t action = ACCEPT, int index = -1); ///< Add route (static)
194 /**< Add a route for the given combination of \a Stream, \a
195 Area and \a Level. The \a Stream parameter is mandatory
196 while either \a Area or \a Level are optional (the
197 template signature is shown simplified here):
199 target.route<SomeStream>();
200 target.route<SomeStream, SomeLevel>();
201 target.route<SomeStream, SomeArea>();
202 target.route<SomeStream, SomeArea, SomeLevel>();
205 See the class description for information on the \a
206 action and \a index parameters
208 \param[in] Stream mandatory stream to match
209 \param[in] Area optional area to match
210 \param[in] Level optional level, matches messages with
211 at least the given level.
212 \param[in] action routing action to take
213 \param[in] index position of new route in the routing
218 void route(std::string const & stream, std::string const & area = "",
219 unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
220 ///< Add route (dynamic)
221 /**< Add a route for the given combination of \a stream, \a
222 area and \a level. The \a stream parameter is mandatory
223 while either \a area or \a level may be left
224 unspecified by setting them to the empty string or
225 senf::log::NONE::value respectively.
227 See the class description for information on the \a
228 action and \a index parameters
230 \throws InvalidStreamException if the given \a stream
231 is not found in the StreamRegistry
232 \throws InvalidAreaException if the given \a area is
233 not found in the AreaRegistry
235 \param[in] stream mandatory stream to match
236 \param[in] area optional area to match
237 \param[in] level optional level, matches messages with
238 at least the given level.
239 \param[in] action routing action to take
240 \param[in] index position of new route in the routing
245 template <class Stream, class Area, class Level>
246 void unroute(action_t action = ACCEPT);
247 ///< Remove route (static)
248 /**< This member removes an arbitrary routing entry. The
249 template parameters are the same as for the
250 corresponding \ref route() call.
252 The routing table is searched for a route exactly
253 matching the given specification. If such a route is
254 found, it will be removed, otherwise the call will be
257 \param[in] Stream mandatory stream to match
258 \param[in] Area optional area to match
259 \param[in] Level optional level, matches messages with
260 at least the given level.
261 \param[in] action routing action to take */
265 void unroute(std::string const & stream, std::string const & area = "",
266 unsigned level = NONE::value, action_t action = ACCEPT);
267 ///< Remove route (dynamic)
268 /**< This member removes an arbitrary routing entry. The \a
269 stream parameter is mandatory while either \a area or
270 \a level may be left unspecified by setting them to the
271 empty string or senf::log::NONE::value respectively.
273 The routing table is searched for a route exactly
274 matching the given specification. If such a route is
275 found, it will be removed, otherwise the call will be
278 \param[in] stream mandatory stream to match
279 \param[in] area optional area to match
280 \param[in] level optional level, matches messages with
281 at least the given level.
282 \param[in] action routing action to take */
283 void unroute(int index=-1); ///< Remove route (indexed)
284 /**< This call will remove the route with the given index.
286 See the class documentation for more information on
289 \param[in] index index of routing entry to remove */
293 template <class Stream> void route(
294 action_t action = ACCEPT, int index = -1);
295 template <class Stream, class Level> void route(
296 action_t action = ACCEPT, int index = -1,
297 typename boost::enable_if< boost::is_convertible<Level*,
298 detail::LevelBase *> >::type * = 0);
299 template <class Stream, class Area> void route(
300 action_t action = ACCEPT, int index = -1,
301 typename boost::enable_if< boost::is_convertible<Area*,
302 detail::AreaBase *> >::type * = 0);
303 template <class Stream, class AreaClass> void route(
304 action_t action = ACCEPT, int index = -1,
305 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
306 detail::AreaBase *> >::type * = 0);
307 template <class Stream, class Area, class Level> void route(
308 action_t action = ACCEPT, int index = -1,
309 typename boost::enable_if< boost::is_convertible<Area *,
310 detail::AreaBase *> >::type * = 0);
311 template <class Stream, class AreaClass, class Level> void route(
312 action_t action = ACCEPT, int index = -1,
313 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
314 detail::AreaBase *> >::type * = 0);
316 template <class Stream> void unroute(
317 action_t action = ACCEPT);
318 template <class Stream, class Level> void unroute(
319 action_t action = ACCEPT,
320 typename boost::enable_if< boost::is_convertible<Level*,
321 detail::LevelBase *> >::type * = 0);
322 template <class Stream, class Area> void unroute(
323 action_t action = ACCEPT,
324 typename boost::enable_if< boost::is_convertible<Area*,
325 detail::AreaBase *> >::type * = 0);
326 template <class Stream, class AreaClass> void unroute(
327 action_t action = ACCEPT,
328 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
329 detail::AreaBase *> >::type * = 0);
330 template <class Stream, class Area, class Level> void unroute(
331 action_t action = ACCEPT,
332 typename boost::enable_if< boost::is_convertible<Area*,
333 detail::AreaBase *> >::type * = 0);
334 template <class Stream, class AreaClass, class Level> void unroute(
335 action_t action = ACCEPT,
336 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
337 detail::AreaBase *> >::type * = 0);
343 /** \brief Exception: Invalid stream */
344 struct InvalidStreamException : public std::exception
345 { virtual char const * what() const throw()
346 { return "senf::log::Target::InvalidStreamException"; } };
348 /** \brief Exception: Invalid area */
349 struct InvalidAreaException : public std::exception
350 { virtual char const * what() const throw()
351 { return "senf::log::Target::InvalidAreaException"; } };
353 iterator begin() const; ///< Iterator to beginning of routing table
354 iterator end() const; ///< Iterator past the end of routing table
357 void route(detail::StreamBase const * stream, detail::AreaBase const * area,
358 unsigned level, action_t action, int index);
359 void unroute(detail::StreamBase const * stream, detail::AreaBase const * area,
360 unsigned level, action_t action);
362 void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
364 void write(boost::posix_time::ptime timestamp, detail::StreamBase const & stream,
365 detail::AreaBase const & area, unsigned level, std::string const & message);
371 virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream,
372 std::string const & area, unsigned level,
373 std::string const & message) = 0;
374 ///< Called to write out the routing message
375 /**< This member must be defined in the derived class to
376 somehow format and write the log message.
378 Every log message always possesses a complete set of
379 meta information (\a stream, \a area and \a level).
381 \note This member must \e not block since it may be
382 called from any unknown context. This prohibits
383 simple logging over NFS or many other network
386 \param[in] timestamp log message timing information
387 \param[in] stream message stream
388 \param[in] area message area
389 \param[in] level message level
390 \param[in] message the message string */
398 friend class detail::AreaBase;
399 friend class detail::TargetRegistry;
402 /** \brief Log message time source abstract base class
404 Instances derived from TimeSource provide the Logging library with the current date/time
405 value. The \c operator() member must be implemented to return the current universal time
408 A new TimeSource may be installed using \ref senf::log::timeSource().
414 virtual ~TimeSource();
415 virtual boost::posix_time::ptime operator()() const = 0;
418 /** \brief Default log message time source
420 This time source is installed by default and uses gettimeofday() (via the Boost.DateTime
421 library) to get the current universal time.
425 struct SystemTimeSource : public TimeSource
427 virtual boost::posix_time::ptime operator()() const;
430 /** \brief Change log message time source
432 Set the log message time source to \a source. The logging library will take ownership of \e
433 source and will take care to free it, if necessary.
435 Since the time source class will in almost all cases be default constructible, see the
436 template overload for a simpler interface.
440 void timeSource(std::auto_ptr<TimeSource> source);
442 /** \brief Change log message time source
444 Set the log message time source to (an instance of) \a Source. \a Source must be default
445 constructible, otherwise use the non-template senf::log::timeSource() overload.
449 template <class Source> void timeSource();
453 ///////////////////////////////hh.e////////////////////////////////////////
454 #include "Target.cci"
455 //#include "Target.ct"
456 #include "Target.cti"
463 // comment-column: 40
464 // c-file-style: "senf"
465 // indent-tabs-mode: nil
466 // ispell-local-dictionary: "american"
467 // compile-command: "scons -u test"