Replace all relative includes with abolute ones
[senf.git] / senf / Utils / Logger / Target.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
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.
12 //
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.
17 //
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.
22
23 /** \file
24     \brief Target non-inline non-template implementation */
25
26 #include "Target.hh"
27 #include "Target.ih"
28
29 // Custom includes
30 #include <algorithm>
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>
36
37 //#include "Target.mpp"
38 #define prefix_
39 ///////////////////////////////cc.p////////////////////////////////////////
40
41 ///////////////////////////////////////////////////////////////////////////
42 // senf::log::Target
43
44 namespace senf {
45 namespace log {
46
47     SENF_CONSOLE_REGISTER_ENUM_MEMBER( Target, action_t, (ACCEPT)(REJECT) );
48
49 namespace detail {
50
51     SENF_CONSOLE_REGISTER_ENUM_MEMBER( TargetRegistry, Level, 
52                                        (VERBOSE)(NOTICE)(MESSAGE)(IMPORTANT)(CRITICAL)(FATAL) );
53
54 }}}
55
56 prefix_ senf::log::Target::Target(std::string const & name)
57 {
58     namespace kw = senf::console::kw;
59
60     detail::TargetRegistry::instance().registerTarget(this, name);
61     consoleDir_().add("list", senf::membind(&Target::consoleList, this))
62         .doc("Show routing table\n"
63              "\n"
64              "Columns:\n"
65              "    #       rule index\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"
69              "            are:\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"
84              "\n"
85              "Examples:\n"
86              "\n"
87              "    route ()\n"
88              "        route all messages to this target.\n"
89              "\n"
90              "    route 1 (my::Class)\n"
91              "        route all messages which are in the my::Class area. Insert this route after\n"
92              "        the first route,\n"
93              "\n"
94              "    route (senf::log::Debug VERBOSE) REJECT\n"
95              "    route (VERBOSE)\n"
96              "        route all messages not in the senf::log::Debug stream to the current area.\n"
97              "\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)))
103         .arg("parameters")
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.");
121 }
122
123 prefix_ senf::log::Target::~Target()
124 {
125     while( ! rib_.empty()) {
126         // This is slow but simplifies the area cache handling and removing a target should be
127         // relatively seldom
128         RIB::reverse_iterator i (rib_.rbegin());
129         unroute(i->stream_, i->area_, i->level_, i->action_);
130     }
131     detail::TargetRegistry::instance().unregisterTarget(this);
132 }
133
134 prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area,
135                                       unsigned level, action_t action, int index)
136 {
137     detail::StreamBase const * s (0);
138     if (! stream.empty()) {
139         s = StreamRegistry::instance().lookup(stream);
140         if (!s)
141             throw InvalidStreamException();
142     }
143     detail::AreaBase const * a (0);
144     if (! area.empty()) {
145         a = AreaRegistry::instance().lookup(area);
146         if (!a)
147             throw InvalidAreaException();
148     }
149     route(s, a, level, action, index);
150 }
151
152 prefix_ void senf::log::Target::unroute(std::string const & stream, std::string const & area,
153                                         unsigned level, action_t action)
154 {
155     detail::StreamBase const * s (0);
156     if (! stream.empty()) {
157         s = StreamRegistry::instance().lookup(stream);
158         if (!s)
159             throw InvalidStreamException();
160     }
161     detail::AreaBase const * a (0);
162     if (! area.empty()) {
163         a = AreaRegistry::instance().lookup(area);
164         if (!a)
165             throw InvalidAreaException();
166     }
167     unroute(s, a, level, action);
168 }
169
170 prefix_ void senf::log::Target::unroute(int index)
171 {
172     if (rib_.empty())
173         return;
174     RIB::iterator i;
175     if (index < 0) {
176         if (RIB::size_type(-index) >= rib_.size())
177             i = rib_.begin();
178         else {
179             i = rib_.end();
180             std::advance(i, index);
181         }
182     } else {
183         if (RIB::size_type(index+1) >= rib_.size()) {
184             i = rib_.end();
185             --i;
186         } else {
187             i = rib_.begin();
188             std::advance(i, index);
189         }
190     }
191     if (i == rib_.end())
192         return;
193     RoutingEntry entry (*i);
194     rib_.erase(i);
195     if (entry.action_ == ACCEPT)
196         updateRoutingCache(entry.stream_, entry.area_);
197 }
198
199 prefix_ void senf::log::Target::flush()
200 {
201     RIB old;
202     rib_.swap(old);
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_);
208 }
209
210 ////////////////////////////////////////
211 // protected members
212
213 prefix_ senf::console::ScopedDirectory<> & senf::log::Target::consoleDir()
214 {
215     return consoleDir_();
216 }
217
218 ////////////////////////////////////////
219 // private members
220
221 prefix_ void senf::log::Target::route(detail::StreamBase const * stream,
222                                       detail::AreaBase const * area, unsigned level,
223                                       action_t action, int index)
224 {
225     RIB::iterator i;
226     if (index < 0) {
227         if (RIB::size_type(-index-1) >= rib_.size())
228             i = rib_.begin();
229         else {
230             i = rib_.end();
231             std::advance(i, index + 1 );
232         }
233     } else {
234         if (RIB::size_type(index) >= rib_.size())
235             i = rib_.end();
236         else {
237             i = rib_.begin();
238             std::advance(i, index);
239         }
240     }
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();
246 }
247
248 prefix_ void senf::log::Target::unroute(detail::StreamBase const * stream,
249                                         detail::AreaBase const * area, unsigned level,
250                                         action_t action)
251 {
252     RIB::iterator i = std::find(rib_.begin(), rib_.end(),
253                                 RoutingEntry(stream, area, level, action));
254     if (i != rib_.end())
255         unroute(std::distance(rib_.begin(), i));
256 }
257
258 prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * stream,
259                                                    detail::AreaBase const * area)
260 {
261     if (! stream) {
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);
266         return;
267     }
268     if (! 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);
273         return;
274     }
275     if (! area->alive())
276         // We are globally destructing and the area is gone already ...
277         return;
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_);
286             if (l < limit)
287                 limit = l;
288         }
289     if (limit == DISABLED::value)
290         area->removeRoutingCache(*this, *stream);
291     else
292         area->updateRoutingCache(*this, *stream, limit);
293 }
294
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)
299 {
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);
308             return;
309         }
310 }
311
312 namespace {
313     std::string formatLabel(std::string const & l)
314     {
315         if (l.empty())
316             return "*";
317         if (l.size() > 29)
318             return l.substr(l.size()-29);
319         return l;
320     }
321 }
322
323 prefix_ void senf::log::Target::consoleList(std::ostream & os)
324 {
325     static char const * levels[] = { 
326         "verbose", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" };
327
328     boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n");
329     os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION";
330     unsigned n (0);
331     for (iterator i (begin()); i != end(); ++i, ++n)
332         os << fmt 
333             % n 
334             % formatLabel(i->stream())
335             % formatLabel(i->area())
336             % levels[i->level()]
337             % (i->action() == ACCEPT ? "accept" : "reject");
338 }
339
340 prefix_ void senf::log::Target::consoleRoute(int index, detail::LogParameters const & pm, action_t action)
341 {
342     route(pm.stream, pm.area, pm.level, action, index);
343 }
344
345 prefix_ void senf::log::Target::consoleUnroute(detail::LogParameters const & pm, action_t action)
346 {
347     unroute(pm.stream, pm.area, pm.level, action);
348 }
349
350 ///////////////////////////////////////////////////////////////////////////
351 // senf::log::detail::TargetRegistry
352
353 prefix_ void senf::log::detail::TargetRegistry::dynamicTarget(std::auto_ptr<Target> target)
354 {
355     target->consoleDir().add("remove", boost::function<void ()>(
356                                  boost::bind(
357                                      &TargetRegistry::consoleRemoveTarget, this, target.get())))
358         .doc("Remove target.");
359     dynamicTargets_.insert(target.release());
360 }
361
362 prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target,
363                                                                std::string const & name)
364 {
365     targets_.insert(target);
366     consoleDir_().add(name, target->consoleDir_());
367 }
368
369 prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream,
370                                                       AreaBase const & area, unsigned level,
371                                                       std::string const & msg)
372 {
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 );
377     }
378     else
379         area.write( TimeSource::now(), stream, level, msg );
380 }
381
382 prefix_ void senf::log::detail::TargetRegistry::consoleRemoveTarget(Target * target)
383 {
384     dynamicTargets_.erase(target);
385     delete target;
386 }
387
388 prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
389     : fallbackRouting_(true)
390 {
391     namespace kw = senf::console::kw;
392
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"
407              "\n"
408              "Examples:\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"
415              "\n"
416              "Just get the log config directory\n"
417              "    $ /sys/log/self\n"
418              "    <Directory '/sys/log/client-xxx.xxx.xxx.xxx:xxx'>\n"
419              "\n"
420              "Route all messages to the currently connected client\n"
421  "    $ /sys/log/self { route (); }");
422 }
423
424 prefix_ senf::log::detail::TargetRegistry::~TargetRegistry()
425 {
426     Targets::iterator i (dynamicTargets_.begin());
427     Targets::iterator const i_end (dynamicTargets_.end());
428     for (; i != i_end; ++i)
429         delete *i;
430 }
431
432 prefix_ void senf::log::detail::TargetRegistry::consoleAreas(std::ostream & os)
433 {
434     AreaRegistry::iterator i (AreaRegistry::instance().begin());
435     AreaRegistry::iterator const i_end (AreaRegistry::instance().end());
436     for (; i != i_end; ++i)
437         os << *i << "\n";
438 }
439
440 prefix_ void senf::log::detail::TargetRegistry::consoleStreams(std::ostream & os)
441 {
442     StreamRegistry::iterator i (StreamRegistry::instance().begin());
443     StreamRegistry::iterator const i_end (StreamRegistry::instance().end());
444     for (; i != i_end; ++i)
445         os << *i << "\n";
446 }
447
448 prefix_ void senf::log::detail::TargetRegistry::consoleWrite(LogParameters pm,
449                                                              std::string const & msg)
450 {
451     pm.setDefaults();
452     write(*pm.stream, *pm.area, pm.level, msg);
453 }
454
455 prefix_ boost::shared_ptr<senf::console::DirectoryNode>
456 senf::log::detail::TargetRegistry::consoleSelf(std::ostream & os)
457 {
458     return senf::console::Client::get(os).consoleDir().node().thisptr();
459 }                                            
460
461 ///////////////////////////////////////////////////////////////////////////
462 // senf::log::detail::LogParameters
463
464 prefix_ void senf::log::detail::LogParameters::clear()
465 {
466     stream = 0;
467     area = 0;
468     level = NONE::value;
469 }
470
471 prefix_ void senf::log::detail::LogParameters::setDefaults()
472 {
473     if (! stream)
474         stream = & senf::log::Debug::instance();
475     if (! area)
476         area = & senf::log::DefaultArea::instance();
477     if (level == NONE::value)
478         level = MESSAGE::value;
479 }
480
481 prefix_ senf::log::detail::LogParameters::LogParameters
482 senf::log::detail::LogParameters::defaultParameters()
483 {
484     LogParameters pm;
485     pm.clear();
486     pm.setDefaults();
487     return pm;
488 }
489
490 ///////////////////////////////////////////////////////////////////////////
491 // namespace members
492
493 prefix_ std::ostream & senf::log::operator<<(std::ostream & os, senf::log::Target::action_t const & action)
494 {
495     if( action == Target::ACCEPT) os << "ACCEPT";
496     else if( action == Target::REJECT) os << "REJECT";
497     else os << "unknown action";
498     return os;
499 }
500
501 namespace {
502
503     char const * levelNames[] = { 
504         "NONE", "VERBOSE", "NOTICE", "MESSAGE", "IMPORTANT", "CRITICAL", "FATAL", "DISABLED" };
505
506     void parseParamToken(std::string const & value, senf::log::detail::LogParameters & out)
507     {
508         senf::log::detail::StreamBase const * s (
509             senf::log::StreamRegistry::instance().lookup(value));
510         if (s) {
511             if (out.stream)
512                 throw senf::console::SyntaxErrorException("duplicate stream parameter");
513             out.stream = s;
514             return;
515         }
516
517         senf::log::detail::AreaBase const * a (
518             senf::log::AreaRegistry::instance().lookup(value));
519         if (a) {
520             if (out.area)
521                 throw senf::console::SyntaxErrorException("duplicate area parameter");
522             out.area = a;
523             return;
524         }
525         
526         char const ** i (
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;
533     }
534
535 }
536
537 prefix_ std::ostream & senf::log::detail::operator<<(std::ostream & os,
538                                                      LogParameters const & pm)
539 {
540     os << '(';
541     if (pm.stream)
542         os << pm.stream->v_name();
543     if (pm.area)
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];
549     os << ')';
550     return os;
551 }
552
553 prefix_ void senf::log::detail::
554 senf_console_parse_argument(console::ParseCommandInfo::TokensRange const & tokens,
555                             LogParameters & out)
556 {
557     out.clear();
558     
559     for (console::ParseCommandInfo::TokensRange::iterator i (tokens.begin());
560          i != tokens.end(); ++i)
561         parseParamToken(i->value(), out);
562 }
563
564 //////////////////////////////////////////////////////////////////////////
565 // I need to put this here, otherwise the file target will not be registered
566 // if it is not used ... :-(
567
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;
571
572 ///////////////////////////////cc.e////////////////////////////////////////
573 #undef prefix_
574 //#include "Target.mpp"
575
576
577 // Local Variables:
578 // mode: c++
579 // fill-column: 100
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"
585 // End: