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),
92 "stream to match or empty to match any stream\n"
93 " use '/sys/log/streams' to list all available streams",
96 "area to match or empty to match any area\n"
97 " use '/sys/log/areas' to list all available areas",
99 .arg("level", "log level, one of: VERBOSE, NOTICE, MESSAGE, IMPORTANT, CRITICAL, FATAL",
100 kw::default_value=local::VERBOSE)
101 .arg("action", "routing action, one of: ACCEPT, REJECT",
102 kw::default_value=ACCEPT)
103 .arg("index", "index at which to insert new rule",
104 kw::default_value=-1)
105 .doc("Add routing entry. Log messages are matched against the routing table beginning\n"
106 "with the first entry. The action of the first matching entry determines the\n"
107 "handling of the message.\n"
112 " route all messages to this target.\n"
114 " route \"\" my::Class\n"
115 " route all messages which are in the my::Class area.\n"
117 " route senf::log::Debug \"\" VERBOSE REJECT\n"
118 " route \"\" \"\" VERBOSE\n"
119 " route all messages not in the senf::log::Debug stream to the current area.\n"
121 "The additional optional index argument identifies the position in the routing table\n"
122 "where the new routing entry will be added. Positive numbers count from the\n"
123 "beginning, 0 being the first routing entry. Negative values count from the end.\n");
124 consoleDir_().add("unroute",
125 senf::membind(static_cast<void (Target::*)(int)>(&Target::unroute), this))
126 .arg("index", "index of routing entry to remove")
127 .overloadDoc("Remove routing entry with the given index");
128 consoleDir_().add("unroute",
129 boost::function<void (std::string const &, std::string const &,
130 local::Level, action_t)>(
132 static_cast<void (Target::*)(
133 std::string const &, std::string const &,
134 unsigned, action_t)>(&Target::unroute),
136 .arg("stream", "stream to match or empty to match any stream",
137 kw::default_value="")
138 .arg("area", "area to match or empty to match any area",
139 kw::default_value="")
140 .arg("level", "log level, one of: VERBOSE, NOTICE, MESSAGE, IMPORTANT, CRITICAL, FATAL",
141 kw::default_value=local::VERBOSE)
142 .arg("action", "routing action, one of: ACCEPT, REJECT",
143 kw::default_value=ACCEPT)
144 .overloadDoc("Remove the routing entry matching the specified arguments.");
145 consoleDir_().add("flush", senf::membind(&Target::flush, this))
146 .doc("Remove all routing entries clearing the routing table. This will disable all\n"
147 "logging output on this target.");
150 prefix_ senf::log::Target::~Target()
152 while( ! rib_.empty()) {
153 // This is slow but simplifies the area cache handling and removing a target should be
155 RIB::reverse_iterator i (rib_.rbegin());
156 unroute(i->stream_, i->area_, i->level_, i->action_);
158 detail::TargetRegistry::instance().unregisterTarget(this);
161 prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
162 unsigned level, action_t action, int index)
164 detail::StreamBase const * s (0);
165 if (! stream.empty()) {
166 s = StreamRegistry::instance().lookup(stream);
168 throw InvalidStreamException();
170 detail::AreaBase const * a (0);
171 if (! area.empty()) {
172 a = AreaRegistry::instance().lookup(area);
174 throw InvalidAreaException();
176 route(s, a, level, action, index);
179 prefix_ void senf::log::Target::unroute(std::string const & stream, std::string const & area,
180 unsigned level, action_t action)
182 detail::StreamBase const * s (0);
183 if (! stream.empty()) {
184 s = StreamRegistry::instance().lookup(stream);
186 throw InvalidStreamException();
188 detail::AreaBase const * a (0);
189 if (! area.empty()) {
190 a = AreaRegistry::instance().lookup(area);
192 throw InvalidAreaException();
194 unroute(s, a, level, action);
197 prefix_ void senf::log::Target::unroute(int index)
203 if (RIB::size_type(-index) >= rib_.size())
207 std::advance(i, index);
210 if (RIB::size_type(index+1) >= rib_.size()) {
215 std::advance(i, index);
220 RoutingEntry entry (*i);
222 if (entry.action_ == ACCEPT)
223 updateRoutingCache(entry.stream_, entry.area_);
226 prefix_ void senf::log::Target::flush()
230 RIB::const_iterator i (old.begin());
231 RIB::const_iterator const i_end (old.end());
232 for (; i != i_end; ++i)
233 if (i->action_ == ACCEPT)
234 updateRoutingCache(i->stream_, i->area_);
237 ////////////////////////////////////////
240 prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
241 : fallbackRouting_(true)
243 console::sysdir().add("log", consoleDir_());
244 consoleDir_().add("areas", senf::membind(&TargetRegistry::consoleAreas, this))
245 .doc("List all areas");
246 consoleDir_().add("streams", senf::membind(&TargetRegistry::consoleStreams, this))
247 .doc("List all streams");
250 prefix_ void senf::log::detail::TargetRegistry::consoleAreas(std::ostream & os)
252 AreaRegistry::iterator i (AreaRegistry::instance().begin());
253 AreaRegistry::iterator const i_end (AreaRegistry::instance().end());
254 for (; i != i_end; ++i)
258 prefix_ void senf::log::detail::TargetRegistry::consoleStreams(std::ostream & os)
260 StreamRegistry::iterator i (StreamRegistry::instance().begin());
261 StreamRegistry::iterator const i_end (StreamRegistry::instance().end());
262 for (; i != i_end; ++i)
266 ////////////////////////////////////////
269 prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
270 detail::AreaBase const * area, unsigned level,
271 action_t action, int index)
275 if (RIB::size_type(-index-1) >= rib_.size())
279 std::advance(i, index + 1 );
282 if (RIB::size_type(index) >= rib_.size())
286 std::advance(i, index);
289 rib_.insert(i, RoutingEntry(stream, area, level, action));
290 if (action == ACCEPT)
291 updateRoutingCache(stream, area);
292 // This disables the initial fallback routing
293 detail::TargetRegistry::instance().routed();
296 prefix_ void senf::log::Target::unroute(detail::StreamBase const * stream,
297 detail::AreaBase const * area, unsigned level,
300 RIB::iterator i = std::find(rib_.begin(), rib_.end(),
301 RoutingEntry(stream, area, level, action));
303 unroute(std::distance(rib_.begin(), i));
306 prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * stream,
307 detail::AreaBase const * area)
310 StreamRegistry::Registry::iterator i (StreamRegistry::instance().registry_.begin());
311 StreamRegistry::Registry::iterator const i_end (StreamRegistry::instance().registry_.end());
312 for (; i != i_end ; ++i)
313 updateRoutingCache(i->second, area);
317 AreaRegistry::Registry::iterator i (AreaRegistry::instance().registry_.begin());
318 AreaRegistry::Registry::iterator const i_end (AreaRegistry::instance().registry_.end());
319 for (; i != i_end ; ++i)
320 updateRoutingCache(stream, i->second);
323 unsigned limit (DISABLED::value);
324 RIB::iterator i (rib_.begin());
325 RIB::iterator const i_end (rib_.end());
326 for(; i != i_end; ++i)
327 if ( (! i->stream_ || i->stream_ == stream) &&
328 (! i->area_ || i->area_ == area) &&
329 i->action_ == ACCEPT ) {
330 unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_);
334 if (limit == DISABLED::value)
335 area->removeRoutingCache(*this, *stream);
337 area->updateRoutingCache(*this, *stream, limit);
340 prefix_ void senf::log::Target::write(time_type timestamp,
341 detail::StreamBase const & stream,
342 detail::AreaBase const & area, unsigned level,
343 std::string const & message)
345 RIB::iterator i (rib_.begin());
346 RIB::iterator const i_end (rib_.end());
347 for (; i != i_end; ++i)
348 if ( (! i->stream_ || i->stream_ == &stream) &&
349 (! i->area_ || i->area_ == &area) &&
350 (i->level_ == NONE::value ? stream.defaultRuntimeLimit() : i->level_) <= level ) {
351 if (i->action_ == ACCEPT)
352 v_write(timestamp, stream.v_name(), area.v_name(), level, message);
358 std::string formatLabel(std::string const & l)
363 return l.substr(l.size()-29);
368 prefix_ void senf::log::Target::consoleList(std::ostream & os)
370 static char const * levels[] = {
371 "none", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" };
373 boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n");
374 os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION";
376 for (iterator i (begin()); i != end(); ++i, ++n)
379 % formatLabel(i->stream())
380 % formatLabel(i->area())
382 % (i->action() == ACCEPT ? "accept" : "reject");
385 ///////////////////////////////////////////////////////////////////////////
386 // senf::log::detail::TargetRegistry
388 prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target,
389 std::string const & name)
391 targets_.insert(target);
392 consoleDir_().add(name, target->consoleDir_());
395 prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
396 AreaBase const & area, unsigned level,
397 std::string const & msg)
399 if (fallbackRouting_) {
400 if (level >= stream.defaultRuntimeLimit())
401 static_cast<Target &>(ConsoleTarget::instance()).v_write(
402 TimeSource::now(), stream.v_name(), area.v_name(), level, msg );
405 area.write( TimeSource::now(), stream, level, msg );
407 ///////////////////////////////////////////////////////////////////////////
410 prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action)
412 if( action == Target::ACCEPT) os << "ACCEPT";
413 else if( action == Target::REJECT) os << "REJECT";
414 else os << "unknown action";
419 ///////////////////////////////cc.e////////////////////////////////////////
421 //#include "Target.mpp"
427 // comment-column: 40
428 // c-file-style: "senf"
429 // indent-tabs-mode: nil
430 // ispell-local-dictionary: "american"
431 // compile-command: "scons -u test"