--- /dev/null
+// $Id$
+//
+// Copyright (C) 2007
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer NETwork research (NET)
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief AreaRegistry non-inline non-template implementation */
+
+#include "AreaRegistry.hh"
+#include "AreaRegistry.ih"
+
+// Custom includes
+#include "Target.hh"
+
+//#include "AreaRegistry.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::log::detail::AreaBase
+
+prefix_ void senf::log::detail::AreaBase::updateRoutingCache(Target & target,
+ StreamBase const & stream,
+ unsigned limit)
+ const
+{
+ if (stream.index >= routingCache_.size())
+ routingCache_.resize(stream.index+1);
+ unsigned l (limit);
+ Routes::iterator i (routingCache_[stream.index].routes.begin());
+ Routes::iterator const i_end (routingCache_[stream.index].routes.end());
+ for (; i != i_end; ++i) {
+ if (i->target == &target) {
+ i->limit = limit;
+ break;
+ }
+ if (i->limit < l)
+ l = i->limit;
+ }
+ if (i == i_end)
+ routingCache_[stream.index].routes.push_back(RouteEntry(limit, &target));
+ else
+ for (; i != i_end; ++i)
+ if (i->limit < l)
+ l = i->limit;
+ routingCache_[stream.index].limit = l;
+}
+
+prefix_ void senf::log::detail::AreaBase::removeRoutingCache(Target & target,
+ StreamBase const & stream)
+ const
+{
+ if (stream.index >= routingCache_.size())
+ return;
+ unsigned l (DISABLED::value);
+ Routes::iterator i (routingCache_[stream.index].routes.begin());
+ Routes::iterator const i_end (routingCache_[stream.index].routes.end());
+ while (i != i_end) {
+ if (i->target == &target)
+ i = routingCache_[stream.index].routes.erase(i);
+ else {
+ if (i->limit < l)
+ l = i->limit;
+ ++i;
+ }
+ }
+ routingCache_[stream.index].limit = l;
+}
+
+prefix_ void senf::log::detail::AreaBase::write(boost::posix_time::ptime timestamp,
+ StreamBase const & stream, unsigned level,
+ std::string msg)
+ const
+{
+ if (stream.index >= routingCache_.size())
+ return;
+ Routes::iterator i (routingCache_[stream.index].routes.begin());
+ Routes::iterator const i_end (routingCache_[stream.index].routes.end());
+ for (; i != i_end; ++i)
+ i->target->write(timestamp, stream, *this, level, msg);
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "AreaRegistry.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
registry_.insert( std::make_pair(area.v_name(), &area) );
}
+prefix_ senf::log::detail::AreaBase const *
+senf::log::AreaRegistry::lookup(std::string const & name)
+{
+ Registry::iterator i (registry_.find(name));
+ return i == registry_.end() ? 0 : i->second;
+}
+
///////////////////////////////////////////////////////////////////////////
// senf::log::detail::AreaBase
senf::log::AreaRegistry::instance().registerArea(*this);
}
-prefix_ unsigned senf::log::detail::AreaBase::streamLimit(StreamBase const & stream)
- const
-{
- return stream.index >= streamLimits_.size() ? DISABLED::value : streamLimits_[stream.index];
-}
-
-prefix_ void senf::log::detail::AreaBase::setStreamLimit(StreamBase const & stream, unsigned value)
+prefix_ unsigned senf::log::detail::AreaBase::limit(StreamBase const & stream)
const
{
- if (stream.index >= streamLimits_.size())
- streamLimits_.resize(stream.index+1,0u);
- streamLimits_[stream.index] = value;
+ return stream.index >= routingCache_.size() ?
+ DISABLED::value : routingCache_[stream.index].limit;
}
///////////////////////////////cci.e///////////////////////////////////////
AreaRegistry();
void registerArea(detail::AreaBase const & area);
+ detail::AreaBase const * lookup(std::string const & name);
Registry registry_;
// Custom includes
#include <string>
#include <vector>
+#include <list>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include "Levels.hh"
///////////////////////////////ih.p////////////////////////////////////////
namespace senf {
namespace log {
+
+ class Target;
+
namespace detail {
class StreamBase;
void init();
- unsigned streamLimit(StreamBase const & stream) const;
- void setStreamLimit(StreamBase const & stream, unsigned value) const;
+ unsigned limit(StreamBase const & stream) const;
+ void updateRoutingCache(Target & target, StreamBase const & stream, unsigned limit) const;
+ void removeRoutingCache(Target & target, StreamBase const & stream) const;
+ void write(boost::posix_time::ptime timestamp, StreamBase const & stream, unsigned level,
+ std::string msg) const;
private:
- typedef std::vector<unsigned> StreamLimits;
- // mutable since this is a cache and may therefore change at unexpected places ...
- mutable StreamLimits streamLimits_;
+ struct RouteEntry {
+ RouteEntry(unsigned limit_, Target * target_) : limit(limit_), target(target_) {}
+ unsigned limit;
+ Target * target;
+ };
+ typedef std::list<RouteEntry> Routes;
+ struct CacheEntry {
+ CacheEntry() : limit (DISABLED::value), routes() {}
+ unsigned limit;
+ Routes routes;
+ };
+ typedef std::vector<CacheEntry> RoutingCache;
+ mutable RoutingCache routingCache_;
};
}}}
<em>Runtime</em> configuration on the other hand deals with routing all those messages, which
are enabled at compile time to the logging targets. If a message is not routed, it will be
discarded. This allows to additionally disable messages at run-time.
-
- \fixme Restructure compile-time configuration: Only allow stream based configuration using
- SENF_LOG_CONF. For more complex configuration, accept a macro SENF_LOG_CONFFILE which, if
- defined, must define the path of a file to be included. Area specific configuration must be
- done in this include file. The area must be complete (not only a predeclaration) at that
- point.
*/
namespace senf {
# define SLC_elt(r, data, elt) \
SENF_LOG_CONF_DEFINE elt
- // Need to use fold here to not exhaust the maximum FOR nesting depth ...
BOOST_PP_SEQ_FOR_EACH(SLC_elt, none, SENF_LOG_CONF)
# undef SLC_elt
/** \brief Define new default log area for the class
- This command declares the containing class to be it's own default log area. It is such like a
- combination of \ref SENF_LOG_DEF_AREA and \ref SENF_LOG_DEFAULT_AREA with a twist.
+ This command declares the containing class to be it's own default log area. It is such like
+ a combination of \ref SENF_LOG_DEF_AREA and \ref SENF_LOG_DEFAULT_AREA with a twist.
\hideinitializer
*/
// We need to put all tests into this single file to not violate the ODR
-#define SENF_LOG_CONF (( (senf)(log)(Debug), (_), NOTICE ))
+#define SENF_LOG_CONF (( (senf)(log)(Debug), (_), NOTICE )) \
+ (( (not_anonymous)(myStream), (not_anonymous)(Foo), VERBOSE ))
// Custom includes
#include "Logger.hh"
senf::log::StringTarget target;
target.route<senf::log::Debug>();
+ target.route("not_anonymous::myStream", "not_anonymous::Foo");
// We cannot easily check the exact log string since that includes the current date/time
// This is a combination of SENF_LOG_DEF_AREA and SENF_LOG_DEFAULT_AREA.
SENF_LOG_CLASS_AREA();
- // Set default log parameters for this scope. The values here are not really
- // necessary since these are the global default values
+ // Set default log parameters for this scope.
SENF_LOG_DEFAULT_STREAM(foo::UserLog);
SENF_LOG_DEFAULT_LEVEL(senf::log::NOTICE);
design goals
\li Flexible configuration at compile and runtime
\li Concise usage and simple interface
- \li Zero overhead for compile-time disabled log messages I did not find any non-mcaro
- implementation which was not either completely convoluted, unusable or slow. So I turned to
- a macro based implementation which can provide all the design goals stated above.
+ \li Zero overhead for compile-time disabled log messages
+
+ I did not find any non-mcaro implementation which was not either completely convoluted,
+ unusable or slow. So I turned to a macro based implementation which can provide all the
+ design goals stated above.
*/
\f
senf::mpl::rv<2> Parameters_select_(AreaBase *);
template <class Base, class Param>
struct Parameters_<Base,Param,2> : public Base
- { typedef Param area; };
+ { typedef Param area; typedef Param area_base; };
senf::mpl::rv<3> Parameters_select_(LevelBase *);
template <class Base, class Param>
typename boost::disable_if< boost::is_convertible<T*,AliasBase*> >::type * = 0);
template <class Base, class Param>
struct Parameters_<Base,Param,6> : public Base
- { typedef typename Param::SENFLogArea area; };
+ { typedef typename Param::SENFLogArea area; typedef Param area_base; };
#endif
static bool const compileEnabled = senf::log::Enabled<
typename Base::stream,
- typename Base::area,
+ typename Base::area_base,
level>::value;
static bool enabled() {
return compileEnabled
- && Base::area::instance().streamLimit(Base::stream::instance())
- <= Base::level::value;
+ && Base::area::instance().limit(Base::stream::instance()) <= level::value;
}
};
registry_.insert( std::make_pair(stream.v_name(), &stream) );
}
+prefix_ senf::log::detail::StreamBase const *
+senf::log::StreamRegistry::lookup(std::string const & name)
+{
+ Registry::iterator i (registry_.find(name));
+ return i == registry_.end() ? 0 : i->second;
+}
+
///////////////////////////////////////////////////////////////////////////
// senf::log::detail::StreamBase
typedef boost::transform_iterator<SelectName, Registry::const_iterator> iterator;
# ifdef DOXYGEN
- // Hmm ... doxygen does not understand using declarations ...
+ // Hmm ... doxygen does not understand 'using declarations' ...
/// Access stream registry singleton instance
static AreaRegistry & instance();
# endif
StreamRegistry();
void registerStream(detail::StreamBase const & stream);
+ detail::StreamBase const * lookup(std::string const & name);
Registry registry_;
prefix_ senf::log::Target::~Target()
{
while( ! rib_.empty()) {
- // This is slower but simplifies the area cache handling and removing a target
- // should be quite seldom
+ // This is terribly slow but simplifies the area cache handling and removing a target should
+ // be quite seldom
RIB::reverse_iterator i (rib_.rbegin());
- unroute(i->stream, i->area, i->level);
+ unroute(i->stream, i->area, i->level, i->action);
}
TargetRegistry::instance().unregisterTarget(this);
}
+prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * stream,
+ detail::AreaBase const * area)
+{
+ if (! stream) {
+ StreamRegistry::Registry::iterator i (StreamRegistry::instance().registry_.begin());
+ StreamRegistry::Registry::iterator const i_end (StreamRegistry::instance().registry_.end());
+ for (; i != i_end ; ++i)
+ updateRoutingCache(i->second, area);
+ return;
+ }
+ if (! area) {
+ AreaRegistry::Registry::iterator i (AreaRegistry::instance().registry_.begin());
+ AreaRegistry::Registry::iterator const i_end (AreaRegistry::instance().registry_.end());
+ for (; i != i_end ; ++i)
+ updateRoutingCache(stream, i->second);
+ return;
+ }
+ unsigned limit (DISABLED::value);
+ RIB::iterator i (rib_.begin());
+ RIB::iterator const i_end (rib_.end());
+ for(; i != i_end; ++i)
+ if ( (! i->stream || i->stream == stream) &&
+ (! i->area || i->area == area) &&
+ i->action == ACCEPT ) {
+ unsigned l (i->level == NONE::value ? i->stream->defaultRuntimeLimit() : i->level);
+ if (l < limit)
+ limit = l;
+ }
+ if (limit == DISABLED::value)
+ area->removeRoutingCache(*this, *stream);
+ else
+ area->updateRoutingCache(*this, *stream, limit);
+}
+
prefix_ void senf::log::Target::write(boost::posix_time::ptime timestamp,
detail::StreamBase const & stream,
detail::AreaBase const & area, unsigned level,
RIB::iterator i (rib_.begin());
RIB::iterator const i_end (rib_.end());
for (; i != i_end; ++i)
- if ( ( ! i->stream || i->stream == &stream ) &&
- ( ! i->area || i->area == &area ) &&
+ if ( (! i->stream || i->stream == &stream) &&
+ (! i->area || i->area == &area) &&
(i->level == NONE::value ? i->stream->defaultRuntimeLimit() : i->level) <= level ) {
- v_write(timestamp, stream.v_name(), area.v_name(), level, message);
+ if (i->action == ACCEPT)
+ v_write(timestamp, stream.v_name(), area.v_name(), level, message);
return;
}
}
std::string msg)
{
boost::posix_time::ptime timestamp (boost::posix_time::microsec_clock::universal_time());
- Targets::iterator i (targets_.begin());
- Targets::iterator i_end (targets_.end());
- for(; i != i_end; ++i)
- (*i)->write(timestamp, stream, area, level, msg);
+ area.write(timestamp, stream, level, msg);
}
///////////////////////////////cc.e////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// senf::log::Target
-prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
- detail::AreaBase const * area, unsigned level)
+prefix_ void senf::log::Target::route(std::string const & stream, action_t action)
{
- rib_.push_back(RoutingEntry(stream, area, level));
-
- // Update the area/stream routing cache
- if (area)
- updateAreaCache(*area, stream, level);
- else {
- AreaRegistry::Registry::iterator i (AreaRegistry::instance().registry_.begin());
- AreaRegistry::Registry::iterator const i_end (AreaRegistry::instance().registry_.end());
- for (; i != i_end; ++i)
- updateAreaCache(*(i->second), stream, level);
- }
-
+ detail::StreamBase const * s (StreamRegistry::instance().lookup(stream));
+ if (!s)
+ throw InvalidStreamException();
+ route(s, 0, NONE::value, action);
}
-prefix_ void
-senf::log::Target::updateAreaCache(detail::AreaBase const & area,
- detail::StreamBase const * stream, unsigned level)
+prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
+ action_t action)
{
- if (stream) {
- if (level < area.streamLimit(*stream))
- area.setStreamLimit(*stream, level);
- } else {
- StreamRegistry::Registry::iterator i (StreamRegistry::instance().registry_.begin());
- StreamRegistry::Registry::iterator const i_end (StreamRegistry::instance().registry_.end());
- for(; i != i_end; ++i)
- if (level < area.streamLimit(*(i->second)))
- area.setStreamLimit(*(i->second),level);
- }
+ detail::StreamBase const * s (StreamRegistry::instance().lookup(stream));
+ if (!s)
+ throw InvalidStreamException();
+ detail::AreaBase const * a (AreaRegistry::instance().lookup(area));
+ if (!a)
+ throw InvalidAreaException();
+ route(s, a, NONE::value, action);
+}
+
+prefix_ void senf::log::Target::route(std::string const & stream, unsigned level, action_t action)
+{
+ detail::StreamBase const * s (StreamRegistry::instance().lookup(stream));
+ if (!s)
+ throw InvalidStreamException();
+ route(s, 0, level, action);
+}
+
+prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
+ unsigned level, action_t action)
+{
+ detail::StreamBase const * s (StreamRegistry::instance().lookup(stream));
+ if (!s)
+ throw InvalidStreamException();
+ detail::AreaBase const * a (AreaRegistry::instance().lookup(area));
+ if (!a)
+ throw InvalidAreaException();
+ route(s, a, level, action);
+}
+
+////////////////////////////////////////
+// private members
+
+prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
+ detail::AreaBase const * area, unsigned level,
+ action_t action)
+{
+ rib_.push_back(RoutingEntry(stream, area, level, action));
+ if (action == ACCEPT)
+ updateRoutingCache(stream, area);
}
prefix_ void senf::log::Target::unroute(detail::StreamBase const * stream,
- detail::AreaBase const * area, unsigned level)
+ detail::AreaBase const * area, unsigned level,
+ action_t action)
{
- rib_.erase(std::remove(rib_.begin(), rib_.end(), RoutingEntry(stream, area, level)),
+ rib_.erase(std::remove(rib_.begin(), rib_.end(), RoutingEntry(stream, area, level, action)),
rib_.end());
+ if (action == ACCEPT)
+ updateRoutingCache(stream, area);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::log::Target::RoutingEntry
+
+prefix_ senf::log::Target::RoutingEntry::RoutingEntry(detail::StreamBase const * stream_,
+ detail::AreaBase const * area_,
+ unsigned level_, action_t action_)
+ : stream(stream_), area(area_), level(level_), action(action_)
+{}
+
+prefix_ senf::log::Target::RoutingEntry::RoutingEntry()
+ : stream(0), area(0), level(0), action(ACCEPT)
+{}
- ///\fixme Update area/stream routing cache
- // Not doing anything here does not produce incorrect behavior, since removing a route
- // can never lower the logging limit. Not updating the cache just reduces the performance.
+prefix_ bool senf::log::Target::RoutingEntry::operator==(RoutingEntry const & other)
+{
+ return
+ stream == other.stream &&
+ area == other.area &&
+ level == other.level &&
+ action == other.action;
}
///////////////////////////////////////////////////////////////////////////
// senf::log::Target
template <class Stream>
-prefix_ void senf::log::Target::route()
+prefix_ void senf::log::Target::route(action_t action)
{
- route(&Stream::instance(), 0, NONE::value);
+ route(&Stream::instance(), 0, NONE::value, action);
}
-template <class Stream, class Arg0>
-prefix_ void senf::log::Target::route()
+template <class Stream, class Arg>
+prefix_ void senf::log::Target::route(action_t action)
{
- route<Arg0>(&Stream::instance(), static_cast<Arg0*>(0));
+ route<Arg>(&Stream::instance(), static_cast<Arg*>(0), action);
}
template <class Stream, class Area, class Level>
-prefix_ void senf::log::Target::route()
+prefix_ void senf::log::Target::route(action_t action)
{
- route(&Stream::instance(), &Area::instance(), Level::value);
+ route(&Stream::instance(), &Area::instance(), Level::value, action);
}
////////////////////////////////////////
template <class Area>
prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
- detail::AreaBase const *)
+ detail::AreaBase const *, action_t action)
{
- route(stream, &Area::instance(), NONE::value);
+ route(stream, &Area::instance(), NONE::value, action);
}
template <class Level>
prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
- detail::LevelBase const *)
+ detail::LevelBase const *, action_t action)
{
- route(stream, 0, Level::value);
+ route(stream, 0, Level::value, action);
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// Types
+ enum action_t { ACCEPT, REJECT };
+
///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
///@{
///@}
template <class Stream>
- void route();
+ void route(action_t action=ACCEPT);
- template <class Stream, class Arg0>
- void route();
+ template <class Stream, class Arg>
+ void route(action_t action=ACCEPT);
template <class Stream, class Area, class Level>
- void route();
+ void route(action_t action=ACCEPT);
+
+ void route(std::string const & stream, action_t action=ACCEPT);
+ void route(std::string const & stream, std::string const & area, action_t action=ACCEPT);
+ void route(std::string const & stream, unsigned level, action_t action=ACCEPT);
+ void route(std::string const & stream, std::string const & area, unsigned level,
+ action_t action=ACCEPT);
+
+ struct InvalidStreamException : public std::exception
+ { virtual char const * what() const throw()
+ { return "senf::log::Target::InvalidStreamException"; } };
+ struct InvalidAreaException : public std::exception
+ { virtual char const * what() const throw()
+ { return "senf::log::Target::InvalidAreaException"; } };
+
protected:
std::string timestamp();
private:
void route(detail::StreamBase const * stream, detail::AreaBase const * area,
- unsigned level);
+ unsigned level, action_t action);
void unroute(detail::StreamBase const * stream, detail::AreaBase const * area,
- unsigned level);
+ unsigned level, action_t action);
template <class Area>
- void route(detail::StreamBase const * stream, detail::AreaBase const *);
+ void route(detail::StreamBase const * stream, detail::AreaBase const *, action_t action);
template <class Level>
- void route(detail::StreamBase const * stream, detail::LevelBase const *);
-
- void updateAreaCache(detail::AreaBase const & area, detail::StreamBase const * stream,
- unsigned level);
+ void route(detail::StreamBase const * stream, detail::LevelBase const *, action_t action);
+
+ void updateRoutingCache(detail::StreamBase const * stream, detail::AreaBase const * area);
void write(boost::posix_time::ptime timestamp, detail::StreamBase const & stream,
detail::AreaBase const & area, unsigned level, std::string const & 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) {}
+ unsigned level_, action_t action_);
+ RoutingEntry();
- bool operator==(RoutingEntry const & other)
- { return stream == other.stream && area == other.area && level == other.level; }
+ bool operator==(RoutingEntry const & other);
detail::StreamBase const * stream;
detail::AreaBase const * area;
- unsigned level;
+ unsigned level; action_t action;
};
typedef std::vector<RoutingEntry> RIB;
RIB rib_;
- friend class TargetRegistry;
+ friend class detail::AreaBase;
};
/** \brief Target registry