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 "../Console/Console.hh"
34 #include "../Console/Sysdir.hh"
35 #include "../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;
60 detail::TargetRegistry::instance().registerTarget(this, name);
61 consoleDir_().add("list", senf::membind(&Target::consoleList, this))
62 .doc("Show routing table\n"
66 " STREAM stream to match, empty to match all streams\n"
67 " AREA area to match, empty to match all targets\n"
68 " LEVEL match messages with level above this. Log levels in increasing order\n"
70 " verbose, notice, message, important, critical, fatal\n"
71 " ACTION action to take: accept or reject");
72 consoleDir_().add("route", senf::membind(&Target::consoleRoute, this))
73 .arg("index", "index at which to insert new rule")
74 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
75 " and log level. You may specify any combination of these parameterse\n"
76 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
77 " to list all valid streams and areas. Valid log levels are:\n"
78 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL")
79 .arg("action", "routing action, one of: ACCEPT, REJECT",
80 kw::default_value=ACCEPT)
81 .doc("Add routing entry. Log messages are matched against the routing table beginning\n"
82 "with the first entry. The action of the first matching entry determines the\n"
83 "handling of the message.\n"
88 " route all messages to this target.\n"
90 " route 1 (my::Class)\n"
91 " route all messages which are in the my::Class area. Insert this route after\n"
94 " route (senf::log::Debug VERBOSE) REJECT\n"
96 " route all messages not in the senf::log::Debug stream to the current area.\n"
98 "The additional optional index argument identifies the position in the routing table\n"
99 "where the new routing entry will be added. Positive numbers count from the\n"
100 "beginning, 0 being the first routing entry. Negative values count from the end.");
101 consoleDir_().add("route", boost::function<void (detail::LogParameters, action_t)>(
102 boost::bind(&Target::consoleRoute, this, -1, _1, _2)))
104 .arg("action", kw::default_value=ACCEPT);
105 consoleDir_().add("unroute",
106 senf::membind(static_cast<void (Target::*)(int)>(&Target::unroute), this))
107 .arg("index", "index of routing entry to remove")
108 .overloadDoc("Remove routing entry with the given index");
109 consoleDir_().add("unroute", senf::membind(&Target::consoleUnroute, this))
110 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
111 " and log level. You may specify any combination of these parameterse\n"
112 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
113 " to list all valid streams and areas. Valid log levels are:\n"
114 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL")
115 .arg("action", "routing action, one of: ACCEPT, REJECT",
116 kw::default_value=ACCEPT)
117 .overloadDoc("Remove the routing entry matching the specified arguments.");
118 consoleDir_().add("flush", senf::membind(&Target::flush, this))
119 .doc("Remove all routing entries clearing the routing table. This will disable all\n"
120 "logging output on this target.");
123 prefix_ senf::log::Target::~Target()
125 while( ! rib_.empty()) {
126 // This is slow but simplifies the area cache handling and removing a target should be
128 RIB::reverse_iterator i (rib_.rbegin());
129 unroute(i->stream_, i->area_, i->level_, i->action_);
131 detail::TargetRegistry::instance().unregisterTarget(this);
134 prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
135 unsigned level, action_t action, int index)
137 detail::StreamBase const * s (0);
138 if (! stream.empty()) {
139 s = StreamRegistry::instance().lookup(stream);
141 throw InvalidStreamException();
143 detail::AreaBase const * a (0);
144 if (! area.empty()) {
145 a = AreaRegistry::instance().lookup(area);
147 throw InvalidAreaException();
149 route(s, a, level, action, index);
152 prefix_ void senf::log::Target::unroute(std::string const & stream, std::string const & area,
153 unsigned level, action_t action)
155 detail::StreamBase const * s (0);
156 if (! stream.empty()) {
157 s = StreamRegistry::instance().lookup(stream);
159 throw InvalidStreamException();
161 detail::AreaBase const * a (0);
162 if (! area.empty()) {
163 a = AreaRegistry::instance().lookup(area);
165 throw InvalidAreaException();
167 unroute(s, a, level, action);
170 prefix_ void senf::log::Target::unroute(int index)
176 if (RIB::size_type(-index) >= rib_.size())
180 std::advance(i, index);
183 if (RIB::size_type(index+1) >= rib_.size()) {
188 std::advance(i, index);
193 RoutingEntry entry (*i);
195 if (entry.action_ == ACCEPT)
196 updateRoutingCache(entry.stream_, entry.area_);
199 prefix_ void senf::log::Target::flush()
203 RIB::const_iterator i (old.begin());
204 RIB::const_iterator const i_end (old.end());
205 for (; i != i_end; ++i)
206 if (i->action_ == ACCEPT)
207 updateRoutingCache(i->stream_, i->area_);
210 ////////////////////////////////////////
213 prefix_ senf::console::ScopedDirectory<> & senf::log::Target::consoleDir()
215 return consoleDir_();
218 ////////////////////////////////////////
221 prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
222 detail::AreaBase const * area, unsigned level,
223 action_t action, int index)
227 if (RIB::size_type(-index-1) >= rib_.size())
231 std::advance(i, index + 1 );
234 if (RIB::size_type(index) >= rib_.size())
238 std::advance(i, index);
241 rib_.insert(i, RoutingEntry(stream, area, level, action));
242 if (action == ACCEPT)
243 updateRoutingCache(stream, area);
244 // This disables the initial fallback routing
245 detail::TargetRegistry::instance().routed();
248 prefix_ void senf::log::Target::unroute(detail::StreamBase const * stream,
249 detail::AreaBase const * area, unsigned level,
252 RIB::iterator i = std::find(rib_.begin(), rib_.end(),
253 RoutingEntry(stream, area, level, action));
255 unroute(std::distance(rib_.begin(), i));
258 prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * stream,
259 detail::AreaBase const * area)
262 StreamRegistry::Registry::iterator i (StreamRegistry::instance().registry_.begin());
263 StreamRegistry::Registry::iterator const i_end (StreamRegistry::instance().registry_.end());
264 for (; i != i_end ; ++i)
265 updateRoutingCache(i->second, area);
269 AreaRegistry::Registry::iterator i (AreaRegistry::instance().registry_.begin());
270 AreaRegistry::Registry::iterator const i_end (AreaRegistry::instance().registry_.end());
271 for (; i != i_end ; ++i)
272 updateRoutingCache(stream, i->second);
275 unsigned limit (DISABLED::value);
276 RIB::iterator i (rib_.begin());
277 RIB::iterator const i_end (rib_.end());
278 for(; i != i_end; ++i)
279 if ( (! i->stream_ || i->stream_ == stream) &&
280 (! i->area_ || i->area_ == area) &&
281 i->action_ == ACCEPT ) {
282 unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_);
286 if (limit == DISABLED::value)
287 area->removeRoutingCache(*this, *stream);
289 area->updateRoutingCache(*this, *stream, limit);
292 prefix_ void senf::log::Target::write(time_type timestamp,
293 detail::StreamBase const & stream,
294 detail::AreaBase const & area, unsigned level,
295 std::string const & message)
297 RIB::iterator i (rib_.begin());
298 RIB::iterator const i_end (rib_.end());
299 for (; i != i_end; ++i)
300 if ( (! i->stream_ || i->stream_ == &stream) &&
301 (! i->area_ || i->area_ == &area) &&
302 (i->level_ == NONE::value ? stream.defaultRuntimeLimit() : i->level_) <= level ) {
303 if (i->action_ == ACCEPT)
304 v_write(timestamp, stream.v_name(), area.v_name(), level, message);
310 std::string formatLabel(std::string const & l)
315 return l.substr(l.size()-29);
320 prefix_ void senf::log::Target::consoleList(std::ostream & os)
322 static char const * levels[] = {
323 "none", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" };
325 boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n");
326 os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION";
328 for (iterator i (begin()); i != end(); ++i, ++n)
331 % formatLabel(i->stream())
332 % formatLabel(i->area())
334 % (i->action() == ACCEPT ? "accept" : "reject");
337 prefix_ void senf::log::Target::consoleRoute(int index, detail::LogParameters const & pm, action_t action)
339 route(pm.stream, pm.area, pm.level, action, index);
342 prefix_ void senf::log::Target::consoleUnroute(detail::LogParameters const & pm, action_t action)
344 unroute(pm.stream, pm.area, pm.level, action);
347 ///////////////////////////////////////////////////////////////////////////
348 // senf::log::detail::TargetRegistry
350 prefix_ void senf::log::detail::TargetRegistry::dynamicTarget(std::auto_ptr<Target> target)
352 target->consoleDir().add("remove", boost::function<void ()>(
354 &TargetRegistry::consoleRemoveTarget, this, target.get())))
355 .doc("Remove target.");
356 dynamicTargets_.insert(target.release());
359 prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target,
360 std::string const & name)
362 targets_.insert(target);
363 consoleDir_().add(name, target->consoleDir_());
366 prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
367 AreaBase const & area, unsigned level,
368 std::string const & msg)
370 if (fallbackRouting_) {
371 if (level >= stream.defaultRuntimeLimit())
372 static_cast<Target &>(ConsoleTarget::instance()).v_write(
373 TimeSource::now(), stream.v_name(), area.v_name(), level, msg );
376 area.write( TimeSource::now(), stream, level, msg );
379 prefix_ void senf::log::detail::TargetRegistry::consoleRemoveTarget(Target * target)
381 dynamicTargets_.erase(target);
385 prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
386 : fallbackRouting_(true)
388 namespace kw = senf::console::kw;
390 console::sysdir().add("log", consoleDir_());
391 consoleDir_().add("areas", senf::membind(&TargetRegistry::consoleAreas, this))
392 .doc("List all areas");
393 consoleDir_().add("streams", senf::membind(&TargetRegistry::consoleStreams, this))
394 .doc("List all streams");
395 consoleDir_().add("message", senf::membind(&TargetRegistry::consoleWrite, this))
396 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
397 " and log level. You may specify any combination of these parameterse\n"
398 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
399 " to list all valid streams and areas. Valid log levels are:\n"
400 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL",
401 kw::default_value = LogParameters::defaultParameters())
402 .arg("message", "message to write")
403 .doc("Write log message.\n"
406 " message \"Test\";\n"
407 " message (senf::log::DefaultArea NOTICE) \"Test notice\";\n"
408 " message (FATAL) \"Program on fire\";\n"
409 " message (VERBOSE senf::log::Debug) \"Debug message\";");
410 consoleDir_().add("self", senf::membind(&TargetRegistry::consoleSelf, this))
411 .doc("Get the log directory of the current network client. Example usage:\n"
413 "Just get the log config directory\n"
415 " <Directory '/sys/log/client-xxx.xxx.xxx.xxx:xxx'>\n"
417 "Route all messages to the currently connected client\n"
418 " $ /sys/log/self { route (); }");
421 prefix_ senf::log::detail::TargetRegistry::~TargetRegistry()
423 Targets::iterator i (dynamicTargets_.begin());
424 Targets::iterator const i_end (dynamicTargets_.end());
425 for (; i != i_end; ++i)
429 prefix_ void senf::log::detail::TargetRegistry::consoleAreas(std::ostream & os)
431 AreaRegistry::iterator i (AreaRegistry::instance().begin());
432 AreaRegistry::iterator const i_end (AreaRegistry::instance().end());
433 for (; i != i_end; ++i)
437 prefix_ void senf::log::detail::TargetRegistry::consoleStreams(std::ostream & os)
439 StreamRegistry::iterator i (StreamRegistry::instance().begin());
440 StreamRegistry::iterator const i_end (StreamRegistry::instance().end());
441 for (; i != i_end; ++i)
445 prefix_ void senf::log::detail::TargetRegistry::consoleWrite(LogParameters pm,
446 std::string const & msg)
449 write(*pm.stream, *pm.area, pm.level, msg);
452 prefix_ boost::shared_ptr<senf::console::DirectoryNode>
453 senf::log::detail::TargetRegistry::consoleSelf(std::ostream & os)
455 return senf::console::Client::get(os).consoleDir().node().thisptr();
458 ///////////////////////////////////////////////////////////////////////////
459 // senf::log::detail::LogParameters
461 prefix_ void senf::log::detail::LogParameters::clear()
468 prefix_ void senf::log::detail::LogParameters::setDefaults()
471 stream = & senf::log::Debug::instance();
473 area = & senf::log::DefaultArea::instance();
474 if (level == NONE::value)
475 level = MESSAGE::value;
478 prefix_ senf::log::detail::LogParameters::LogParameters
479 senf::log::detail::LogParameters::defaultParameters()
487 ///////////////////////////////////////////////////////////////////////////
490 prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action)
492 if( action == Target::ACCEPT) os << "ACCEPT";
493 else if( action == Target::REJECT) os << "REJECT";
494 else os << "unknown action";
500 char const * levelNames[] = {
501 "NONE", "VERBOSE", "NOTICE", "MESSAGE", "IMPORTANT", "CRITICAL", "FATAL", "DISABLED" };
503 void parseParamToken(std::string const & value, senf::log::detail::LogParameters & out)
505 senf::log::detail::StreamBase const * s (
506 senf::log::StreamRegistry::instance().lookup(value));
509 throw senf::console::SyntaxErrorException("duplicate stream parameter");
514 senf::log::detail::AreaBase const * a (
515 senf::log::AreaRegistry::instance().lookup(value));
518 throw senf::console::SyntaxErrorException("duplicate area parameter");
524 std::find(levelNames+1, levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1, value));
525 if (i == levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1)
526 throw senf::console::SyntaxErrorException("invalid log parameter");
527 if (out.level != senf::log::NONE::value)
528 throw senf::console::SyntaxErrorException("duplicate level parameter");
529 out.level = i-levelNames;
534 prefix_ std::ostream & senf::log::detail::operator<<(std::ostream & os,
535 LogParameters const & pm)
539 os << pm.stream->v_name();
541 if (pm.stream) os << ' ';
542 os << pm.area->v_name();
543 if (pm.level != NONE::value)
544 if (pm.stream || pm.area) os << ' ';
545 os << levelNames[pm.level];
550 prefix_ void senf::log::detail::
551 senf_console_parse_argument(console::ParseCommandInfo::TokensRange const & tokens,
556 for (console::ParseCommandInfo::TokensRange::iterator i (tokens.begin());
557 i != tokens.end(); ++i)
558 parseParamToken(i->value(), out);
561 //////////////////////////////////////////////////////////////////////////
562 // I need to put this here, otherwise the file target will not be registered
563 // if it is not used ... :-(
565 senf::log::FileTarget::RegisterConsole senf::log::FileTarget::RegisterConsole::instance;
566 senf::log::SyslogTarget::RegisterConsole senf::log::SyslogTarget::RegisterConsole::instance;
567 senf::log::SyslogUDPTarget::RegisterConsole senf::log::SyslogUDPTarget::RegisterConsole::instance;
569 ///////////////////////////////cc.e////////////////////////////////////////
571 //#include "Target.mpp"
577 // comment-column: 40
578 // c-file-style: "senf"
579 // indent-tabs-mode: nil
580 // ispell-local-dictionary: "american"
581 // compile-command: "scons -u test"