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"
38 #include "../Exception.hh"
40 //#include "Target.mpp"
41 ///////////////////////////////hh.p////////////////////////////////////////
43 /** \defgroup targets Targets
45 Targets receive log messages and write them to some destination: The console, a log file, an SQL
46 DB and so on. Every target is derived from the \ref senf::log::Target base class. This base
47 class provides the target with the necessary routing infrastructure. The different targets only
48 differ in the way, they write the data.
50 \see senf::log::Target
56 namespace detail { class TargetRegistry; }
58 /** \brief Logging target base class
60 Targets are the final destination of %log messages. Every message is eventually routed to one
63 \section target_routing Routing
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).
69 Every target manages it's own routing table. Conceptually, every routing message will be
70 routed to every target where it will then be matched against each targets routing table (the
71 implementation is more efficient and utilizes a routing cache).
73 Each routing entry consists of the following parameters
74 \li (mandatory) \e stream. The entry will match only messages directed at that stream
75 \li (optional) \e area. If the area is specified, only messages directed at that area are
76 matched, otherwise any area will be allowed
77 \li (optional) \e level. If the log level is specified, messages will be accepted if their
78 level is at least that value. If the value is not specified, the limit will be taken
79 from the stream's default value.
81 Each parameter (stream, area and level) has two representations: A static (compile time
82 constant) representation, which is the representation also used in the log statements, and a
83 dynamic representation, which may be used for manipulating the routing table.
85 The static representation is used, when passing routing parameters via template arguments:
87 target.route<foo::SomeStream, senf::log::NOTICE>(senf::log::Target::REJECT);
88 target.route<foo::SomeStream>();
90 The identical routing statements may be expressed using dynamic routing via:
92 target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT);
93 target.route("foo::SomeStream");
95 The static representation has the benefit of being compile-time type checked: Invalid
96 routing parameters will be caught while compiling the code. The dynamic representation is
97 more flexible as it allows to adjust routing from user input (e.g. configuration files).
99 The different object representations are:
100 \li The \e streams is statically represented by it's name, which is the name of a class
101 defined with \ref SENF_LOG_DEFINE_STREAM. The dynamic representation is a string
102 representation of this name.
103 \li The \e area is statically represented by it's name, which again is the name of a class
104 defined with \ref SENF_LOG_DEFINE_STREAM. The dynamic representation again is a string
105 representation of this class's name. The dynamic representation represents an absent
106 area with the empty string.
107 \li The \e level is statically represented by a level class from \ref
108 loglevels. Dynamically, it is represented by an unsigned integer number, the \c value
109 member of that class.
111 \section target_impl Implementing new targets
113 To implement a new target type, you need to derive from senf::log::Target and implement the
114 single \c v_write member. This member will be called whenever a message should be output.
116 The target may process in any arbitrary way: reformat, writing it into an SQL DB, whatever
117 can be envisioned. However, there is one important limitation: The \c v_write call must not
118 block. So for more complex scenarios, additional measures must be taken (e.g. writing a %log
119 backend daemon which receives the messages via UDP and processes them). Of course, in rare
120 cases messages might be lost but this cannot be avoided.
124 class Target : private boost::noncopyable
127 ///////////////////////////////////////////////////////////////////////////
130 /** \brief Routing action
132 Every routing entry is associated with a routing action. This action is final (for this
133 target. Each target is processed independently).
136 ACCEPT /** Output message */
137 , REJECT /** Suppress message output */
140 /** \brief Target routing entry
142 A single routing entry matches messages against their \e stream, \e area and \e
143 level. If the entry matches, the given \e action is performed.
145 \see senf::log::Target
149 std::string stream() const; ///< Stream to match
150 std::string area() const; ///< Area to match (empty of unspecified)
151 unsigned level() const; ///< Level to match (senf::log::NONE::value if unspecified)
152 action_t action() const; ///< Action to take
159 bool operator==(RoutingEntry const & other);
162 RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area,
163 unsigned level, action_t action);
165 detail::StreamBase const * stream_;
166 detail::AreaBase const * area_;
174 typedef std::vector<RoutingEntry> RIB;
177 typedef RIB::const_iterator iterator; ///< Routing table iterator
179 ///////////////////////////////////////////////////////////////////////////
180 ///\name Structors and default members
187 ///////////////////////////////////////////////////////////////////////////
193 template <class Stream, class Area, class Level> void route(
194 action_t action = ACCEPT, int index = -1); ///< Add route (static)
195 /**< Add a route for the given combination of \a Stream, \a
196 Area and \a Level. The \a Stream parameter is mandatory
197 while either \a Area or \a Level are optional (the
198 template signature is shown simplified here):
200 target.route<SomeStream>();
201 target.route<SomeStream, SomeLevel>();
202 target.route<SomeStream, SomeArea>();
203 target.route<SomeStream, SomeArea, SomeLevel>();
206 See the class description for information on the \a
207 action and \a index parameters
209 \tparam Stream mandatory stream to match
210 \tparam Area optional area to match
211 \tparam Level optional level, matches messages with
212 at least the given level.
213 \param[in] action routing action to take
214 \param[in] index position of new route in the routing
219 void route(std::string const & stream, std::string const & area = "",
220 unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
221 ///< Add route (dynamic)
222 /**< Add a route for the given combination of \a stream, \a
223 area and \a level. The \a stream parameter is mandatory
224 while either \a area or \a level may be left
225 unspecified by setting them to the empty string or
226 senf::log::NONE::value respectively.
228 See the class description for information on the \a
229 action and \a index parameters
231 \throws InvalidStreamException if the given \a stream
232 is not found in the StreamRegistry
233 \throws InvalidAreaException if the given \a area is
234 not found in the AreaRegistry
236 \param[in] stream mandatory stream to match
237 \param[in] area optional area to match
238 \param[in] level optional level, matches messages with
239 at least the given level.
240 \param[in] action routing action to take
241 \param[in] index position of new route in the routing
246 template <class Stream, class Area, class Level>
247 void unroute(action_t action = ACCEPT);
248 ///< Remove route (static)
249 /**< This member removes an arbitrary routing entry. The
250 template parameters are the same as for the
251 corresponding \ref route() call.
253 The routing table is searched for a route exactly
254 matching the given specification. If such a route is
255 found, it will be removed, otherwise the call will be
258 \tparam Stream mandatory stream to match
259 \tparam Area optional area to match
260 \tparam Level optional level, matches messages with
261 at least the given level.
262 \param[in] action routing action to take */
266 void unroute(std::string const & stream, std::string const & area = "",
267 unsigned level = NONE::value, action_t action = ACCEPT);
268 ///< Remove route (dynamic)
269 /**< This member removes an arbitrary routing entry. The \a
270 stream parameter is mandatory while either \a area or
271 \a level may be left unspecified by setting them to the
272 empty string or senf::log::NONE::value respectively.
274 The routing table is searched for a route exactly
275 matching the given specification. If such a route is
276 found, it will be removed, otherwise the call will be
279 \param[in] stream mandatory stream to match
280 \param[in] area optional area to match
281 \param[in] level optional level, matches messages with
282 at least the given level.
283 \param[in] action routing action to take */
284 void unroute(int index=-1); ///< Remove route (indexed)
285 /**< This call will remove the route with the given index.
287 See the class documentation for more information on
290 \param[in] index index of routing entry to remove */
294 template <class Stream> void route(
295 action_t action = ACCEPT, int index = -1);
296 template <class Stream, class Level> void route(
297 action_t action = ACCEPT, int index = -1,
298 typename boost::enable_if< boost::is_convertible<Level*,
299 detail::LevelBase *> >::type * = 0);
300 template <class Stream, class Area> void route(
301 action_t action = ACCEPT, int index = -1,
302 typename boost::enable_if< boost::is_convertible<Area*,
303 detail::AreaBase *> >::type * = 0);
304 template <class Stream, class AreaClass> void route(
305 action_t action = ACCEPT, int index = -1,
306 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
307 detail::AreaBase *> >::type * = 0);
308 template <class Stream, class Area, class Level> void route(
309 action_t action = ACCEPT, int index = -1,
310 typename boost::enable_if< boost::is_convertible<Area *,
311 detail::AreaBase *> >::type * = 0);
312 template <class Stream, class AreaClass, class Level> void route(
313 action_t action = ACCEPT, int index = -1,
314 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
315 detail::AreaBase *> >::type * = 0);
317 template <class Stream> void unroute(
318 action_t action = ACCEPT);
319 template <class Stream, class Level> void unroute(
320 action_t action = ACCEPT,
321 typename boost::enable_if< boost::is_convertible<Level*,
322 detail::LevelBase *> >::type * = 0);
323 template <class Stream, class Area> void unroute(
324 action_t action = ACCEPT,
325 typename boost::enable_if< boost::is_convertible<Area*,
326 detail::AreaBase *> >::type * = 0);
327 template <class Stream, class AreaClass> void unroute(
328 action_t action = ACCEPT,
329 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
330 detail::AreaBase *> >::type * = 0);
331 template <class Stream, class Area, class Level> void unroute(
332 action_t action = ACCEPT,
333 typename boost::enable_if< boost::is_convertible<Area*,
334 detail::AreaBase *> >::type * = 0);
335 template <class Stream, class AreaClass, class Level> void unroute(
336 action_t action = ACCEPT,
337 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
338 detail::AreaBase *> >::type * = 0);
344 /** \brief Exception: Invalid stream */
345 struct InvalidStreamException : public senf::Exception
346 { InvalidStreamException()
347 : senf::Exception("senf::log::Target::InvalidStreamException"){} };
349 /** \brief Exception: Invalid area */
350 struct InvalidAreaException : public senf::Exception
351 { InvalidAreaException()
352 : senf::Exception("senf::log::Target::InvalidAreaException"){} };
354 iterator begin() const; ///< Iterator to beginning of routing table
355 iterator end() const; ///< Iterator past the end of routing table
358 void route(detail::StreamBase const * stream, detail::AreaBase const * area,
359 unsigned level, action_t action, int index);
360 void unroute(detail::StreamBase const * stream, detail::AreaBase const * area,
361 unsigned level, action_t action);
363 void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
365 void write(boost::posix_time::ptime timestamp, detail::StreamBase const & stream,
366 detail::AreaBase const & area, unsigned level, std::string const & message);
372 virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream,
373 std::string const & area, unsigned level,
374 std::string const & message) = 0;
375 ///< Called to write out the routing message
376 /**< This member must be defined in the derived class to
377 somehow format and write the %log message.
379 Every %log message always possesses a complete set of
380 meta information (\a stream, \a area and \a level).
382 \note This member must \e not block since it may be
383 called from any unknown context. This prohibits
384 simple logging over NFS or many other network
387 \param[in] timestamp %log message timing information
388 \param[in] stream message stream
389 \param[in] area message area
390 \param[in] level message level
391 \param[in] message the message string */
399 friend class detail::AreaBase;
400 friend class detail::TargetRegistry;
403 /** \brief Log message time source abstract base class
405 Instances derived from TimeSource provide the Logging library with the current date/time
406 value. The \c operator() member must be implemented to return the current universal time
409 A new TimeSource may be installed using \ref senf::log::timeSource().
415 virtual ~TimeSource();
416 virtual boost::posix_time::ptime operator()() const = 0;
419 /** \brief Default %log message time source
421 This time source is installed by default and uses gettimeofday() (via the Boost.DateTime
422 library) to get the current universal time.
426 struct SystemTimeSource : public TimeSource
428 virtual boost::posix_time::ptime operator()() const;
431 /** \brief Change %log message time source
433 Set the %log message time source to \a source. The logging library will take ownership of \e
434 source and will take care to free it, if necessary.
436 Since the time source class will in almost all cases be default constructible, see the
437 template overload for a simpler interface.
441 void timeSource(std::auto_ptr<TimeSource> source);
443 /** \brief Change %log message time source
445 Set the %log message time source to (an instance of) \a Source. \a Source must be default
446 constructible, otherwise use the non-template senf::log::timeSource() overload.
450 template <class Source> void timeSource();
454 ///////////////////////////////hh.e////////////////////////////////////////
455 #include "Target.cci"
456 //#include "Target.ct"
457 #include "Target.cti"
464 // comment-column: 40
465 // c-file-style: "senf"
466 // indent-tabs-mode: nil
467 // ispell-local-dictionary: "american"
468 // compile-command: "scons -u test"