4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief Target non-inline non-template implementation */
31 #include <boost/format.hpp>
32 #include "ConsoleTarget.hh"
33 #include <senf/Utils/Console/Console.hh>
34 #include <senf/Utils/Console/Sysdir.hh>
35 #include <senf/Utils/membind.hh>
37 //#include "Target.mpp"
39 ///////////////////////////////cc.p////////////////////////////////////////
41 ///////////////////////////////////////////////////////////////////////////
47 SENF_CONSOLE_REGISTER_ENUM_MEMBER( Target, action_t, (ACCEPT)(REJECT) );
51 SENF_CONSOLE_REGISTER_ENUM_MEMBER( TargetRegistry, Level,
52 (VERBOSE)(NOTICE)(MESSAGE)(IMPORTANT)(CRITICAL)(FATAL) );
56 prefix_ senf::log::Target::Target(std::string const & name)
58 namespace kw = senf::console::kw;
59 namespace fty = senf::console::factory;
61 detail::TargetRegistry::instance().registerTarget(this, name);
63 .add("list", fty::Command(&Target::consoleList, this)
64 .doc("Show routing table\n"
68 " STREAM stream to match, empty to match all streams\n"
69 " AREA area to match, empty to match all targets\n"
70 " LEVEL match messages with level above this. Log levels in increasing order\n"
72 " verbose, notice, message, important, critical, fatal\n"
73 " ACTION action to take: accept or reject") );
75 .add("route", fty::Command(&Target::consoleRoute, this)
76 .arg("index", "index at which to insert new rule")
77 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
78 " and log level. You may specify any combination of these parameterse\n"
79 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
80 " to list all valid streams and areas. Valid log levels are:\n"
81 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL")
82 .arg("action", "routing action, one of: ACCEPT, REJECT",
83 kw::default_value=ACCEPT)
84 .doc("Add routing entry. Log messages are matched against the routing table beginning\n"
85 "with the first entry. The action of the first matching entry determines the\n"
86 "handling of the message.\n"
91 " route all messages to this target.\n"
93 " route 1 (my::Class)\n"
94 " route all messages which are in the my::Class area. Insert this route after\n"
97 " route (senf::log::Debug VERBOSE) REJECT\n"
99 " route all messages not in the senf::log::Debug stream to the current area.\n"
101 "The additional optional index argument identifies the position in the routing table\n"
102 "where the new routing entry will be added. Positive numbers count from the\n"
103 "beginning, 0 being the first routing entry. Negative values count from the end.") );
105 .add("route", fty::Command<void (detail::LogParameters, action_t)>(
106 boost::bind(&Target::consoleRoute, this, -1, _1, _2))
108 .arg("action", kw::default_value=ACCEPT) );
111 fty::Command(static_cast<void (Target::*)(int)>(&Target::unroute), this)
112 .arg("index", "index of routing entry to remove")
113 .overloadDoc("Remove routing entry with the given index") );
115 .add("unroute", fty::Command(&Target::consoleUnroute, this)
116 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
117 " and log level. You may specify any combination of these parameterse\n"
118 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
119 " to list all valid streams and areas. Valid log levels are:\n"
120 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL")
121 .arg("action", "routing action, one of: ACCEPT, REJECT",
122 kw::default_value=ACCEPT)
123 .overloadDoc("Remove the routing entry matching the specified arguments.") );
125 .add("flush", fty::Command(&Target::flush, this)
126 .doc("Remove all routing entries clearing the routing table. This will disable all\n"
127 "logging output on this target.") );
130 prefix_ senf::log::Target::~Target()
132 while( ! rib_.empty()) {
133 // This is slow but simplifies the area cache handling and removing a target should be
135 RIB::reverse_iterator i (rib_.rbegin());
136 unroute(i->stream_, i->area_, i->level_, i->action_);
138 detail::TargetRegistry::instance().unregisterTarget(this);
141 prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
142 unsigned level, action_t action, int index)
144 detail::StreamBase const * s (0);
145 if (! stream.empty()) {
146 s = StreamRegistry::instance().lookup(stream);
148 throw InvalidStreamException();
150 detail::AreaBase const * a (0);
151 if (! area.empty()) {
152 a = AreaRegistry::instance().lookup(area);
154 throw InvalidAreaException();
156 route(s, a, level, action, index);
159 prefix_ void senf::log::Target::unroute(std::string const & stream, std::string const & area,
160 unsigned level, action_t action)
162 detail::StreamBase const * s (0);
163 if (! stream.empty()) {
164 s = StreamRegistry::instance().lookup(stream);
166 throw InvalidStreamException();
168 detail::AreaBase const * a (0);
169 if (! area.empty()) {
170 a = AreaRegistry::instance().lookup(area);
172 throw InvalidAreaException();
174 unroute(s, a, level, action);
177 prefix_ void senf::log::Target::unroute(int index)
183 if (RIB::size_type(-index) >= rib_.size())
187 std::advance(i, index);
190 if (RIB::size_type(index+1) >= rib_.size()) {
195 std::advance(i, index);
200 RoutingEntry entry (*i);
202 if (entry.action_ == ACCEPT)
203 updateRoutingCache(entry.stream_, entry.area_);
206 prefix_ void senf::log::Target::flush()
210 RIB::const_iterator i (old.begin());
211 RIB::const_iterator const i_end (old.end());
212 for (; i != i_end; ++i)
213 if (i->action_ == ACCEPT)
214 updateRoutingCache(i->stream_, i->area_);
217 ////////////////////////////////////////
220 prefix_ senf::console::ScopedDirectory<> & senf::log::Target::consoleDir()
222 return consoleDir_();
225 ////////////////////////////////////////
228 prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
229 detail::AreaBase const * area, unsigned level,
230 action_t action, int index)
234 if (RIB::size_type(-index-1) >= rib_.size())
238 std::advance(i, index + 1 );
241 if (RIB::size_type(index) >= rib_.size())
245 std::advance(i, index);
248 rib_.insert(i, RoutingEntry(stream, area, level, action));
249 if (action == ACCEPT)
250 updateRoutingCache(stream, area);
251 // This disables the initial fallback routing
252 detail::TargetRegistry::instance().routed();
255 prefix_ void senf::log::Target::unroute(detail::StreamBase const * stream,
256 detail::AreaBase const * area, unsigned level,
259 RIB::iterator i = std::find(rib_.begin(), rib_.end(),
260 RoutingEntry(stream, area, level, action));
262 unroute(std::distance(rib_.begin(), i));
265 prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * stream,
266 detail::AreaBase const * area)
269 StreamRegistry::Registry::iterator i (StreamRegistry::instance().registry_.begin());
270 StreamRegistry::Registry::iterator const i_end (StreamRegistry::instance().registry_.end());
271 for (; i != i_end ; ++i)
272 updateRoutingCache(i->second, area);
276 AreaRegistry::Registry::iterator i (AreaRegistry::instance().registry_.begin());
277 AreaRegistry::Registry::iterator const i_end (AreaRegistry::instance().registry_.end());
278 for (; i != i_end ; ++i)
279 updateRoutingCache(stream, i->second);
283 // We are globally destructing and the area is gone already ...
285 unsigned limit (DISABLED::value);
286 RIB::iterator i (rib_.begin());
287 RIB::iterator const i_end (rib_.end());
288 for(; i != i_end; ++i)
289 if ( (! i->stream_ || i->stream_ == stream) &&
290 (! i->area_ || i->area_ == area) &&
291 i->action_ == ACCEPT ) {
292 unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_);
296 if (limit == DISABLED::value)
297 area->removeRoutingCache(*this, *stream);
299 area->updateRoutingCache(*this, *stream, limit);
302 prefix_ void senf::log::Target::write(time_type timestamp,
303 detail::StreamBase const & stream,
304 detail::AreaBase const & area, unsigned level,
305 std::string const & message)
307 RIB::iterator i (rib_.begin());
308 RIB::iterator const i_end (rib_.end());
309 for (; i != i_end; ++i)
310 if ( (! i->stream_ || i->stream_ == &stream) &&
311 (! i->area_ || i->area_ == &area) &&
312 (i->level_ == NONE::value ? stream.defaultRuntimeLimit() : i->level_) <= level ) {
313 if (i->action_ == ACCEPT)
314 v_write(timestamp, stream.v_name(), area.v_name(), level, message);
320 std::string formatLabel(std::string const & l)
325 return l.substr(l.size()-29);
330 prefix_ void senf::log::Target::consoleList(std::ostream & os)
332 static char const * levels[] = {
333 "verbose", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" };
335 boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n");
336 os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION";
338 for (iterator i (begin()); i != end(); ++i, ++n)
341 % formatLabel(i->stream())
342 % formatLabel(i->area())
344 % (i->action() == ACCEPT ? "accept" : "reject");
347 prefix_ void senf::log::Target::consoleRoute(int index, detail::LogParameters const & pm, action_t action)
349 route(pm.stream, pm.area, pm.level, action, index);
352 prefix_ void senf::log::Target::consoleUnroute(detail::LogParameters const & pm, action_t action)
354 unroute(pm.stream, pm.area, pm.level, action);
357 ///////////////////////////////////////////////////////////////////////////
358 // senf::log::detail::TargetRegistry
360 prefix_ void senf::log::detail::TargetRegistry::dynamicTarget(std::auto_ptr<Target> target)
362 namespace fty = senf::console::factory;
365 .add("remove", fty::Command<void ()>(
366 boost::bind(&TargetRegistry::consoleRemoveTarget, this, target.get()))
367 .doc("Remove target.") );
368 dynamicTargets_.insert(target.release());
371 prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target,
372 std::string const & name)
374 targets_.insert(target);
375 consoleDir_().add(name, target->consoleDir_());
378 prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
379 AreaBase const & area, unsigned level,
380 std::string const & msg)
382 if (fallbackRouting_) {
383 if (level >= stream.defaultRuntimeLimit())
384 static_cast<Target &>(ConsoleTarget::instance()).v_write(
385 TimeSource::now(), stream.v_name(), area.v_name(), level, msg );
388 area.write( TimeSource::now(), stream, level, msg );
391 prefix_ void senf::log::detail::TargetRegistry::consoleRemoveTarget(Target * target)
393 dynamicTargets_.erase(target);
397 prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
398 : fallbackRouting_(true)
400 namespace kw = senf::console::kw;
401 namespace fty = senf::console::factory;
403 console::sysdir().add("log", consoleDir_());
405 .add("areas", fty::Command(&TargetRegistry::consoleAreas, this)
406 .doc("List all areas") );
408 .add("streams", fty::Command(&TargetRegistry::consoleStreams, this)
409 .doc("List all streams") );
411 .add("message", fty::Command(&TargetRegistry::consoleWrite, this)
412 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
413 " and log level. You may specify any combination of these parameterse\n"
414 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
415 " to list all valid streams and areas. Valid log levels are:\n"
416 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL",
417 kw::default_value = LogParameters::defaultParameters())
418 .arg("message", "message to write")
419 .doc("Write log message.\n"
422 " message \"Test\";\n"
423 " message (senf::log::DefaultArea NOTICE) \"Test notice\";\n"
424 " message (FATAL) \"Program on fire\";\n"
425 " message (VERBOSE senf::log::Debug) \"Debug message\";") );
427 .add("self", fty::Command(&TargetRegistry::consoleSelf, this)
428 .doc("Get the log directory of the current network client. Example usage:\n"
430 "Just get the log config directory\n"
432 " <Directory '/sys/log/client-xxx.xxx.xxx.xxx:xxx'>\n"
434 "Route all messages to the currently connected client\n"
435 " $ /sys/log/self { route () ); }") );
438 prefix_ senf::log::detail::TargetRegistry::~TargetRegistry()
440 Targets::iterator i (dynamicTargets_.begin());
441 Targets::iterator const i_end (dynamicTargets_.end());
442 for (; i != i_end; ++i)
446 prefix_ void senf::log::detail::TargetRegistry::consoleAreas(std::ostream & os)
448 AreaRegistry::iterator i (AreaRegistry::instance().begin());
449 AreaRegistry::iterator const i_end (AreaRegistry::instance().end());
450 for (; i != i_end; ++i)
454 prefix_ void senf::log::detail::TargetRegistry::consoleStreams(std::ostream & os)
456 StreamRegistry::iterator i (StreamRegistry::instance().begin());
457 StreamRegistry::iterator const i_end (StreamRegistry::instance().end());
458 for (; i != i_end; ++i)
462 prefix_ void senf::log::detail::TargetRegistry::consoleWrite(LogParameters pm,
463 std::string const & msg)
466 write(*pm.stream, *pm.area, pm.level, msg);
469 prefix_ boost::shared_ptr<senf::console::DirectoryNode>
470 senf::log::detail::TargetRegistry::consoleSelf(std::ostream & os)
472 return senf::console::Client::get(os).consoleDir().node().thisptr();
475 ///////////////////////////////////////////////////////////////////////////
476 // senf::log::detail::LogParameters
478 prefix_ void senf::log::detail::LogParameters::clear()
485 prefix_ void senf::log::detail::LogParameters::setDefaults()
488 stream = & senf::log::Debug::instance();
490 area = & senf::log::DefaultArea::instance();
491 if (level == NONE::value)
492 level = MESSAGE::value;
495 prefix_ senf::log::detail::LogParameters::LogParameters
496 senf::log::detail::LogParameters::defaultParameters()
504 ///////////////////////////////////////////////////////////////////////////
507 prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action)
509 if (action == Target::ACCEPT) os << "ACCEPT";
510 else if (action == Target::REJECT) os << "REJECT";
511 else os << "unknown action";
517 char const * levelNames[] = {
518 "NONE", "VERBOSE", "NOTICE", "MESSAGE", "IMPORTANT", "CRITICAL", "FATAL", "DISABLED" };
520 void parseParamToken(std::string const & value, senf::log::detail::LogParameters & out)
522 senf::log::detail::StreamBase const * s (
523 senf::log::StreamRegistry::instance().lookup(value));
526 throw senf::console::SyntaxErrorException("duplicate stream parameter");
531 senf::log::detail::AreaBase const * a (
532 senf::log::AreaRegistry::instance().lookup(value));
535 throw senf::console::SyntaxErrorException("duplicate area parameter");
541 std::find(levelNames+1, levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1, value));
542 if (i == levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1)
543 throw senf::console::SyntaxErrorException("invalid log parameter");
544 if (out.level != senf::log::NONE::value)
545 throw senf::console::SyntaxErrorException("duplicate level parameter");
546 out.level = i-levelNames;
551 prefix_ std::ostream & senf::log::detail::operator<<(std::ostream & os,
552 LogParameters const & pm)
556 os << pm.stream->v_name();
558 if (pm.stream) os << ' ';
559 os << pm.area->v_name();
560 if (pm.level != NONE::value)
561 if (pm.stream || pm.area) os << ' ';
562 os << levelNames[pm.level];
567 prefix_ void senf::log::detail::
568 senf_console_parse_argument(console::ParseCommandInfo::TokensRange const & tokens,
573 for (console::ParseCommandInfo::TokensRange::iterator i (tokens.begin());
574 i != tokens.end(); ++i)
575 parseParamToken(i->value(), out);
578 //////////////////////////////////////////////////////////////////////////
579 // I need to put this here, otherwise the file target will not be registered
580 // if it is not used ... :-(
582 senf::log::FileTarget::RegisterConsole senf::log::FileTarget::RegisterConsole::instance;
583 senf::log::SyslogTarget::RegisterConsole senf::log::SyslogTarget::RegisterConsole::instance;
584 senf::log::SyslogUDPTarget::RegisterConsole senf::log::SyslogUDPTarget::RegisterConsole::instance;
586 ///////////////////////////////cc.e////////////////////////////////////////
588 //#include "Target.mpp"
594 // comment-column: 40
595 // c-file-style: "senf"
596 // indent-tabs-mode: nil
597 // ispell-local-dictionary: "american"
598 // compile-command: "scons -u test"