X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Utils%2FLogger%2FTarget.cc;h=ca0574912d4d519d21708b89bd5e12ef28cd3898;hb=1a02a61e1e1515dca27577013cc7300ea5133fd5;hp=91d231e98ed78fb25c0b9357e541cc8e57b0ac1e;hpb=d0776a27ffd63ab51b4e3419a8a6f87d11e60594;p=senf.git diff --git a/Utils/Logger/Target.cc b/Utils/Logger/Target.cc index 91d231e..ca05749 100644 --- a/Utils/Logger/Target.cc +++ b/Utils/Logger/Target.cc @@ -28,7 +28,11 @@ // Custom includes #include +#include #include "ConsoleTarget.hh" +#include "../Console/Console.hh" +#include "../Console/Sysdir.hh" +#include "../membind.hh" //#include "Target.mpp" #define prefix_ @@ -37,9 +41,83 @@ /////////////////////////////////////////////////////////////////////////// // 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) { - detail::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() @@ -56,9 +134,12 @@ prefix_ senf::log::Target::~Target() 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 (StreamRegistry::instance().lookup(stream)); - if (!s) - throw InvalidStreamException(); + 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); @@ -71,9 +152,12 @@ prefix_ void senf::log::Target::route(std::string const & stream, std::string co prefix_ void senf::log::Target::unroute(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::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); @@ -85,6 +169,8 @@ prefix_ void senf::log::Target::unroute(std::string const & stream, std::string 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()) @@ -110,6 +196,25 @@ prefix_ void senf::log::Target::unroute(int index) 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 @@ -141,10 +246,10 @@ prefix_ void senf::log::Target::route(detail::StreamBase const * stream, } 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::iterator i = std::find(rib_.begin(), rib_.end(), + RIB::iterator i = std::find(rib_.begin(), rib_.end(), RoutingEntry(stream, area, level, action)); if (i != rib_.end()) unroute(std::distance(rib_.begin(), i)); @@ -174,7 +279,7 @@ prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * st 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_); + unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_); if (l < limit) limit = l; } @@ -184,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) @@ -194,49 +299,263 @@ prefix_ void senf::log::Target::write(boost::posix_time::ptime timestamp, 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 ) { + (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::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::detail::TargetRegistry::registerTarget(Target * target, + std::string const & name) +{ + 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 msg) + std::string const & msg) { if (fallbackRouting_) { if (level >= stream.defaultRuntimeLimit()) - static_cast(ConsoleTarget::instance()).v_write( - (*timeSource_)(), stream.v_name(), area.v_name(), level, msg ); + static_cast(ConsoleTarget::instance()).v_write( + TimeSource::now(), stream.v_name(), area.v_name(), level, msg ); } else - area.write( (*timeSource_)(), stream, level, msg ); + 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::TimeSource +// senf::log::detail::LogParameters -prefix_ senf::log::TimeSource::~TimeSource() -{} +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; +} /////////////////////////////////////////////////////////////////////////// -// senf::log::SystemTimeSource +// namespace members -prefix_ boost::posix_time::ptime senf::log::SystemTimeSource::operator()() - const +prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action) { - return boost::posix_time::microsec_clock::universal_time(); + 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