X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Utils%2FLogger%2FTarget.hh;h=ff8fc5467fe0cb7df75feed8c8805a9d14be373e;hb=456ee576285b76aa46240f8001f426757810dcc1;hp=43ae95449cdd2a640168eadb0955e96201a2a544;hpb=9ff976ea47b175355a1f7ef4d05f14edb98a82e4;p=senf.git diff --git a/Utils/Logger/Target.hh b/Utils/Logger/Target.hh index 43ae954..ff8fc54 100644 --- a/Utils/Logger/Target.hh +++ b/Utils/Logger/Target.hh @@ -1,8 +1,8 @@ // $Id$ // -// Copyright (C) 2007 -// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) -// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) +// Copyright (C) 2007 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY // Stefan Bund // // This program is free software; you can redistribute it and/or modify @@ -27,77 +27,347 @@ #define HH_Target_ 1 // Custom includes +#include +#include +#include +#include #include "../singleton.hh" -#include "Stream.hh" -#include "Area.hh" +#include "../mpl.hh" +#include "StreamRegistry.hh" +#include "../Exception.hh" +#include "TimeSource.hh" //#include "Target.mpp" ///////////////////////////////hh.p//////////////////////////////////////// +/** \defgroup targets Targets + + Targets receive log messages and write them to some destination: The console, a log file, an SQL + DB and so on. Every target is derived from the \ref senf::log::Target base class. This base + class provides the target with the necessary routing infrastructure. The different targets only + differ in the way, they write the data. + + \see senf::log::Target + */ + namespace senf { namespace log { + + namespace detail { class TargetRegistry; } + namespace detail { class AreaBase; } + + /** \brief Logging target base class + + Targets are the final destination of %log messages. Every message is eventually routed to one + or several targets. + + \section target_routing Routing + + Each target manages a routing table. The message meta-data (stream, area and level) is + matched against this table. If an entry matches, the action associated with this entry is + taken (either \c ACCEPT or \c REJECT). + + Every target manages it's own routing table. Conceptually, every routing message will be + routed to every target where it will then be matched against each targets routing table (the + implementation is more efficient and utilizes a routing cache). + + Each routing entry consists of the following parameters + \li (optional) \e stream. The entry will match only messages directed at that stream + \li (optional) \e area. If the area is specified, only messages directed at that area are + matched, otherwise any area will be allowed + \li (optional) \e level. If the log level is specified, messages will be accepted if their + level is at least that value. If the value is not specified, the limit will be taken + from the stream's default value. - /** \brief + Each parameter (stream, area and level) has two representations: A static (compile time + constant) representation, which is the representation also used in the log statements, and a + dynamic representation, which may be used for manipulating the routing table. + + The static representation is used, when passing routing parameters via template arguments: + \code + target.route(senf::log::Target::REJECT); + target.route(); + \endcode + The identical routing statements may be expressed using dynamic routing via: + \code + target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT); + target.route("foo::SomeStream"); + \endcode + The static representation has the benefit of being compile-time type checked: Invalid + routing parameters will be caught while compiling the code. The dynamic representation is + more flexible as it allows to adjust routing from user input (e.g. configuration files). + + The different object representations are: + \li The \e streams is statically represented by it's name, which is the name of a class + defined with \ref SENF_LOG_DEFINE_STREAM. The dynamic representation is a string + representation of this name. + \li The \e area is statically represented by it's name, which again is the name of a class + defined with \ref SENF_LOG_DEFINE_STREAM. The dynamic representation again is a string + representation of this class's name. The dynamic representation represents an absent + area with the empty string. + \li The \e level is statically represented by a level class from \ref + loglevels. Dynamically, it is represented by an unsigned integer number, the \c value + member of that class. + + \section target_impl Implementing new targets + + To implement a new target type, you need to derive from senf::log::Target and implement the + single \c v_write member. This member will be called whenever a message should be output. + + The target may process in any arbitrary way: reformat, writing it into an SQL DB, whatever + can be envisioned. However, there is one important limitation: The \c v_write call must not + block. So for more complex scenarios, additional measures must be taken (e.g. writing a %log + backend daemon which receives the messages via UDP and processes them). Of course, in rare + cases messages might be lost but this cannot be avoided. + + \see \ref targets */ - class Target - : public senf::singleton + class Target : private boost::noncopyable { public: /////////////////////////////////////////////////////////////////////////// // Types + /** \brief Routing action + + Every routing entry is associated with a routing action. This action is final (for this + target. Each target is processed independently). + */ + enum action_t { + ACCEPT /** Output message */ + , REJECT /** Suppress message output */ + }; + + /** \brief Target routing entry + + A single routing entry matches messages against their \e stream, \e area and \e + level. If the entry matches, the given \e action is performed. + + \see senf::log::Target + */ + struct RoutingEntry + { + std::string stream() const; ///< Stream to match + std::string area() const; ///< Area to match (empty of unspecified) + unsigned level() const; ///< Level to match (senf::log::NONE::value if unspecified) + action_t action() const; ///< Action to take + +# ifdef DOXYGEN + private: +# endif + + RoutingEntry(); + bool operator==(RoutingEntry const & other); + + private: + RoutingEntry(detail::StreamBase const * stream, detail::AreaBase const * area, + unsigned level, action_t action); + + detail::StreamBase const * stream_; + detail::AreaBase const * area_; + unsigned level_; + action_t action_; + + friend class Target; + }; + + private: + typedef std::vector RIB; + + public: + typedef RIB::const_iterator iterator; ///< Routing table iterator + /////////////////////////////////////////////////////////////////////////// ///\name Structors and default members ///@{ + Target(); virtual ~Target(); - // default default constructor - // default copy constructor - // default copy assignment - // default destructor + ///@} + /////////////////////////////////////////////////////////////////////////// + ///\name Routing + ///\{ - // no conversion constructors +# ifdef DOXYGEN - ///@} + template void route( + action_t action = ACCEPT, int index = -1); ///< Add route (static) + /**< Add a route for the given combination of \a Stream, \a + Area and \a Level. All parameters (\a Stream, \a Area + and \a Level) are optional (the template signature is + shown simplified here). Examples: + \code + target.route(); + target.route(); + target.route(); + target.route(); + target.route(); + \endcode - protected: + See the class description for information on the \a + action and \a index parameters - private: + \tparam Stream stream to match + \tparam Area area to match + \tparam Level level, matches messages with + at least the given level. + \param[in] action routing action to take + \param[in] index position of new route in the routing + table */ + +# endif + + void route(std::string const & stream, std::string const & area = "", + unsigned level = NONE::value, action_t action = ACCEPT, int index = -1); + ///< Add route (dynamic) + /**< Add a route for the given combination of \a stream, \a + area and \a level. All parameters (\a Stream, \a Area + and \a Level) are optional and may be omitted by + setting them to the empty string or the + senf::log::NONE::value respectively. + + See the class description for information on the \a + action and \a index parameters + + \throws InvalidStreamException if the given \a stream + is not found in the StreamRegistry + \throws InvalidAreaException if the given \a area is + not found in the AreaRegistry + + \param[in] stream stream to match + \param[in] area area to match + \param[in] level level, matches messages with at least + the given level. + \param[in] action routing action to take + \param[in] index position of new route in the routing + table */ + +# ifdef DOXYGEN + + template + void unroute(action_t action = ACCEPT); + ///< Remove route (static) + /**< This member removes an arbitrary routing entry. The + template parameters are the same as for the + corresponding \ref route() call. + + The routing table is searched for a route exactly + matching the given specification. If such a route is + found, it will be removed, otherwise the call will be + ignored + + \tparam Stream stream to match + \tparam Area area to match + \tparam Level level, matches messages with + at least the given level. + \param[in] action routing action to take */ + +# endif + + void unroute(std::string const & stream, std::string const & area = "", + unsigned level = NONE::value, action_t action = ACCEPT); + ///< Remove route (dynamic) + /**< This member removes an arbitrary routing entry. The \a + stream parameter is mandatory while either \a area or + \a level may be left unspecified by setting them to the + empty string or senf::log::NONE::value respectively. + + The routing table is searched for a route exactly + matching the given specification. If such a route is + found, it will be removed, otherwise the call will be + ignored + + \param[in] stream stream to match + \param[in] area area to match + \param[in] level level, matches messages with at least + the given level. + \param[in] action routing action to take */ + void unroute(int index=-1); ///< Remove route (indexed) + /**< This call will remove the route with the given index. + + See the class documentation for more information on + indexing. + + \param[in] index index of routing entry to remove */ + +# ifndef DOXYGEN + + template + void route(action_t action = ACCEPT, int index = -1); + template + void route(action_t action = ACCEPT, int index = -1); + template + void route(action_t action = ACCEPT, int index = -1); + + template + void unroute(action_t action = ACCEPT); + template + void unroute(action_t action = ACCEPT); + template + void unroute(action_t action = ACCEPT); +# endif + + ///\} + + /** \brief Exception: Invalid stream */ + struct InvalidStreamException : public senf::Exception + { InvalidStreamException() + : senf::Exception("senf::log::Target::InvalidStreamException"){} }; + + /** \brief Exception: Invalid area */ + struct InvalidAreaException : public senf::Exception + { InvalidAreaException() + : senf::Exception("senf::log::Target::InvalidAreaException"){} }; + + iterator begin() const; ///< Iterator to beginning of routing table + iterator end() const; ///< Iterator past the end of routing table + + private: void route(detail::StreamBase const * stream, detail::AreaBase const * area, - unsigned level); + unsigned level, action_t action, int index); void unroute(detail::StreamBase const * stream, detail::AreaBase const * area, - unsigned level); + unsigned level, action_t action); - void updateAreaCache(detail::AreaBase const & area, detail::StreamBase const * stream, - unsigned level); + void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area); - void write(detail::StreamBase const & stream, detail::AreaBase const & area, - unsigned level, std::string const & message); - - virtual void v_write(std::string const & stream, std::string const & area, unsigned level, + void write(time_type timestamp, detail::StreamBase const & stream, + detail::AreaBase const & area, unsigned level, std::string const & message); + +# ifdef DOXYGEN + protected: +# endif + + virtual void v_write(time_type timestamp, std::string const & stream, + std::string const & area, unsigned level, std::string const & message) = 0; + ///< Called to write out the routing message + /**< This member must be defined in the derived class to + somehow format and write the %log message. - struct RoutingEntry - { - RoutingEntry(detail::StreamBase const * stream_, detail::AreaBase const * area_, - unsigned level_) - : stream(stream_), area(area_), level(level_) {} - RoutingEntry() - : stream(0), area(0), level(0) {} - - bool operator==(RoutingEntry const & other) - { return stream == other.stream && area == other.area && level == other.level; } - - detail::StreamBase const * stream; - detail::AreaBase const * area; - unsigned level; - }; + Every %log message always possesses a complete set of + meta information (\a stream, \a area and \a level). - typedef std::vector RIB; + \note This member must \e not block since it may be + called from any unknown context. This prohibits + simple logging over NFS or many other network + protocols. + + \param[in] timestamp %log message timing information + \param[in] stream message stream + \param[in] area message area + \param[in] level message level + \param[in] message the message string */ + +# ifdef DOXYGEN + private: +# endif RIB rib_; + + friend class detail::AreaBase; + friend class detail::TargetRegistry; }; }} @@ -105,7 +375,7 @@ namespace log { ///////////////////////////////hh.e//////////////////////////////////////// #include "Target.cci" //#include "Target.ct" -//#include "Target.cti" +#include "Target.cti" #endif