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",
73 boost::function<void (std::string const &, std::string const &,
74 detail::TargetRegistry::Level, action_t, int)>(
76 static_cast<void (Target::*)(
77 std::string const &, std::string const &,
78 unsigned, action_t, int)>(&Target::route),
81 "stream to match or empty to match any stream\n"
82 " use '/sys/log/streams' to list all available streams",
85 "area to match or empty to match any area\n"
86 " use '/sys/log/areas' to list all available areas",
88 .arg("level", "log level, one of: VERBOSE, NOTICE, MESSAGE, IMPORTANT, CRITICAL, FATAL",
89 kw::default_value=detail::TargetRegistry::VERBOSE)
90 .arg("action", "routing action, one of: ACCEPT, REJECT",
91 kw::default_value=ACCEPT)
92 .arg("index", "index at which to insert new rule",
94 .doc("Add routing entry. Log messages are matched against the routing table beginning\n"
95 "with the first entry. The action of the first matching entry determines the\n"
96 "handling of the message.\n"
101 " route all messages to this target.\n"
103 " route \"\" my::Class\n"
104 " route all messages which are in the my::Class area.\n"
106 " route senf::log::Debug \"\" VERBOSE REJECT\n"
107 " route \"\" \"\" VERBOSE\n"
108 " route all messages not in the senf::log::Debug stream to the current area.\n"
110 "The additional optional index argument identifies the position in the routing table\n"
111 "where the new routing entry will be added. Positive numbers count from the\n"
112 "beginning, 0 being the first routing entry. Negative values count from the end.\n");
113 consoleDir_().add("unroute",
114 senf::membind(static_cast<void (Target::*)(int)>(&Target::unroute), this))
115 .arg("index", "index of routing entry to remove")
116 .overloadDoc("Remove routing entry with the given index");
117 consoleDir_().add("unroute",
118 boost::function<void (std::string const &, std::string const &,
119 detail::TargetRegistry::Level, action_t)>(
121 static_cast<void (Target::*)(
122 std::string const &, std::string const &,
123 unsigned, action_t)>(&Target::unroute),
125 .arg("stream", "stream to match or empty to match any stream",
126 kw::default_value="")
127 .arg("area", "area to match or empty to match any area",
128 kw::default_value="")
129 .arg("level", "log level, one of: VERBOSE, NOTICE, MESSAGE, IMPORTANT, CRITICAL, FATAL",
130 kw::default_value=detail::TargetRegistry::VERBOSE)
131 .arg("action", "routing action, one of: ACCEPT, REJECT",
132 kw::default_value=ACCEPT)
133 .overloadDoc("Remove the routing entry matching the specified arguments.");
134 consoleDir_().add("flush", senf::membind(&Target::flush, this))
135 .doc("Remove all routing entries clearing the routing table. This will disable all\n"
136 "logging output on this target.");
139 prefix_ senf::log::Target::~Target()
141 while( ! rib_.empty()) {
142 // This is slow but simplifies the area cache handling and removing a target should be
144 RIB::reverse_iterator i (rib_.rbegin());
145 unroute(i->stream_, i->area_, i->level_, i->action_);
147 detail::TargetRegistry::instance().unregisterTarget(this);
150 prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
151 unsigned level, action_t action, int index)
153 detail::StreamBase const * s (0);
154 if (! stream.empty()) {
155 s = StreamRegistry::instance().lookup(stream);
157 throw InvalidStreamException();
159 detail::AreaBase const * a (0);
160 if (! area.empty()) {
161 a = AreaRegistry::instance().lookup(area);
163 throw InvalidAreaException();
165 route(s, a, level, action, index);
168 prefix_ void senf::log::Target::unroute(std::string const & stream, std::string const & area,
169 unsigned level, action_t action)
171 detail::StreamBase const * s (0);
172 if (! stream.empty()) {
173 s = StreamRegistry::instance().lookup(stream);
175 throw InvalidStreamException();
177 detail::AreaBase const * a (0);
178 if (! area.empty()) {
179 a = AreaRegistry::instance().lookup(area);
181 throw InvalidAreaException();
183 unroute(s, a, level, action);
186 prefix_ void senf::log::Target::unroute(int index)
192 if (RIB::size_type(-index) >= rib_.size())
196 std::advance(i, index);
199 if (RIB::size_type(index+1) >= rib_.size()) {
204 std::advance(i, index);
209 RoutingEntry entry (*i);
211 if (entry.action_ == ACCEPT)
212 updateRoutingCache(entry.stream_, entry.area_);
215 prefix_ void senf::log::Target::flush()
219 RIB::const_iterator i (old.begin());
220 RIB::const_iterator const i_end (old.end());
221 for (; i != i_end; ++i)
222 if (i->action_ == ACCEPT)
223 updateRoutingCache(i->stream_, i->area_);
226 ////////////////////////////////////////
229 prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
230 : fallbackRouting_(true)
232 namespace kw = senf::console::kw;
234 console::sysdir().add("log", consoleDir_());
235 consoleDir_().add("areas", senf::membind(&TargetRegistry::consoleAreas, this))
236 .doc("List all areas");
237 consoleDir_().add("streams", senf::membind(&TargetRegistry::consoleStreams, this))
238 .doc("List all streams");
239 consoleDir_().add("message", senf::membind(&TargetRegistry::consoleWrite, this))
240 .arg("stream", "stream to write message to",
241 kw::default_value = "senf::log::Debug")
242 .arg("area","area to write message to",
243 kw::default_value = "senf::log::DefaultArea")
244 .arg("level", "log level, one of:\n"
245 " VERBOSE, NOTICE, MESSAGE, IMPORTANT, CRITICAL, FATAL",
246 kw::default_value = MESSAGE)
247 .arg("message", "message to write")
248 .doc("Write log message");
251 prefix_ senf::log::detail::TargetRegistry::~TargetRegistry()
253 Targets::iterator i (dynamicTargets_.begin());
254 Targets::iterator const i_end (dynamicTargets_.end());
255 for (; i != i_end; ++i)
259 prefix_ void senf::log::detail::TargetRegistry::consoleAreas(std::ostream & os)
261 AreaRegistry::iterator i (AreaRegistry::instance().begin());
262 AreaRegistry::iterator const i_end (AreaRegistry::instance().end());
263 for (; i != i_end; ++i)
267 prefix_ void senf::log::detail::TargetRegistry::consoleStreams(std::ostream & os)
269 StreamRegistry::iterator i (StreamRegistry::instance().begin());
270 StreamRegistry::iterator const i_end (StreamRegistry::instance().end());
271 for (; i != i_end; ++i)
275 prefix_ void senf::log::detail::TargetRegistry::consoleWrite(std::string const & stream,
276 std::string const & area,
278 std::string const & msg)
280 detail::StreamBase const * s (StreamRegistry::instance().lookup(stream));
282 throw Target::InvalidStreamException();
283 detail::AreaBase const * a (AreaRegistry::instance().lookup(area));
285 throw Target::InvalidAreaException();
286 write(*s, *a, level, msg);
289 prefix_ senf::console::ScopedDirectory<> & senf::log::Target::consoleDir()
291 return consoleDir_();
294 ////////////////////////////////////////
297 prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
298 detail::AreaBase const * area, unsigned level,
299 action_t action, int index)
303 if (RIB::size_type(-index-1) >= rib_.size())
307 std::advance(i, index + 1 );
310 if (RIB::size_type(index) >= rib_.size())
314 std::advance(i, index);
317 rib_.insert(i, RoutingEntry(stream, area, level, action));
318 if (action == ACCEPT)
319 updateRoutingCache(stream, area);
320 // This disables the initial fallback routing
321 detail::TargetRegistry::instance().routed();
324 prefix_ void senf::log::Target::unroute(detail::StreamBase const * stream,
325 detail::AreaBase const * area, unsigned level,
328 RIB::iterator i = std::find(rib_.begin(), rib_.end(),
329 RoutingEntry(stream, area, level, action));
331 unroute(std::distance(rib_.begin(), i));
334 prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * stream,
335 detail::AreaBase const * area)
338 StreamRegistry::Registry::iterator i (StreamRegistry::instance().registry_.begin());
339 StreamRegistry::Registry::iterator const i_end (StreamRegistry::instance().registry_.end());
340 for (; i != i_end ; ++i)
341 updateRoutingCache(i->second, area);
345 AreaRegistry::Registry::iterator i (AreaRegistry::instance().registry_.begin());
346 AreaRegistry::Registry::iterator const i_end (AreaRegistry::instance().registry_.end());
347 for (; i != i_end ; ++i)
348 updateRoutingCache(stream, i->second);
351 unsigned limit (DISABLED::value);
352 RIB::iterator i (rib_.begin());
353 RIB::iterator const i_end (rib_.end());
354 for(; i != i_end; ++i)
355 if ( (! i->stream_ || i->stream_ == stream) &&
356 (! i->area_ || i->area_ == area) &&
357 i->action_ == ACCEPT ) {
358 unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_);
362 if (limit == DISABLED::value)
363 area->removeRoutingCache(*this, *stream);
365 area->updateRoutingCache(*this, *stream, limit);
368 prefix_ void senf::log::Target::write(time_type timestamp,
369 detail::StreamBase const & stream,
370 detail::AreaBase const & area, unsigned level,
371 std::string const & message)
373 RIB::iterator i (rib_.begin());
374 RIB::iterator const i_end (rib_.end());
375 for (; i != i_end; ++i)
376 if ( (! i->stream_ || i->stream_ == &stream) &&
377 (! i->area_ || i->area_ == &area) &&
378 (i->level_ == NONE::value ? stream.defaultRuntimeLimit() : i->level_) <= level ) {
379 if (i->action_ == ACCEPT)
380 v_write(timestamp, stream.v_name(), area.v_name(), level, message);
386 std::string formatLabel(std::string const & l)
391 return l.substr(l.size()-29);
396 prefix_ void senf::log::Target::consoleList(std::ostream & os)
398 static char const * levels[] = {
399 "none", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" };
401 boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n");
402 os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION";
404 for (iterator i (begin()); i != end(); ++i, ++n)
407 % formatLabel(i->stream())
408 % formatLabel(i->area())
410 % (i->action() == ACCEPT ? "accept" : "reject");
413 ///////////////////////////////////////////////////////////////////////////
414 // senf::log::detail::TargetRegistry
416 prefix_ void senf::log::detail::TargetRegistry::dynamicTarget(std::auto_ptr<Target> target)
418 target->consoleDir().add("remove", boost::function<void ()>(
420 &TargetRegistry::consoleRemoveTarget, this, target.get())))
421 .doc("Remove target.");
422 dynamicTargets_.insert(target.release());
425 prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target,
426 std::string const & name)
428 targets_.insert(target);
429 consoleDir_().add(name, target->consoleDir_());
432 prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
433 AreaBase const & area, unsigned level,
434 std::string const & msg)
436 if (fallbackRouting_) {
437 if (level >= stream.defaultRuntimeLimit())
438 static_cast<Target &>(ConsoleTarget::instance()).v_write(
439 TimeSource::now(), stream.v_name(), area.v_name(), level, msg );
442 area.write( TimeSource::now(), stream, level, msg );
445 prefix_ void senf::log::detail::TargetRegistry::consoleRemoveTarget(Target * target)
447 dynamicTargets_.erase(target);
451 ///////////////////////////////////////////////////////////////////////////
454 prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action)
456 if( action == Target::ACCEPT) os << "ACCEPT";
457 else if( action == Target::REJECT) os << "REJECT";
458 else os << "unknown action";
462 //////////////////////////////////////////////////////////////////////////
463 // I need to put this here, otherwise the file target will not be registered
464 // if it is not used ... :-(
466 senf::log::FileTarget::RegisterConsole senf::log::FileTarget::RegisterConsole::instance;
467 senf::log::SyslogTarget::RegisterConsole senf::log::SyslogTarget::RegisterConsole::instance;
468 senf::log::SyslogUDPTarget::RegisterConsole senf::log::SyslogUDPTarget::RegisterConsole::instance;
470 ///////////////////////////////cc.e////////////////////////////////////////
472 //#include "Target.mpp"
478 // comment-column: 40
479 // c-file-style: "senf"
480 // indent-tabs-mode: nil
481 // ispell-local-dictionary: "american"
482 // compile-command: "scons -u test"