00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00026 #include "Target.hh"
00027 #include "Target.ih"
00028
00029
00030 #include <algorithm>
00031 #include <boost/format.hpp>
00032 #include "ConsoleTarget.hh"
00033 #include <senf/Utils/Console/Console.hh>
00034
00035
00036 #define prefix_
00037
00038
00039
00040
00041
00042 namespace senf {
00043 namespace log {
00044
00045 SENF_CONSOLE_REGISTER_ENUM_MEMBER( Target, action_t, (ACCEPT)(REJECT) );
00046
00047 namespace detail {
00048
00049 SENF_CONSOLE_REGISTER_ENUM_MEMBER( TargetRegistry, Level,
00050 (VERBOSE)(NOTICE)(MESSAGE)(IMPORTANT)(CRITICAL)(FATAL) );
00051
00052 }}}
00053
00054 prefix_ senf::log::Target::Target(std::string const & name)
00055 {
00056 namespace kw = console::kw;
00057 namespace fty = console::factory;
00058
00059 detail::TargetRegistry::instance().registerTarget(this, name);
00060 consoleDir_()
00061 .add("list", fty::Command(&Target::consoleList, this)
00062 .doc("Show routing table\n"
00063 "\n"
00064 "Columns:\n"
00065 " # rule index\n"
00066 " STREAM stream to match, empty to match all streams\n"
00067 " AREA area to match, empty to match all targets\n"
00068 " LEVEL match messages with level above this. Log levels in increasing order\n"
00069 " are:\n"
00070 " verbose, notice, message, important, critical, fatal\n"
00071 " If the log level is listed as 'default', the streams default limit\n"
00072 " applies.\n"
00073 " ACTION action to take: accept or reject") );
00074 consoleDir_()
00075 .add("route", fty::Command(&Target::consoleRoute, this)
00076 .arg("index", "index at which to insert new rule")
00077 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
00078 " and log level. You may specify any combination of these parameters\n"
00079 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
00080 " to list all valid streams and areas. Valid log levels are:\n"
00081 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL")
00082 .arg("action", "routing action, one of: ACCEPT, REJECT",
00083 kw::default_value=ACCEPT)
00084 .doc("Add routing entry. Log messages are matched against the routing table beginning\n"
00085 "with the first entry. The action of the first matching entry determines the\n"
00086 "handling of the message.\n"
00087 "\n"
00088 "Examples:\n"
00089 "\n"
00090 " route ()\n"
00091 " route all messages with level above each streams default log limit to this\n"
00092 " target.\n"
00093 "\n"
00094 " route 1 (my::Class VERBOSE)\n"
00095 " route all messages which are in the my::Class area. Insert this route after\n"
00096 " the first route,\n"
00097 "\n"
00098 " route (senf::log::Debug VERBOSE) REJECT\n"
00099 " route (VERBOSE)\n"
00100 " route all messages not in the senf::log::Debug stream to the current area.\n"
00101 "\n"
00102 "The additional optional index argument identifies the position in the routing table\n"
00103 "where the new routing entry will be added. Positive numbers count from the\n"
00104 "beginning, 0 being the first routing entry. Negative values count from the end.") );
00105 consoleDir_()
00106 .add("route", fty::Command<void (detail::LogParameters, action_t)>(
00107 boost::bind(&Target::consoleRoute, this, -1, _1, _2))
00108 .arg("parameters")
00109 .arg("action", kw::default_value=ACCEPT) );
00110 consoleDir_()
00111 .add("unroute",
00112 fty::Command(static_cast<void (Target::*)(int)>(&Target::unroute), this)
00113 .arg("index", "index of routing entry to remove")
00114 .overloadDoc("Remove routing entry with the given index") );
00115 consoleDir_()
00116 .add("unroute", fty::Command(&Target::consoleUnroute, this)
00117 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
00118 " and log level. You may specify any combination of these parameters\n"
00119 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
00120 " to list all valid streams and areas. Valid log levels are:\n"
00121 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL")
00122 .arg("action", "routing action, one of: ACCEPT, REJECT",
00123 kw::default_value=ACCEPT)
00124 .overloadDoc("Remove the routing entry matching the specified arguments.") );
00125 consoleDir_()
00126 .add("flush", fty::Command(&Target::flush, this)
00127 .doc("Remove all routing entries clearing the routing table. This will disable all\n"
00128 "logging output on this target.") );
00129 }
00130
00131 prefix_ senf::log::Target::~Target()
00132 {
00133 while( ! rib_.empty()) {
00134
00135
00136 RIB::reverse_iterator i (rib_.rbegin());
00137 unroute(i->stream_, i->area_, i->level_, i->action_);
00138 }
00139 detail::TargetRegistry::instance().unregisterTarget(this);
00140 }
00141
00142 prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
00143 unsigned level, action_t action, int index)
00144 {
00145 detail::StreamBase const * s (0);
00146 if (! stream.empty()) {
00147 s = StreamRegistry::instance().lookup(stream);
00148 if (!s)
00149 throw InvalidStreamException();
00150 }
00151 detail::AreaBase const * a (0);
00152 if (! area.empty()) {
00153 a = AreaRegistry::instance().lookup(area);
00154 if (!a)
00155 throw InvalidAreaException();
00156 }
00157 route(s, a, level, action, index);
00158 }
00159
00160 prefix_ void senf::log::Target::unroute(std::string const & stream, std::string const & area,
00161 unsigned level, action_t action)
00162 {
00163 detail::StreamBase const * s (0);
00164 if (! stream.empty()) {
00165 s = StreamRegistry::instance().lookup(stream);
00166 if (!s)
00167 throw InvalidStreamException();
00168 }
00169 detail::AreaBase const * a (0);
00170 if (! area.empty()) {
00171 a = AreaRegistry::instance().lookup(area);
00172 if (!a)
00173 throw InvalidAreaException();
00174 }
00175 unroute(s, a, level, action);
00176 }
00177
00178 prefix_ void senf::log::Target::unroute(int index)
00179 {
00180 if (rib_.empty())
00181 return;
00182 RIB::iterator i;
00183 if (index < 0) {
00184 if (RIB::size_type(-index) >= rib_.size())
00185 i = rib_.begin();
00186 else {
00187 i = rib_.end();
00188 std::advance(i, index);
00189 }
00190 } else {
00191 if (RIB::size_type(index+1) >= rib_.size()) {
00192 i = rib_.end();
00193 --i;
00194 } else {
00195 i = rib_.begin();
00196 std::advance(i, index);
00197 }
00198 }
00199 if (i == rib_.end())
00200 return;
00201 RoutingEntry entry (*i);
00202 rib_.erase(i);
00203 if (entry.action_ == ACCEPT)
00204 updateRoutingCache(entry.stream_, entry.area_);
00205 }
00206
00207 prefix_ void senf::log::Target::flush()
00208 {
00209 RIB old;
00210 rib_.swap(old);
00211 RIB::const_iterator i (old.begin());
00212 RIB::const_iterator const i_end (old.end());
00213 for (; i != i_end; ++i)
00214 if (i->action_ == ACCEPT)
00215 updateRoutingCache(i->stream_, i->area_);
00216 }
00217
00218
00219
00220
00221 prefix_ senf::console::ScopedDirectory<> & senf::log::Target::consoleDir()
00222 {
00223 return consoleDir_();
00224 }
00225
00226
00227
00228
00229 prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
00230 detail::AreaBase const * area, unsigned level,
00231 action_t action, int index)
00232 {
00233 RIB::iterator i;
00234 if (index < 0) {
00235 if (RIB::size_type(-index-1) >= rib_.size())
00236 i = rib_.begin();
00237 else {
00238 i = rib_.end();
00239 std::advance(i, index + 1 );
00240 }
00241 } else {
00242 if (RIB::size_type(index) >= rib_.size())
00243 i = rib_.end();
00244 else {
00245 i = rib_.begin();
00246 std::advance(i, index);
00247 }
00248 }
00249 rib_.insert(i, RoutingEntry(stream, area, level, action));
00250 if (action == ACCEPT)
00251 updateRoutingCache(stream, area);
00252
00253 detail::TargetRegistry::instance().routed();
00254 }
00255
00256 prefix_ void senf::log::Target::unroute(detail::StreamBase const * stream,
00257 detail::AreaBase const * area, unsigned level,
00258 action_t action)
00259 {
00260 RIB::iterator i = std::find(rib_.begin(), rib_.end(),
00261 RoutingEntry(stream, area, level, action));
00262 if (i != rib_.end())
00263 unroute(std::distance(rib_.begin(), i));
00264 }
00265
00266 prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * stream,
00267 detail::AreaBase const * area)
00268 {
00269 if (! stream) {
00270 StreamRegistry::Registry::iterator i (StreamRegistry::instance().registry_.begin());
00271 StreamRegistry::Registry::iterator const i_end (StreamRegistry::instance().registry_.end());
00272 for (; i != i_end ; ++i)
00273 updateRoutingCache(i->second, area);
00274 return;
00275 }
00276 if (! area) {
00277 AreaRegistry::Registry::iterator i (AreaRegistry::instance().registry_.begin());
00278 AreaRegistry::Registry::iterator const i_end (AreaRegistry::instance().registry_.end());
00279 for (; i != i_end ; ++i)
00280 updateRoutingCache(stream, i->second);
00281 return;
00282 }
00283 if (! area->alive())
00284
00285 return;
00286 unsigned limit (DISABLED::value);
00287 RIB::iterator i (rib_.begin());
00288 RIB::iterator const i_end (rib_.end());
00289 for (; i != i_end; ++i)
00290 if ( (! i->stream_ || i->stream_ == stream) &&
00291 (! i->area_ || i->area_ == area) &&
00292 i->action_ == ACCEPT ) {
00293 unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_);
00294 if (l < limit)
00295 limit = l;
00296 }
00297 if (limit == DISABLED::value)
00298 area->removeRoutingCache(*this, *stream);
00299 else
00300 area->updateRoutingCache(*this, *stream, limit);
00301 }
00302
00303 prefix_ void senf::log::Target::write(time_type timestamp,
00304 detail::StreamBase const & stream,
00305 detail::AreaBase const & area, unsigned level,
00306 std::string const & message)
00307 {
00308 RIB::iterator i (rib_.begin());
00309 RIB::iterator const i_end (rib_.end());
00310 for (; i != i_end; ++i)
00311 if ( (! i->stream_ || i->stream_ == &stream) &&
00312 (! i->area_ || i->area_ == &area) &&
00313 (i->level_ == NONE::value ? stream.defaultRuntimeLimit() : i->level_) <= level ) {
00314 if (i->action_ == ACCEPT)
00315 v_write(timestamp, stream.v_name(), area.v_name(), level, message);
00316 return;
00317 }
00318 }
00319
00320 namespace {
00321 std::string formatLabel(std::string const & l)
00322 {
00323 if (l.empty())
00324 return "*";
00325 if (l.size() > 29)
00326 return l.substr(l.size()-29);
00327 return l;
00328 }
00329
00330 char const * levelNames[] = {
00331 "NONE", "VERBOSE", "NOTICE", "MESSAGE", "IMPORTANT", "CRITICAL", "FATAL", "DISABLED" };
00332
00333 char const * levelNamesList[] = {
00334 "default", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" };
00335 }
00336
00337 prefix_ void senf::log::Target::consoleList(std::ostream & os)
00338 {
00339
00340 boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n");
00341 os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION";
00342 unsigned n (0);
00343 for (iterator i (begin()); i != end(); ++i, ++n)
00344 os << fmt
00345 % n
00346 % formatLabel(i->stream())
00347 % formatLabel(i->area())
00348 % levelNamesList[i->level()]
00349 % (i->action() == ACCEPT ? "accept" : "reject");
00350 }
00351
00352 prefix_ void senf::log::Target::consoleRoute(int index, detail::LogParameters const & pm, action_t action)
00353 {
00354 route(pm.stream, pm.area, pm.level, action, index);
00355 }
00356
00357 prefix_ void senf::log::Target::consoleUnroute(detail::LogParameters const & pm, action_t action)
00358 {
00359 unroute(pm.stream, pm.area, pm.level, action);
00360 }
00361
00362
00363
00364
00365 prefix_ void senf::log::detail::TargetRegistry::dynamicTarget(std::auto_ptr<Target> target)
00366 {
00367 namespace fty = console::factory;
00368
00369 target->consoleDir()
00370 .add("remove", fty::Command<void ()>(
00371 boost::bind(&TargetRegistry::consoleRemoveTarget, this, target.get()))
00372 .doc("Remove target.") );
00373 dynamicTargets_.insert(target.release());
00374 }
00375
00376 prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target,
00377 std::string const & name)
00378 {
00379 targets_.insert(target);
00380 consoleDir_().add(name, target->consoleDir_());
00381 }
00382
00383 prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
00384 AreaBase const & area, unsigned level,
00385 std::string const & msg)
00386 {
00387 if (fallbackRouting_) {
00388 if (level >= stream.defaultRuntimeLimit())
00389 static_cast<Target &>(ConsoleTarget::instance()).v_write(
00390 TimeSource::now(), stream.v_name(), area.v_name(), level, msg );
00391 }
00392 else
00393 area.write( TimeSource::now(), stream, level, msg );
00394 }
00395
00396 prefix_ void senf::log::detail::TargetRegistry::consoleRemoveTarget(Target * target)
00397 {
00398 dynamicTargets_.erase(target);
00399 delete target;
00400 }
00401
00402 prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
00403 : fallbackRouting_(true)
00404 {
00405 namespace kw = console::kw;
00406 namespace fty = console::factory;
00407
00408 console::sysdir().add("log", consoleDir_());
00409 consoleDir_()
00410 .add("areas", fty::Command(&TargetRegistry::consoleAreas, this)
00411 .doc("List all areas") );
00412 consoleDir_()
00413 .add("streams", fty::Command(&TargetRegistry::consoleStreams, this)
00414 .doc("List all streams with the streams default runtime log level limit.") );
00415 consoleDir_()
00416 .add("message", fty::Command(&TargetRegistry::consoleWrite, this)
00417 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
00418 " and log level. You may specify any combination of these parameters\n"
00419 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
00420 " to list all valid streams and areas. Valid log levels are:\n"
00421 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL",
00422 kw::default_value = LogParameters::defaultParameters())
00423 .arg("message", "message to write")
00424 .doc("Write log message.\n"
00425 "\n"
00426 "Examples:\n"
00427 " message \"Test\";\n"
00428 " message (senf::log::DefaultArea NOTICE) \"Test notice\";\n"
00429 " message (FATAL) \"Program on fire\";\n"
00430 " message (VERBOSE senf::log::Debug) \"Debug message\";") );
00431 consoleDir_()
00432 .add("self", fty::Command(&TargetRegistry::consoleSelf, this)
00433 .doc("Get the log directory of the current network client. Example usage:\n"
00434 "\n"
00435 "Just get the log config directory\n"
00436 " $ /sys/log/self\n"
00437 " <Directory '/sys/log/client-xxx.xxx.xxx.xxx:xxx'>\n"
00438 "\n"
00439 "Route all messages to the currently connected client\n"
00440 " $ /sys/log/self { route () ); }") );
00441 }
00442
00443 prefix_ senf::log::detail::TargetRegistry::~TargetRegistry()
00444 {
00445 Targets::iterator i (dynamicTargets_.begin());
00446 Targets::iterator const i_end (dynamicTargets_.end());
00447 for (; i != i_end; ++i)
00448 delete *i;
00449 }
00450
00451 prefix_ void senf::log::detail::TargetRegistry::consoleAreas(std::ostream & os)
00452 {
00453 AreaRegistry::iterator i (AreaRegistry::instance().begin());
00454 AreaRegistry::iterator const i_end (AreaRegistry::instance().end());
00455 for (; i != i_end; ++i)
00456 os << *i << "\n";
00457 }
00458
00459 prefix_ void senf::log::detail::TargetRegistry::consoleStreams(std::ostream & os)
00460 {
00461 StreamRegistry::iterator i (StreamRegistry::instance().begin());
00462 StreamRegistry::iterator const i_end (StreamRegistry::instance().end());
00463 for (; i != i_end; ++i) {
00464 os << *i << " "
00465 << levelNames[StreamRegistry::instance().lookup(*i)->defaultRuntimeLimit()] << "\n";
00466 }
00467 }
00468
00469 prefix_ void senf::log::detail::TargetRegistry::consoleWrite(LogParameters pm,
00470 std::string const & msg)
00471 {
00472 pm.setDefaults();
00473 write(*pm.stream, *pm.area, pm.level, msg);
00474 }
00475
00476 prefix_ boost::shared_ptr<senf::console::DirectoryNode>
00477 senf::log::detail::TargetRegistry::consoleSelf(std::ostream & os)
00478 {
00479 return senf::console::Client::get(os).consoleDir().node().thisptr();
00480 }
00481
00482
00483
00484
00485 prefix_ void senf::log::detail::LogParameters::clear()
00486 {
00487 stream = 0;
00488 area = 0;
00489 level = NONE::value;
00490 }
00491
00492 prefix_ void senf::log::detail::LogParameters::setDefaults()
00493 {
00494 if (! stream)
00495 stream = & senf::log::Debug::instance();
00496 if (! area)
00497 area = & senf::log::DefaultArea::instance();
00498 if (level == NONE::value)
00499 level = MESSAGE::value;
00500 }
00501
00502 prefix_ senf::log::detail::LogParameters senf::log::detail::LogParameters::defaultParameters()
00503 {
00504 LogParameters pm;
00505 pm.clear();
00506 pm.setDefaults();
00507 return pm;
00508 }
00509
00510
00511
00512
00513 prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action)
00514 {
00515 if (action == Target::ACCEPT) os << "ACCEPT";
00516 else if (action == Target::REJECT) os << "REJECT";
00517 else os << "unknown action";
00518 return os;
00519 }
00520
00521 namespace {
00522
00523 void parseParamToken(std::string const & value, senf::log::detail::LogParameters & out)
00524 {
00525 senf::log::detail::StreamBase const * s (
00526 senf::log::StreamRegistry::instance().lookup(value));
00527 if (s) {
00528 if (out.stream)
00529 throw senf::console::SyntaxErrorException("duplicate stream parameter");
00530 out.stream = s;
00531 return;
00532 }
00533
00534 senf::log::detail::AreaBase const * a (
00535 senf::log::AreaRegistry::instance().lookup(value));
00536 if (a) {
00537 if (out.area)
00538 throw senf::console::SyntaxErrorException("duplicate area parameter");
00539 out.area = a;
00540 return;
00541 }
00542
00543 char const ** i (
00544 std::find(levelNames+1, levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1, value));
00545 if (i == levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1)
00546 throw senf::console::SyntaxErrorException("invalid log parameter");
00547 if (out.level != senf::log::NONE::value)
00548 throw senf::console::SyntaxErrorException("duplicate level parameter");
00549 out.level = i-levelNames;
00550 }
00551
00552 }
00553
00554 prefix_ std::ostream & senf::log::detail::operator<<(std::ostream & os,
00555 LogParameters const & pm)
00556 {
00557 os << '(';
00558 if (pm.stream)
00559 os << pm.stream->v_name();
00560 if (pm.area)
00561 if (pm.stream) os << ' ';
00562 os << pm.area->v_name();
00563 if (pm.level != NONE::value)
00564 if (pm.stream || pm.area) os << ' ';
00565 os << levelNames[pm.level];
00566 os << ')';
00567 return os;
00568 }
00569
00570 prefix_ void senf::log::detail::
00571 senf_console_parse_argument(console::ParseCommandInfo::TokensRange const & tokens,
00572 LogParameters & out)
00573 {
00574 out.clear();
00575
00576 for (console::ParseCommandInfo::TokensRange::iterator i (tokens.begin());
00577 i != tokens.end(); ++i)
00578 parseParamToken(i->value(), out);
00579 }
00580
00581
00582
00583
00584
00585 senf::log::FileTarget::RegisterConsole senf::log::FileTarget::RegisterConsole::instance;
00586 senf::log::SyslogTarget::RegisterConsole senf::log::SyslogTarget::RegisterConsole::instance;
00587 senf::log::SyslogUDPTarget::RegisterConsole senf::log::SyslogUDPTarget::RegisterConsole::instance;
00588
00589
00590 #undef prefix_
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602