X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Utils%2FLogger%2FTarget.cc;h=ca0574912d4d519d21708b89bd5e12ef28cd3898;hb=1a02a61e1e1515dca27577013cc7300ea5133fd5;hp=068631c7df3e5cbbd7d4778d33c7441f422437f2;hpb=5bf459d443ab7cef04116bc0cb95e1af0178334f;p=senf.git diff --git a/Utils/Logger/Target.cc b/Utils/Logger/Target.cc index 068631c..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); @@ -124,6 +208,14 @@ prefix_ void senf::log::Target::flush() } //////////////////////////////////////// +// protected members + +prefix_ senf::console::ScopedDirectory<> & senf::log::Target::consoleDir() +{ + return consoleDir_(); +} + +//////////////////////////////////////// // private members prefix_ void senf::log::Target::route(detail::StreamBase const * stream, @@ -214,9 +306,63 @@ prefix_ void senf::log::Target::write(time_type timestamp, } } +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 const & msg) @@ -229,6 +375,100 @@ prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream, 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 @@ -240,6 +480,76 @@ prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Targe 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_