4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
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
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 \fixme optionally Integrate with Scheduler / ClockService to reduce number of gettimeofday()
126 class Target : private boost::noncopyable
129 ///////////////////////////////////////////////////////////////////////////
132 /** \brief Routing action
134 Every routing entry is associated with a routing action. This action is final (for this
135 target. Each target is processed independently).
138 ACCEPT /** Output message */
139 , REJECT /** Suppress message output */
142 /** \brief Target routing entry
144 A single routing entry matches messages against their \e stream, \e area and \e
145 level. If the entry matches, the given \e action is performed.
147 \see senf::log::Target
151 std::string stream() const; ///< Stream to match
152 std::string area() const; ///< Area to match (empty of unspecified)
153 unsigned level() const; ///< Level to match (senf::log::NONE::value if unspecified)
154 action_t action() const; ///< Action to take
161 bool operator==(RoutingEntry const & other);
164 RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area,
165 unsigned level, action_t action);
167 detail::StreamBase const * stream_;
168 detail::AreaBase const * area_;
176 typedef std::vector<RoutingEntry> RIB;
179 typedef RIB::const_iterator iterator; ///< Routing table iterator
181 ///////////////////////////////////////////////////////////////////////////
182 ///\name Structors and default members
189 ///////////////////////////////////////////////////////////////////////////
195 template <class Stream, class Area, class Level> void route(
196 action_t action = ACCEPT, int index = -1); ///< Add route (static)
197 /**< Add a route for the given combination of \a Stream, \a
198 Area and \a Level. The \a Stream parameter is mandatory
199 while either \a Area or \a Level are optional (the
200 template signature is shown simplified here):
202 target.route<SomeStream>();
203 target.route<SomeStream, SomeLevel>();
204 target.route<SomeStream, SomeArea>();
205 target.route<SomeStream, SomeArea, SomeLevel>();
208 See the class description for information on the \a
209 action and \a index parameters
211 \param[in] Stream mandatory stream to match
212 \param[in] Area optional area to match
213 \param[in] Level optional level, matches messages with
214 at least the given level.
215 \param[in] action routing action to take
216 \param[in] index position of new route in the routing
221 void route(std::string const & stream, std::string const & area = "",
222 unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
223 ///< Add route (dynamic)
224 /**< Add a route for the given combination of \a stream, \a
225 area and \a level. The \a stream parameter is mandatory
226 while either \a area or \a level may be left
227 unspecified by setting them to the empty string or
228 senf::log::NONE::value respectively.
230 See the class description for information on the \a
231 action and \a index parameters
233 \throws InvalidStreamException if the given \a stream
234 is not found in the StreamRegistry
235 \throws InvalidAreaException if the given \a area is
236 not found in the AreaRegistry
238 \param[in] stream mandatory stream to match
239 \param[in] area optional area to match
240 \param[in] level optional level, matches messages with
241 at least the given level.
242 \param[in] action routing action to take
243 \param[in] index position of new route in the routing
248 template <class Stream, class Area, class Level>
249 void unroute(action_t action = ACCEPT);
250 ///< Remove route (static)
251 /**< This member removes an arbitrary routing entry. The
252 template parameters are the same as for the
253 corresponding \ref route() call.
255 The routing table is searched for a route exactly
256 matching the given specification. If such a route is
257 found, it will be removed, otherwise the call will be
260 \param[in] Stream mandatory stream to match
261 \param[in] Area optional area to match
262 \param[in] Level optional level, matches messages with
263 at least the given level.
264 \param[in] action routing action to take */
268 void unroute(std::string const & stream, std::string const & area = "",
269 unsigned level = NONE::value, action_t action = ACCEPT);
270 ///< Remove route (dynamic)
271 /**< This member removes an arbitrary routing entry. The \a
272 stream parameter is mandatory while either \a area or
273 \a level may be left unspecified by setting them to the
274 empty string or senf::log::NONE::value respectively.
276 The routing table is searched for a route exactly
277 matching the given specification. If such a route is
278 found, it will be removed, otherwise the call will be
281 \param[in] stream mandatory stream to match
282 \param[in] area optional area to match
283 \param[in] level optional level, matches messages with
284 at least the given level.
285 \param[in] action routing action to take */
286 void unroute(int index=-1); ///< Remove route (indexed)
287 /**< This call will remove the route with the given index.
289 See the class documentation for more information on
292 \param[in] index index of routing entry to remove */
296 template <class Stream> void route(
297 action_t action = ACCEPT, int index = -1);
298 template <class Stream, class Level> void route(
299 action_t action = ACCEPT, int index = -1,
300 typename boost::enable_if< boost::is_convertible<Level*,
301 detail::LevelBase *> >::type * = 0);
302 template <class Stream, class Area> void route(
303 action_t action = ACCEPT, int index = -1,
304 typename boost::enable_if< boost::is_convertible<Area*,
305 detail::AreaBase *> >::type * = 0);
306 template <class Stream, class AreaClass> void route(
307 action_t action = ACCEPT, int index = -1,
308 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
309 detail::AreaBase *> >::type * = 0);
310 template <class Stream, class Area, class Level> void route(
311 action_t action = ACCEPT, int index = -1,
312 typename boost::enable_if< boost::is_convertible<Area *,
313 detail::AreaBase *> >::type * = 0);
314 template <class Stream, class AreaClass, class Level> void route(
315 action_t action = ACCEPT, int index = -1,
316 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
317 detail::AreaBase *> >::type * = 0);
319 template <class Stream> void unroute(
320 action_t action = ACCEPT);
321 template <class Stream, class Level> void unroute(
322 action_t action = ACCEPT,
323 typename boost::enable_if< boost::is_convertible<Level*,
324 detail::LevelBase *> >::type * = 0);
325 template <class Stream, class Area> void unroute(
326 action_t action = ACCEPT,
327 typename boost::enable_if< boost::is_convertible<Area*,
328 detail::AreaBase *> >::type * = 0);
329 template <class Stream, class AreaClass> void unroute(
330 action_t action = ACCEPT,
331 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
332 detail::AreaBase *> >::type * = 0);
333 template <class Stream, class Area, class Level> void unroute(
334 action_t action = ACCEPT,
335 typename boost::enable_if< boost::is_convertible<Area*,
336 detail::AreaBase *> >::type * = 0);
337 template <class Stream, class AreaClass, class Level> void unroute(
338 action_t action = ACCEPT,
339 typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
340 detail::AreaBase *> >::type * = 0);
346 /** \brief Exception: Invalid stream */
347 struct InvalidStreamException : public std::exception
348 { virtual char const * what() const throw()
349 { return "senf::log::Target::InvalidStreamException"; } };
351 /** \brief Exception: Invalid area */
352 struct InvalidAreaException : public std::exception
353 { virtual char const * what() const throw()
354 { return "senf::log::Target::InvalidAreaException"; } };
356 iterator begin() const; ///< Iterator to beginning of routing table
357 iterator end() const; ///< Iterator past the end of routing table
360 void route(detail::StreamBase const * stream, detail::AreaBase const * area,
361 unsigned level, action_t action, int index);
362 void unroute(detail::StreamBase const * stream, detail::AreaBase const * area,
363 unsigned level, action_t action);
365 void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
367 void write(boost::posix_time::ptime timestamp, detail::StreamBase const & stream,
368 detail::AreaBase const & area, unsigned level, std::string const & message);
374 virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream,
375 std::string const & area, unsigned level,
376 std::string const & message) = 0;
377 ///< Called to write out the routing message
378 /**< This member must be defined in the derived class to
379 somehow format and write the log message.
381 Every log message always possesses a complete set of
382 meta information (\a stream, \a area and \a level). The
383 \a area may be an empty string if the message was
384 written from the senf::log::DefaultArea.
386 \note This member must \e not block since it may be
387 called from any unknown context. This prohibits
388 simple logging over NFS or many other network
391 \param[in] timestamp log message timing information
392 \param[in] stream message stream
393 \param[in] area message area
394 \param[in] level message level
395 \param[in] message the message string */
403 friend class detail::AreaBase;
408 ///////////////////////////////hh.e////////////////////////////////////////
409 #include "Target.cci"
410 //#include "Target.ct"
411 #include "Target.cti"
418 // comment-column: 40
419 // c-file-style: "senf"
420 // indent-tabs-mode: nil
421 // ispell-local-dictionary: "american"
422 // compile-command: "scons -u test"