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) );
55 VERBOSE = senf::log::VERBOSE::value,
56 NOTICE = senf::log::NOTICE::value,
57 MESSAGE = senf::log::MESSAGE::value,
58 IMPORTANT = senf::log::IMPORTANT::value,
59 CRITICAL = senf::log::CRITICAL::value,
60 FATAL = senf::log::FATAL::value
62 SENF_CONSOLE_REGISTER_ENUM( Level,
63 (VERBOSE)(NOTICE)(MESSAGE)(IMPORTANT)(CRITICAL)(FATAL) );
67 prefix_ senf::log::Target::Target(std::string const & name)
69 namespace kw = senf::console::kw;
71 detail::TargetRegistry::instance().registerTarget(this, name);
72 consoleDir_().add("list", senf::membind(&Target::consoleList, this))
73 .doc("Show routing table\n"
77 " STREAM stream to match, empty to match all streams\n"
78 " AREA area to match, empty to match all targets\n"
79 " LEVEL match messages with level above this. Log levels in increasing order\n"
81 " verbose, notice, message, important, critical, fatal\n"
82 " ACTION action to take: accept or reject");
83 consoleDir_().add("route",
84 boost::function<void (std::string const &, std::string const &,
85 local::Level, action_t, int)>(
87 static_cast<void (Target::*)(
88 std::string const &, std::string const &,
89 unsigned, action_t, int)>(&Target::route),
91 .arg("stream", "stream to match or empty to match any stream",
93 .arg("area", "area to match or empty to match any area",
95 .arg("level", "log level, one of: VERBOSE, NOTICE, MESSAGE, IMPORTANT, CRITICAL, FATAL",
96 kw::default_value=local::VERBOSE)
97 .arg("action", "routing action, one of: ACCEPT, REJECT",
98 kw::default_value=ACCEPT)
99 .arg("index", "index at which to insert new rule",
100 kw::default_value=-1)
101 .doc("Add routing entry. Log messages are matched against the routing table beginning\n"
102 "with the first entry. The action of the first matching entry determines the\n"
103 "handling of the message.\n"
108 " route all messages to this target.\n"
110 " route \"\" my::Class\n"
111 " route all messages which are in the my::Class area.\n"
113 " route senf::log::Debug \"\" VERBOSE REJECT\n"
114 " route \"\" \"\" VERBOSE\n"
115 " route all messages not in the senf::log::Debug stream to the current area.\n"
117 "The additional optional index argument identifies the position in the routing table\n"
118 "where the new routing entry will be added. Positive numbers count from the\n"
119 "beginning, 0 being the first routing entry. Negative values count from the end.\n");
120 consoleDir_().add("unroute",
121 senf::membind(static_cast<void (Target::*)(int)>(&Target::unroute), this))
122 .arg("index", "index of routing entry to remove")
123 .overloadDoc("Remove routing entry with the given index");
124 consoleDir_().add("unroute",
125 boost::function<void (std::string const &, std::string const &,
126 local::Level, action_t)>(
128 static_cast<void (Target::*)(
129 std::string const &, std::string const &,
130 unsigned, action_t)>(&Target::unroute),
132 .arg("stream", "stream to match or empty to match any stream",
133 kw::default_value="")
134 .arg("area", "area to match or empty to match any area",
135 kw::default_value="")
136 .arg("level", "log level, one of: VERBOSE, NOTICE, MESSAGE, IMPORTANT, CRITICAL, FATAL",
137 kw::default_value=local::VERBOSE)
138 .arg("action", "routing action, one of: ACCEPT, REJECT",
139 kw::default_value=ACCEPT)
140 .overloadDoc("Remove the routing entry matching the specified arguments.");
141 consoleDir_().add("flush", senf::membind(&Target::flush, this))
142 .doc("Remove all routing entries clearing the routing table. This will disable all\n"
143 "logging output on this target.");
146 prefix_ senf::log::Target::~Target()
148 while( ! rib_.empty()) {
149 // This is slow but simplifies the area cache handling and removing a target should be
151 RIB::reverse_iterator i (rib_.rbegin());
152 unroute(i->stream_, i->area_, i->level_, i->action_);
154 detail::TargetRegistry::instance().unregisterTarget(this);
157 prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
158 unsigned level, action_t action, int index)
160 detail::StreamBase const * s (0);
161 if (! stream.empty()) {
162 s = StreamRegistry::instance().lookup(stream);
164 throw InvalidStreamException();
166 detail::AreaBase const * a (0);
167 if (! area.empty()) {
168 a = AreaRegistry::instance().lookup(area);
170 throw InvalidAreaException();
172 route(s, a, level, action, index);
175 prefix_ void senf::log::Target::unroute(std::string const & stream, std::string const & area,
176 unsigned level, action_t action)
178 detail::StreamBase const * s (0);
179 if (! stream.empty()) {
180 s = StreamRegistry::instance().lookup(stream);
182 throw InvalidStreamException();
184 detail::AreaBase const * a (0);
185 if (! area.empty()) {
186 a = AreaRegistry::instance().lookup(area);
188 throw InvalidAreaException();
190 unroute(s, a, level, action);
193 prefix_ void senf::log::Target::unroute(int index)
199 if (RIB::size_type(-index) >= rib_.size())
203 std::advance(i, index);
206 if (RIB::size_type(index+1) >= rib_.size()) {
211 std::advance(i, index);
216 RoutingEntry entry (*i);
218 if (entry.action_ == ACCEPT)
219 updateRoutingCache(entry.stream_, entry.area_);
222 prefix_ void senf::log::Target::flush()
226 RIB::const_iterator i (old.begin());
227 RIB::const_iterator const i_end (old.end());
228 for (; i != i_end; ++i)
229 if (i->action_ == ACCEPT)
230 updateRoutingCache(i->stream_, i->area_);
233 ////////////////////////////////////////
236 prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
237 : fallbackRouting_(true)
239 console::sysdir().add("log", consoleDir_());
242 ////////////////////////////////////////
245 prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
246 detail::AreaBase const * area, unsigned level,
247 action_t action, int index)
251 if (RIB::size_type(-index-1) >= rib_.size())
255 std::advance(i, index + 1 );
258 if (RIB::size_type(index) >= rib_.size())
262 std::advance(i, index);
265 rib_.insert(i, RoutingEntry(stream, area, level, action));
266 if (action == ACCEPT)
267 updateRoutingCache(stream, area);
268 // This disables the initial fallback routing
269 detail::TargetRegistry::instance().routed();
272 prefix_ void senf::log::Target::unroute(detail::StreamBase const * stream,
273 detail::AreaBase const * area, unsigned level,
276 RIB::iterator i = std::find(rib_.begin(), rib_.end(),
277 RoutingEntry(stream, area, level, action));
279 unroute(std::distance(rib_.begin(), i));
282 prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * stream,
283 detail::AreaBase const * area)
286 StreamRegistry::Registry::iterator i (StreamRegistry::instance().registry_.begin());
287 StreamRegistry::Registry::iterator const i_end (StreamRegistry::instance().registry_.end());
288 for (; i != i_end ; ++i)
289 updateRoutingCache(i->second, area);
293 AreaRegistry::Registry::iterator i (AreaRegistry::instance().registry_.begin());
294 AreaRegistry::Registry::iterator const i_end (AreaRegistry::instance().registry_.end());
295 for (; i != i_end ; ++i)
296 updateRoutingCache(stream, i->second);
299 unsigned limit (DISABLED::value);
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->action_ == ACCEPT ) {
306 unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_);
310 if (limit == DISABLED::value)
311 area->removeRoutingCache(*this, *stream);
313 area->updateRoutingCache(*this, *stream, limit);
316 prefix_ void senf::log::Target::write(time_type timestamp,
317 detail::StreamBase const & stream,
318 detail::AreaBase const & area, unsigned level,
319 std::string const & message)
321 RIB::iterator i (rib_.begin());
322 RIB::iterator const i_end (rib_.end());
323 for (; i != i_end; ++i)
324 if ( (! i->stream_ || i->stream_ == &stream) &&
325 (! i->area_ || i->area_ == &area) &&
326 (i->level_ == NONE::value ? stream.defaultRuntimeLimit() : i->level_) <= level ) {
327 if (i->action_ == ACCEPT)
328 v_write(timestamp, stream.v_name(), area.v_name(), level, message);
334 std::string formatLabel(std::string const & l)
339 return l.substr(l.size()-29);
344 prefix_ void senf::log::Target::consoleList(std::ostream & os)
346 static char const * levels[] = {
347 "none", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" };
349 boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n");
350 os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION";
352 for (iterator i (begin()); i != end(); ++i, ++n)
355 % formatLabel(i->stream())
356 % formatLabel(i->area())
358 % (i->action() == ACCEPT ? "accept" : "reject");
361 ///////////////////////////////////////////////////////////////////////////
362 // senf::log::detail::TargetRegistry
364 prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target,
365 std::string const & name)
367 targets_.insert(target);
368 consoleDir_().add(name, target->consoleDir_());
371 prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
372 AreaBase const & area, unsigned level,
373 std::string const & msg)
375 if (fallbackRouting_) {
376 if (level >= stream.defaultRuntimeLimit())
377 static_cast<Target &>(ConsoleTarget::instance()).v_write(
378 TimeSource::now(), stream.v_name(), area.v_name(), level, msg );
381 area.write( TimeSource::now(), stream, level, msg );
383 ///////////////////////////////////////////////////////////////////////////
386 prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action)
388 if( action == Target::ACCEPT) os << "ACCEPT";
389 else if( action == Target::REJECT) os << "REJECT";
390 else os << "unknown action";
395 ///////////////////////////////cc.e////////////////////////////////////////
397 //#include "Target.mpp"
403 // comment-column: 40
404 // c-file-style: "senf"
405 // indent-tabs-mode: nil
406 // ispell-local-dictionary: "american"
407 // compile-command: "scons -u test"