X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Utils%2FLogger%2FTarget.cc;h=ca0574912d4d519d21708b89bd5e12ef28cd3898;hb=1a02a61e1e1515dca27577013cc7300ea5133fd5;hp=11142a7c841c371155e02f27696019b849ca8cd5;hpb=f6f670f2dbc82b77db29df6cd452f2b351b9662a;p=senf.git diff --git a/Utils/Logger/Target.cc b/Utils/Logger/Target.cc index 11142a7..ca05749 100644 --- a/Utils/Logger/Target.cc +++ b/Utils/Logger/Target.cc @@ -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 @@ -24,9 +24,15 @@ \brief Target non-inline non-template implementation */ #include "Target.hh" -//#include "Target.ih" +#include "Target.ih" // Custom includes +#include +#include +#include "ConsoleTarget.hh" +#include "../Console/Console.hh" +#include "../Console/Sysdir.hh" +#include "../membind.hh" //#include "Target.mpp" #define prefix_ @@ -35,20 +41,218 @@ /////////////////////////////////////////////////////////////////////////// // senf::log::Target -prefix_ senf::log::Target::Target() +namespace senf { +namespace log { + + SENF_CONSOLE_REGISTER_ENUM_MEMBER( Target, action_t, (ACCEPT)(REJECT) ); + +namespace detail { + + SENF_CONSOLE_REGISTER_ENUM_MEMBER( TargetRegistry, Level, + (VERBOSE)(NOTICE)(MESSAGE)(IMPORTANT)(CRITICAL)(FATAL) ); + +}}} + +prefix_ senf::log::Target::Target(std::string const & name) { - TargetRegistry::instance().registerTarget(this); + namespace kw = senf::console::kw; + + detail::TargetRegistry::instance().registerTarget(this, name); + consoleDir_().add("list", senf::membind(&Target::consoleList, this)) + .doc("Show routing table\n" + "\n" + "Columns:\n" + " # rule index\n" + " STREAM stream to match, empty to match all streams\n" + " AREA area to match, empty to match all targets\n" + " LEVEL match messages with level above this. Log levels in increasing order\n" + " are:\n" + " verbose, notice, message, important, critical, fatal\n" + " ACTION action to take: accept or reject"); + consoleDir_().add("route", senf::membind(&Target::consoleRoute, this)) + .arg("index", "index at which to insert new rule") + .arg("parameters", "log parameters. The log parameters select the log stream, log area\n" + " and log level. You may specify any combination of these parameterse\n" + " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n" + " to list all valid streams and areas. Valid log levels are:\n" + " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL") + .arg("action", "routing action, one of: ACCEPT, REJECT", + kw::default_value=ACCEPT) + .doc("Add routing entry. Log messages are matched against the routing table beginning\n" + "with the first entry. The action of the first matching entry determines the\n" + "handling of the message.\n" + "\n" + "Examples:\n" + "\n" + " route ()\n" + " route all messages to this target.\n" + "\n" + " route 1 (my::Class)\n" + " route all messages which are in the my::Class area. Insert this route after\n" + " the first route,\n" + "\n" + " route (senf::log::Debug VERBOSE) REJECT\n" + " route (VERBOSE)\n" + " route all messages not in the senf::log::Debug stream to the current area.\n" + "\n" + "The additional optional index argument identifies the position in the routing table\n" + "where the new routing entry will be added. Positive numbers count from the\n" + "beginning, 0 being the first routing entry. Negative values count from the end."); + consoleDir_().add("route", boost::function( + boost::bind(&Target::consoleRoute, this, -1, _1, _2))) + .arg("parameters") + .arg("action", kw::default_value=ACCEPT); + consoleDir_().add("unroute", + senf::membind(static_cast(&Target::unroute), this)) + .arg("index", "index of routing entry to remove") + .overloadDoc("Remove routing entry with the given index"); + consoleDir_().add("unroute", senf::membind(&Target::consoleUnroute, this)) + .arg("parameters", "log parameters. The log parameters select the log stream, log area\n" + " and log level. You may specify any combination of these parameterse\n" + " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n" + " to list all valid streams and areas. Valid log levels are:\n" + " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL") + .arg("action", "routing action, one of: ACCEPT, REJECT", + kw::default_value=ACCEPT) + .overloadDoc("Remove the routing entry matching the specified arguments."); + consoleDir_().add("flush", senf::membind(&Target::flush, this)) + .doc("Remove all routing entries clearing the routing table. This will disable all\n" + "logging output on this target."); } prefix_ senf::log::Target::~Target() { while( ! rib_.empty()) { - // This is terribly slow but simplifies the area cache handling and removing a target should - // be quite seldom + // This is slow but simplifies the area cache handling and removing a target should be + // relatively seldom RIB::reverse_iterator i (rib_.rbegin()); - unroute(i->stream, i->area, i->level, i->action); + unroute(i->stream_, i->area_, i->level_, i->action_); + } + detail::TargetRegistry::instance().unregisterTarget(this); +} + +prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area, + unsigned level, action_t action, int index) +{ + detail::StreamBase const * s (0); + if (! stream.empty()) { + s = StreamRegistry::instance().lookup(stream); + if (!s) + throw InvalidStreamException(); + } + detail::AreaBase const * a (0); + if (! area.empty()) { + a = AreaRegistry::instance().lookup(area); + if (!a) + throw InvalidAreaException(); + } + route(s, a, level, action, index); +} + +prefix_ void senf::log::Target::unroute(std::string const & stream, std::string const & area, + unsigned level, action_t action) +{ + detail::StreamBase const * s (0); + if (! stream.empty()) { + s = StreamRegistry::instance().lookup(stream); + if (!s) + throw InvalidStreamException(); + } + detail::AreaBase const * a (0); + if (! area.empty()) { + a = AreaRegistry::instance().lookup(area); + if (!a) + throw InvalidAreaException(); } - TargetRegistry::instance().unregisterTarget(this); + unroute(s, a, level, action); +} + +prefix_ void senf::log::Target::unroute(int index) +{ + if (rib_.empty()) + return; + RIB::iterator i; + if (index < 0) { + if (RIB::size_type(-index) >= rib_.size()) + i = rib_.begin(); + else { + i = rib_.end(); + std::advance(i, index); + } + } else { + if (RIB::size_type(index+1) >= rib_.size()) { + i = rib_.end(); + --i; + } else { + i = rib_.begin(); + std::advance(i, index); + } + } + if (i == rib_.end()) + return; + RoutingEntry entry (*i); + rib_.erase(i); + if (entry.action_ == ACCEPT) + updateRoutingCache(entry.stream_, entry.area_); +} + +prefix_ void senf::log::Target::flush() +{ + RIB old; + rib_.swap(old); + RIB::const_iterator i (old.begin()); + RIB::const_iterator const i_end (old.end()); + for (; i != i_end; ++i) + if (i->action_ == ACCEPT) + updateRoutingCache(i->stream_, i->area_); +} + +//////////////////////////////////////// +// protected members + +prefix_ senf::console::ScopedDirectory<> & senf::log::Target::consoleDir() +{ + return consoleDir_(); +} + +//////////////////////////////////////// +// private members + +prefix_ void senf::log::Target::route(detail::StreamBase const * stream, + detail::AreaBase const * area, unsigned level, + action_t action, int index) +{ + RIB::iterator i; + if (index < 0) { + if (RIB::size_type(-index-1) >= rib_.size()) + i = rib_.begin(); + else { + i = rib_.end(); + std::advance(i, index + 1 ); + } + } else { + if (RIB::size_type(index) >= rib_.size()) + i = rib_.end(); + else { + i = rib_.begin(); + std::advance(i, index); + } + } + rib_.insert(i, RoutingEntry(stream, area, level, action)); + if (action == ACCEPT) + updateRoutingCache(stream, area); + // This disables the initial fallback routing + detail::TargetRegistry::instance().routed(); +} + +prefix_ void senf::log::Target::unroute(detail::StreamBase const * stream, + detail::AreaBase const * area, unsigned level, + action_t action) +{ + RIB::iterator i = std::find(rib_.begin(), rib_.end(), + RoutingEntry(stream, area, level, action)); + if (i != rib_.end()) + unroute(std::distance(rib_.begin(), i)); } prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * stream, @@ -72,10 +276,10 @@ prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * st 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 ( (! i->stream_ || i->stream_ == stream) && + (! i->area_ || i->area_ == area) && + i->action_ == ACCEPT ) { + unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_); if (l < limit) limit = l; } @@ -85,7 +289,7 @@ prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * st area->updateRoutingCache(*this, *stream, limit); } -prefix_ void senf::log::Target::write(boost::posix_time::ptime timestamp, +prefix_ void senf::log::Target::write(time_type timestamp, detail::StreamBase const & stream, detail::AreaBase const & area, unsigned level, std::string const & message) @@ -93,31 +297,265 @@ prefix_ void senf::log::Target::write(boost::posix_time::ptime timestamp, 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->level == NONE::value ? i->stream->defaultRuntimeLimit() : i->level) <= level ) { - if (i->action == ACCEPT) + if ( (! i->stream_ || i->stream_ == &stream) && + (! i->area_ || i->area_ == &area) && + (i->level_ == NONE::value ? stream.defaultRuntimeLimit() : i->level_) <= level ) { + if (i->action_ == ACCEPT) v_write(timestamp, stream.v_name(), area.v_name(), level, message); return; } } +namespace { + std::string formatLabel(std::string const & l) + { + if (l.empty()) + return "-"; + if (l.size() > 29) + return l.substr(l.size()-29); + return l; + } +} + +prefix_ void senf::log::Target::consoleList(std::ostream & os) +{ + static char const * levels[] = { + "none", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" }; + + boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n"); + os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION"; + unsigned n (0); + for (iterator i (begin()); i != end(); ++i, ++n) + os << fmt + % n + % formatLabel(i->stream()) + % formatLabel(i->area()) + % levels[i->level()] + % (i->action() == ACCEPT ? "accept" : "reject"); +} + +prefix_ void senf::log::Target::consoleRoute(int index, detail::LogParameters const & pm, action_t action) +{ + route(pm.stream, pm.area, pm.level, action, index); +} + +prefix_ void senf::log::Target::consoleUnroute(detail::LogParameters const & pm, action_t action) +{ + unroute(pm.stream, pm.area, pm.level, action); +} + /////////////////////////////////////////////////////////////////////////// -// senf::log::TargetRegistry +// senf::log::detail::TargetRegistry + +prefix_ void senf::log::detail::TargetRegistry::dynamicTarget(std::auto_ptr target) +{ + target->consoleDir().add("remove", boost::function( + boost::bind( + &TargetRegistry::consoleRemoveTarget, this, target.get()))) + .doc("Remove target."); + dynamicTargets_.insert(target.release()); +} -prefix_ void senf::log::TargetRegistry::write(detail::StreamBase const & stream, - detail::AreaBase const & area, unsigned level, - std::string msg) +prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target, + std::string const & name) { - boost::posix_time::ptime timestamp (boost::posix_time::microsec_clock::universal_time()); - area.write(timestamp, stream, level, msg); + targets_.insert(target); + consoleDir_().add(name, target->consoleDir_()); } +prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream, + AreaBase const & area, unsigned level, + std::string const & msg) +{ + if (fallbackRouting_) { + if (level >= stream.defaultRuntimeLimit()) + static_cast(ConsoleTarget::instance()).v_write( + TimeSource::now(), stream.v_name(), area.v_name(), level, msg ); + } + else + area.write( TimeSource::now(), stream, level, msg ); +} + +prefix_ void senf::log::detail::TargetRegistry::consoleRemoveTarget(Target * target) +{ + dynamicTargets_.erase(target); + delete target; +} + +prefix_ senf::log::detail::TargetRegistry::TargetRegistry() + : fallbackRouting_(true) +{ + namespace kw = senf::console::kw; + + console::sysdir().add("log", consoleDir_()); + consoleDir_().add("areas", senf::membind(&TargetRegistry::consoleAreas, this)) + .doc("List all areas"); + consoleDir_().add("streams", senf::membind(&TargetRegistry::consoleStreams, this)) + .doc("List all streams"); + consoleDir_().add("message", senf::membind(&TargetRegistry::consoleWrite, this)) + .arg("parameters", "log parameters. The log parameters select the log stream, log area\n" + " and log level. You may specify any combination of these parameterse\n" + " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n" + " to list all valid streams and areas. Valid log levels are:\n" + " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL", + kw::default_value = LogParameters::defaultParameters()) + .arg("message", "message to write") + .doc("Write log message.\n" + "\n" + "Examples:\n" + " message \"Test\";\n" + " message (senf::log::DefaultArea NOTICE) \"Test notice\";\n" + " message (FATAL) \"Program on fire\";\n" + " message (VERBOSE senf::log::Debug) \"Debug message\";"); +} + +prefix_ senf::log::detail::TargetRegistry::~TargetRegistry() +{ + Targets::iterator i (dynamicTargets_.begin()); + Targets::iterator const i_end (dynamicTargets_.end()); + for (; i != i_end; ++i) + delete *i; +} + +prefix_ void senf::log::detail::TargetRegistry::consoleAreas(std::ostream & os) +{ + AreaRegistry::iterator i (AreaRegistry::instance().begin()); + AreaRegistry::iterator const i_end (AreaRegistry::instance().end()); + for (; i != i_end; ++i) + os << *i << "\n"; +} + +prefix_ void senf::log::detail::TargetRegistry::consoleStreams(std::ostream & os) +{ + StreamRegistry::iterator i (StreamRegistry::instance().begin()); + StreamRegistry::iterator const i_end (StreamRegistry::instance().end()); + for (; i != i_end; ++i) + os << *i << "\n"; +} + +prefix_ void senf::log::detail::TargetRegistry::consoleWrite(LogParameters pm, + std::string const & msg) +{ + pm.setDefaults(); + write(*pm.stream, *pm.area, pm.level, msg); +} + +/////////////////////////////////////////////////////////////////////////// +// senf::log::detail::LogParameters + +prefix_ void senf::log::detail::LogParameters::clear() +{ + stream = 0; + area = 0; + level = NONE::value; +} + +prefix_ void senf::log::detail::LogParameters::setDefaults() +{ + if (! stream) + stream = & senf::log::Debug::instance(); + if (! area) + area = & senf::log::DefaultArea::instance(); + if (level == NONE::value) + level = MESSAGE::value; +} + +prefix_ senf::log::detail::LogParameters::LogParameters +senf::log::detail::LogParameters::defaultParameters() +{ + LogParameters pm; + pm.clear(); + pm.setDefaults(); + return pm; +} + +/////////////////////////////////////////////////////////////////////////// +// namespace members + +prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action) +{ + if( action == Target::ACCEPT) os << "ACCEPT"; + else if( action == Target::REJECT) os << "REJECT"; + else os << "unknown action"; + return os; +} + +namespace { + + char const * levelNames[] = { + "NONE", "VERBOSE", "NOTICE", "MESSAGE", "IMPORTANT", "CRITICAL", "FATAL", "DISABLED" }; + + void parseParamToken(std::string const & value, senf::log::detail::LogParameters & out) + { + senf::log::detail::StreamBase const * s ( + senf::log::StreamRegistry::instance().lookup(value)); + if (s) { + if (out.stream) + throw senf::console::SyntaxErrorException("duplicate stream parameter"); + out.stream = s; + return; + } + + senf::log::detail::AreaBase const * a ( + senf::log::AreaRegistry::instance().lookup(value)); + if (a) { + if (out.area) + throw senf::console::SyntaxErrorException("duplicate area parameter"); + out.area = a; + return; + } + + char const ** i ( + std::find(levelNames+1, levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1, value)); + if (i == levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1) + throw senf::console::SyntaxErrorException("invalid log parameter"); + if (out.level != senf::log::NONE::value) + throw senf::console::SyntaxErrorException("duplicate level parameter"); + out.level = i-levelNames; + } + +} + +prefix_ std::ostream & senf::log::detail::operator<<(std::ostream & os, + LogParameters const & pm) +{ + os << '('; + if (pm.stream) + os << pm.stream->v_name(); + if (pm.area) + if (pm.stream) os << ' '; + os << pm.area->v_name(); + if (pm.level != NONE::value) + if (pm.stream || pm.area) os << ' '; + os << levelNames[pm.level]; + os << ')'; + return os; +} + +prefix_ void senf::log::detail:: +senf_console_parse_argument(console::ParseCommandInfo::TokensRange const & tokens, + LogParameters & out) +{ + out.clear(); + + for (console::ParseCommandInfo::TokensRange::iterator i (tokens.begin()); + i != tokens.end(); ++i) + parseParamToken(i->value(), out); +} + +////////////////////////////////////////////////////////////////////////// +// I need to put this here, otherwise the file target will not be registered +// if it is not used ... :-( + +senf::log::FileTarget::RegisterConsole senf::log::FileTarget::RegisterConsole::instance; +senf::log::SyslogTarget::RegisterConsole senf::log::SyslogTarget::RegisterConsole::instance; +senf::log::SyslogUDPTarget::RegisterConsole senf::log::SyslogUDPTarget::RegisterConsole::instance; + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ //#include "Target.mpp" - + // Local Variables: // mode: c++ // fill-column: 100