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;
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);
276 // We are globally destructing and the area is gone already ...
278 unsigned limit (DISABLED::value);
279 RIB::iterator i (rib_.begin());
280 RIB::iterator const i_end (rib_.end());
281 for(; i != i_end; ++i)
282 if ( (! i->stream_ || i->stream_ == stream) &&
283 (! i->area_ || i->area_ == area) &&
284 i->action_ == ACCEPT ) {
285 unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_);
289 if (limit == DISABLED::value)
290 area->removeRoutingCache(*this, *stream);
292 area->updateRoutingCache(*this, *stream, limit);
295 prefix_ void senf::log::Target::write(time_type timestamp,
296 detail::StreamBase const & stream,
297 detail::AreaBase const & area, unsigned level,
298 std::string const & message)
300 RIB::iterator i (rib_.begin());
301 RIB::iterator const i_end (rib_.end());
302 for (; i != i_end; ++i)
303 if ( (! i->stream_ || i->stream_ == &stream) &&
304 (! i->area_ || i->area_ == &area) &&
305 (i->level_ == NONE::value ? stream.defaultRuntimeLimit() : i->level_) <= level ) {
306 if (i->action_ == ACCEPT)
307 v_write(timestamp, stream.v_name(), area.v_name(), level, message);
313 std::string formatLabel(std::string const & l)
318 return l.substr(l.size()-29);
323 prefix_ void senf::log::Target::consoleList(std::ostream & os)
325 static char const * levels[] = {
326 "verbose", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" };
328 boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n");
329 os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION";
331 for (iterator i (begin()); i != end(); ++i, ++n)
334 % formatLabel(i->stream())
335 % formatLabel(i->area())
337 % (i->action() == ACCEPT ? "accept" : "reject");
340 prefix_ void senf::log::Target::consoleRoute(int index, detail::LogParameters const & pm, action_t action)
342 route(pm.stream, pm.area, pm.level, action, index);
345 prefix_ void senf::log::Target::consoleUnroute(detail::LogParameters const & pm, action_t action)
347 unroute(pm.stream, pm.area, pm.level, action);
350 ///////////////////////////////////////////////////////////////////////////
351 // senf::log::detail::TargetRegistry
353 prefix_ void senf::log::detail::TargetRegistry::dynamicTarget(std::auto_ptr<Target> target)
355 target->consoleDir().add("remove", boost::function<void ()>(
357 &TargetRegistry::consoleRemoveTarget, this, target.get())))
358 .doc("Remove target.");
359 dynamicTargets_.insert(target.release());
362 prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target,
363 std::string const & name)
365 targets_.insert(target);
366 consoleDir_().add(name, target->consoleDir_());
369 prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
370 AreaBase const & area, unsigned level,
371 std::string const & msg)
373 if (fallbackRouting_) {
374 if (level >= stream.defaultRuntimeLimit())
375 static_cast<Target &>(ConsoleTarget::instance()).v_write(
376 TimeSource::now(), stream.v_name(), area.v_name(), level, msg );
379 area.write( TimeSource::now(), stream, level, msg );
382 prefix_ void senf::log::detail::TargetRegistry::consoleRemoveTarget(Target * target)
384 dynamicTargets_.erase(target);
388 prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
389 : fallbackRouting_(true)
391 namespace kw = senf::console::kw;
393 console::sysdir().add("log", consoleDir_());
394 consoleDir_().add("areas", senf::membind(&TargetRegistry::consoleAreas, this))
395 .doc("List all areas");
396 consoleDir_().add("streams", senf::membind(&TargetRegistry::consoleStreams, this))
397 .doc("List all streams");
398 consoleDir_().add("message", senf::membind(&TargetRegistry::consoleWrite, this))
399 .arg("parameters", "log parameters. The log parameters select the log stream, log area\n"
400 " and log level. You may specify any combination of these parameterse\n"
401 " in any order. Use the '/sys/log/stream' and '/sys/log/areas' commands\n"
402 " to list all valid streams and areas. Valid log levels are:\n"
403 " VERBOSE NOTICE MESSAGE IMPORTANT CRITICAL FATAL",
404 kw::default_value = LogParameters::defaultParameters())
405 .arg("message", "message to write")
406 .doc("Write log message.\n"
409 " message \"Test\";\n"
410 " message (senf::log::DefaultArea NOTICE) \"Test notice\";\n"
411 " message (FATAL) \"Program on fire\";\n"
412 " message (VERBOSE senf::log::Debug) \"Debug message\";");
413 consoleDir_().add("self", senf::membind(&TargetRegistry::consoleSelf, this))
414 .doc("Get the log directory of the current network client. Example usage:\n"
416 "Just get the log config directory\n"
418 " <Directory '/sys/log/client-xxx.xxx.xxx.xxx:xxx'>\n"
420 "Route all messages to the currently connected client\n"
421 " $ /sys/log/self { route (); }");
424 prefix_ senf::log::detail::TargetRegistry::~TargetRegistry()
426 Targets::iterator i (dynamicTargets_.begin());
427 Targets::iterator const i_end (dynamicTargets_.end());
428 for (; i != i_end; ++i)
432 prefix_ void senf::log::detail::TargetRegistry::consoleAreas(std::ostream & os)
434 AreaRegistry::iterator i (AreaRegistry::instance().begin());
435 AreaRegistry::iterator const i_end (AreaRegistry::instance().end());
436 for (; i != i_end; ++i)
440 prefix_ void senf::log::detail::TargetRegistry::consoleStreams(std::ostream & os)
442 StreamRegistry::iterator i (StreamRegistry::instance().begin());
443 StreamRegistry::iterator const i_end (StreamRegistry::instance().end());
444 for (; i != i_end; ++i)
448 prefix_ void senf::log::detail::TargetRegistry::consoleWrite(LogParameters pm,
449 std::string const & msg)
452 write(*pm.stream, *pm.area, pm.level, msg);
455 prefix_ boost::shared_ptr<senf::console::DirectoryNode>
456 senf::log::detail::TargetRegistry::consoleSelf(std::ostream & os)
458 return senf::console::Client::get(os).consoleDir().node().thisptr();
461 ///////////////////////////////////////////////////////////////////////////
462 // senf::log::detail::LogParameters
464 prefix_ void senf::log::detail::LogParameters::clear()
471 prefix_ void senf::log::detail::LogParameters::setDefaults()
474 stream = & senf::log::Debug::instance();
476 area = & senf::log::DefaultArea::instance();
477 if (level == NONE::value)
478 level = MESSAGE::value;
481 prefix_ senf::log::detail::LogParameters::LogParameters
482 senf::log::detail::LogParameters::defaultParameters()
490 ///////////////////////////////////////////////////////////////////////////
493 prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action)
495 if (action == Target::ACCEPT) os << "ACCEPT";
496 else if (action == Target::REJECT) os << "REJECT";
497 else os << "unknown action";
503 char const * levelNames[] = {
504 "NONE", "VERBOSE", "NOTICE", "MESSAGE", "IMPORTANT", "CRITICAL", "FATAL", "DISABLED" };
506 void parseParamToken(std::string const & value, senf::log::detail::LogParameters & out)
508 senf::log::detail::StreamBase const * s (
509 senf::log::StreamRegistry::instance().lookup(value));
512 throw senf::console::SyntaxErrorException("duplicate stream parameter");
517 senf::log::detail::AreaBase const * a (
518 senf::log::AreaRegistry::instance().lookup(value));
521 throw senf::console::SyntaxErrorException("duplicate area parameter");
527 std::find(levelNames+1, levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1, value));
528 if (i == levelNames+sizeof(levelNames)/sizeof(levelNames[0])-1)
529 throw senf::console::SyntaxErrorException("invalid log parameter");
530 if (out.level != senf::log::NONE::value)
531 throw senf::console::SyntaxErrorException("duplicate level parameter");
532 out.level = i-levelNames;
537 prefix_ std::ostream & senf::log::detail::operator<<(std::ostream & os,
538 LogParameters const & pm)
542 os << pm.stream->v_name();
544 if (pm.stream) os << ' ';
545 os << pm.area->v_name();
546 if (pm.level != NONE::value)
547 if (pm.stream || pm.area) os << ' ';
548 os << levelNames[pm.level];
553 prefix_ void senf::log::detail::
554 senf_console_parse_argument(console::ParseCommandInfo::TokensRange const & tokens,
559 for (console::ParseCommandInfo::TokensRange::iterator i (tokens.begin());
560 i != tokens.end(); ++i)
561 parseParamToken(i->value(), out);
564 //////////////////////////////////////////////////////////////////////////
565 // I need to put this here, otherwise the file target will not be registered
566 // if it is not used ... :-(
568 senf::log::FileTarget::RegisterConsole senf::log::FileTarget::RegisterConsole::instance;
569 senf::log::SyslogTarget::RegisterConsole senf::log::SyslogTarget::RegisterConsole::instance;
570 senf::log::SyslogUDPTarget::RegisterConsole senf::log::SyslogUDPTarget::RegisterConsole::instance;
572 ///////////////////////////////cc.e////////////////////////////////////////
574 //#include "Target.mpp"
580 // comment-column: 40
581 // c-file-style: "senf"
582 // indent-tabs-mode: nil
583 // ispell-local-dictionary: "american"
584 // compile-command: "scons -u test"