Skip to content
Snippets Groups Projects
Commit 7711fb7b authored by g0dil's avatar g0dil
Browse files

Utils/Logger: SyslogTarget

Utils/Logger: More consistently support optional stream spec
parent 0fd7c329
No related branches found
No related tags found
No related merge requests found
...@@ -54,16 +54,16 @@ ...@@ -54,16 +54,16 @@
<pre> <pre>
g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Debug),(_),DISABLED )) g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Debug),(_),DISABLED ))
(( (senf)(log)(Debug),(foo)(SomeClass),VERBOSE )) (( (senf)(log)(Debug),(foo)(SomeClass),VERBOSE ))
(( (foo)(Transactions),(_),NOTICE ))" ... (( (_),(_),NOTICE ))" ...
</pre> </pre>
The value is relatively complex; It's a Boost.Preprocessor style sequence of tuples, of which The value is relatively complex; It's a Boost.Preprocessor style sequence of tuples, of which
the first and second elements are again sequences. What this boils down to, is that it allows to the first and second elements are again sequences. What this boils down to, is that it allows to
configure compile time logging limits based on stream and optional area. configure compile time logging limits based on stream and optional area.
The above example disables all debug logging by setting the default log limit for all areas on The above example disables all debug logging by setting the default log limit for all areas on
the \c senf::log::Debug stream to \c DISABLED. It then re-enables debug logging only within the the \c senf::log::Debug stream to \c DISABLED. It enables debug logging only within the \c
\c foo::SomeClass area, where it is set to \c VERBOSE. Furthermore, the limit on the \c foo::SomeClass area, where it is set to \c VERBOSE. Lastly, the global compile time limit is set
foo::Transactions stream is set to \c NOTICE. to \c NOTICE.
There are two standard uses for this configuration: Either to disable most logging in final There are two standard uses for this configuration: Either to disable most logging in final
builds by changing the compile time limit to something like senf::log::IMPORTANT or to enable builds by changing the compile time limit to something like senf::log::IMPORTANT or to enable
...@@ -76,6 +76,20 @@ ...@@ -76,6 +76,20 @@
g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Verbose), (some)(Area), VERBOSE ))" g++ ... -DSENF_LOG_CONF="(( (senf)(log)(Verbose), (some)(Area), VERBOSE ))"
</pre> </pre>
All the entries specified via \c SENF_LOG_CONF are applied in a fixed order:
\li First the entries which have both a stream and an area specified are checked
\li next all entries with area but no stream given are checked
\li followed by all entries with a given stream but no area
\li and lastly if no match was found until now, a generic entry without stream and area is
checked
\li if no matching entry is found, the default compile time limit of the stream is used
So an area specification has precedence over a stream specification.
\warning Enabling a message at compile time does \e not ensure, the message is shown. You
additionally need to \e route the message (see next chapter). This is especially true for \c
VERBOSE messages, which are default disabled at runtime.
\see \ref SENF_LOG_CONF \see \ref SENF_LOG_CONF
...@@ -83,8 +97,8 @@ ...@@ -83,8 +97,8 @@
The runtime configuration is performed by routing messages to one or more logging targets: The runtime configuration is performed by routing messages to one or more logging targets:
\code \code
senf::log::ConsoleLog & consoleLog (senf::log::ConsoleLog::instance()); senf::log::ConsoleTarget & consoleLog (senf::log::ConsoleTarget::instance());
senf::log::FileLog fileLog ("my.log"); senf::log::FileTarget fileLog ("my.log");
consoleLog.route<senf::log::Debug>(); consoleLog.route<senf::log::Debug>();
consoleLog.route<foo::Transactions, foo::SomeClass>(senf::log::Target::REJECT); consoleLog.route<foo::Transactions, foo::SomeClass>(senf::log::Target::REJECT);
...@@ -100,6 +114,10 @@ ...@@ -100,6 +114,10 @@
The routing statements are processed by the targets in order, the first matching rule will The routing statements are processed by the targets in order, the first matching rule will
decide a log messages fate for that target. decide a log messages fate for that target.
\warning You can \e only route those messages at runtime which have been compile-time
enabled. By default, \c VERBOSE messages are \e disabled at compile time. They must be
enabled \e explicitly by setting \c SENF_LOG_CONF so they can be routed.
\section config_fallback Fallback routing \section config_fallback Fallback routing
There are two cases, where this setup may lead to inadvertently lost log messages: There are two cases, where this setup may lead to inadvertently lost log messages:
...@@ -147,28 +165,30 @@ namespace log { ...@@ -147,28 +165,30 @@ namespace log {
\par "" \par ""
<table class="ebnf"> <table class="ebnf">
<tr><td>conf</td> <td>::= \e element \e element* \n</td></tr> <tr><td>conf</td> <td>::= \e element \e element* \n</td></tr>
<tr><td>element</td> <td>::= <tt>((</tt> \e stream <tt>,</tt> \e optional_area <tt>,</tt> \e level <tt>))</tt> \n</td></tr> <tr><td>element</td> <td>::= <tt>((</tt> \e optional_stream <tt>,</tt> \e optional_area <tt>,</tt> \e level <tt>))</tt> \n</td></tr>
<tr><td>stream</td> <td>::= \e scope_seq \n</td></tr> <tr><td>optional_stream</td> <td>::= <tt>(_)</tt> | \e scope_seq \n</td></tr>
<tr><td>optional_area</td><td>::= <tt>(_)</tt> | \e scope_seq \n</td></tr> <tr><td>optional_area</td> <td>::= <tt>(_)</tt> | \e scope_seq \n</td></tr>
<tr><td>level</td> <td>::= \c VERBOSE | \c NOTICE | \c MESSAGE | \c IMPORTANT | \c CRITICAL | \c DISABLED \n</td></tr> <tr><td>level</td> <td>::= \c VERBOSE | \c NOTICE | \c MESSAGE | \c IMPORTANT | \c CRITICAL | \c DISABLED \n</td></tr>
<tr><td>scope_seq</td> <td>::= \e scope \e scope* \n</td></tr> <tr><td>scope_seq</td> <td>::= \e scope \e scope* \n</td></tr>
<tr><td>scope</td> <td>::= <tt>(</tt> \e name <tt>)</tt> \n</td></tr> <tr><td>scope</td> <td>::= <tt>(</tt> \e name <tt>)</tt> \n</td></tr>
<tr><td>name</td> <td>::= arbitrary C++ identifier</td></tr> <tr><td>name</td> <td>::= arbitrary C++ identifier</td></tr>
</table> </table>
\ref SENF_LOG_CONF is a Boost.Preprocessor style sequence of 3-tuples. Each tuple applies to \ref SENF_LOG_CONF is a Boost.Preprocessor style sequence of 3-tuples.
a specific stream which is defined by the first tuple element \e stream.
The first tuple element \e optional_stream specifies the stream to match. If this is
<tt>(_)</tt>, the entry will match any stream.
The next tuple element, \e optional_area optionally restricts the entry to match only the The next tuple element, \e optional_area optionally restricts the entry to match only the
given area. given area. If set to <tt>(_)</tt>, the area is left unrestricted.
The last tuple element \e level defines the compile time log level. Messages with a level The last tuple element \e level defines the compile time log level. Messages with a level
below this are discarded at compile time. below this are discarded at compile time.
Both \e stream and \e optional_area are given as a \e scope_seq. A scope sequence is a fully Both \e optional_stream and \e optional_area are given as a \e scope_seq. A scope sequence
qualified C++ identifier placed into a sequence: <tt>foo::bar::baz</tt> is represented by is a fully qualified C++ identifier placed into a sequence: <tt>foo::bar::baz</tt> is
<tt>(foo)(bar)(baz)</tt>. represented by <tt>(foo)(bar)(baz)</tt>.
*/ */
# define SENF_LOG_CONF # define SENF_LOG_CONF
......
...@@ -44,18 +44,30 @@ namespace detail { ...@@ -44,18 +44,30 @@ namespace detail {
struct na {}; struct na {};
/// Internal: Compile time configuration for given \a Stream and \a Area /// Internal: Compile time configuration for given \a Stream and \a Area
template <class Stream, class Area> template <class Stream, class Area, class QueryStream=Stream, bool Query=true>
struct Config struct Config
{ {
typedef typename Config<Stream,na>::compileLimit compileLimit; typedef typename Config<na, Area, Stream, Query>::compileLimit compileLimit;
}; };
# ifndef DOXYGEN # ifndef DOXYGEN
template <class Stream> template <class Area, class QueryStream, bool Query>
struct Config<Stream, na> struct Config<na, Area, QueryStream, Query>
{ {
typedef typename Stream::compileLimit compileLimit; typedef typename Config<QueryStream, na, QueryStream, Query>::compileLimit compileLimit;
};
template <class Stream, class QueryStream, bool Query>
struct Config<Stream, na, QueryStream, Query>
{
typedef typename Config<na, na, QueryStream, Query>::compileLimit compileLimit;
};
template <class QueryStream, bool Query>
struct Config<na, na, QueryStream, Query>
{
typedef typename QueryStream::compileLimit compileLimit;
}; };
# endif # endif
...@@ -88,9 +100,11 @@ namespace detail { ...@@ -88,9 +100,11 @@ namespace detail {
SENF_LOG_PREDECL(stream) \ SENF_LOG_PREDECL(stream) \
SENF_LOG_PREDECL(area) \ SENF_LOG_PREDECL(area) \
namespace senf { namespace log { namespace detail { \ namespace senf { namespace log { namespace detail { \
template <> \ template <class QueryStream> \
struct Config< SENF_LOG_SEQ_TO_NAME(stream), \ struct Config< SENF_LOG_SEQ_TO_NAME(stream), \
SENF_LOG_SEQ_TO_NAME(area) > \ SENF_LOG_SEQ_TO_NAME(area), \
QueryStream, \
true > \
{ typedef senf::log::level compileLimit; }; \ { typedef senf::log::level compileLimit; }; \
}}} }}}
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// senf::log::IOStreamTarget // senf::log::IOStreamTarget
const char * const senf::log::IOStreamTarget::LEVELNAMES_[8] = { char const * const senf::log::IOStreamTarget::LEVELNAMES_[8] = {
"NONE", "VERBOSE", "NOTICE", "MESSAGE", "IMPORTANT", "CRITICAL", "FATAL", "DISABLED" }; "NONE", "VERBOSE", "NOTICE", "MESSAGE", "IMPORTANT", "CRITICAL", "FATAL", "DISABLED" };
prefix_ senf::log::IOStreamTarget::IOStreamTarget(std::ostream & os) prefix_ senf::log::IOStreamTarget::IOStreamTarget(std::ostream & os)
......
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief SyslogTarget non-inline non-template implementation */
#include "SyslogTarget.hh"
//#include "SyslogTarget.ih"
// Custom includes
//#include "SyslogTarget.mpp"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
int const senf::log::SyslogTarget::LEVELMAP_[8] = {
0, LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING, LOG_CRIT, LOG_EMERG, 0 };
prefix_ void senf::log::SyslogTarget::v_write(time_type timestamp, std::string const & stream,
std::string const & area, unsigned level,
std::string const & message)
{
if (area != "senf::log::DefaultArea")
syslog(facility_ | LEVELMAP_[level], "[%s] %s", area.c_str(), message.c_str());
else
syslog(facility_ | LEVELMAP_[level], "%s", message.c_str());
}
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
//#include "SyslogTarget.mpp"
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief SyslogTarget inline non-template implementation */
//#include "SyslogTarget.ih"
// Custom includes
#define prefix_ inline
///////////////////////////////cci.p///////////////////////////////////////
prefix_ senf::log::SyslogTarget::SyslogTarget(int facility)
: facility_ (facility)
{}
///////////////////////////////cci.e///////////////////////////////////////
#undef prefix_
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief SyslogTarget public header */
#ifndef HH_SyslogTarget_
#define HH_SyslogTarget_ 1
// Custom includes
#include <syslog.h>
#include "Target.hh"
//#include "SyslogTarget.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
namespace log {
class SyslogTarget
: public Target
{
public:
///////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////
///\name Structors and default members
///@{
explicit SyslogTarget(int facility = LOG_USER);
///@}
///////////////////////////////////////////////////////////////////////////
protected:
void v_write(time_type timestamp, std::string const & stream,
std::string const & area, unsigned level,
std::string const & message);
private:
int facility_;
static int const LEVELMAP_[8];
};
}}
///////////////////////////////hh.e////////////////////////////////////////
#include "SyslogTarget.cci"
//#include "SyslogTarget.ct"
//#include "SyslogTarget.cti"
#endif
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief SyslogTarget.test unit tests */
//#include "SyslogTarget.test.hh"
//#include "SyslogTarget.test.ih"
// Custom includes
#include "Logger.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
BOOST_AUTO_UNIT_TEST(syslogTarget)
{
senf::log::SyslogTarget syslog;
syslog.route();
BOOST_WARN_MESSAGE( false, "Check the system log for the test message" );
SENF_LOG(("SENF syslog test message"));
}
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
...@@ -174,7 +174,7 @@ prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * st ...@@ -174,7 +174,7 @@ prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * st
if ( (! i->stream_ || i->stream_ == stream) && if ( (! i->stream_ || i->stream_ == stream) &&
(! i->area_ || i->area_ == area) && (! i->area_ || i->area_ == area) &&
i->action_ == ACCEPT ) { i->action_ == ACCEPT ) {
unsigned l (i->level_ == NONE::value ? i->stream_->defaultRuntimeLimit() : i->level_); unsigned l (i->level_ == NONE::value ? stream->defaultRuntimeLimit() : i->level_);
if (l < limit) if (l < limit)
limit = l; limit = l;
} }
...@@ -194,7 +194,7 @@ prefix_ void senf::log::Target::write(time_type timestamp, ...@@ -194,7 +194,7 @@ prefix_ void senf::log::Target::write(time_type timestamp,
for (; i != i_end; ++i) for (; i != i_end; ++i)
if ( (! i->stream_ || i->stream_ == &stream) && if ( (! i->stream_ || i->stream_ == &stream) &&
(! i->area_ || i->area_ == &area) && (! i->area_ || i->area_ == &area) &&
(i->level_ == NONE::value ? i->stream_->defaultRuntimeLimit() : i->level_) <= level ) { (i->level_ == NONE::value ? stream.defaultRuntimeLimit() : i->level_) <= level ) {
if (i->action_ == ACCEPT) if (i->action_ == ACCEPT)
v_write(timestamp, stream.v_name(), area.v_name(), level, message); v_write(timestamp, stream.v_name(), area.v_name(), level, message);
return; return;
......
...@@ -34,6 +34,16 @@ ...@@ -34,6 +34,16 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// senf::log::Target // senf::log::Target
prefix_ void senf::log::Target::route(action_t action, int index)
{
route(0, 0, NONE::value, action, index);
}
prefix_ void senf::log::Target::unroute(action_t action)
{
unroute(0, 0, NONE::value, action);
}
prefix_ senf::log::Target::iterator senf::log::Target::begin() prefix_ senf::log::Target::iterator senf::log::Target::begin()
const const
{ {
......
...@@ -58,8 +58,8 @@ namespace log { ...@@ -58,8 +58,8 @@ namespace log {
/** \brief Logging target base class /** \brief Logging target base class
Targets are the final destination of %log messages. Every message is eventually routed to one Targets are the final destination of %log messages. Every message is eventually routed to
or several targets. one or several targets.
\section target_routing Routing \section target_routing Routing
...@@ -67,12 +67,13 @@ namespace log { ...@@ -67,12 +67,13 @@ namespace log {
matched against this table. If an entry matches, the action associated with this entry is matched against this table. If an entry matches, the action associated with this entry is
taken (either \c ACCEPT or \c REJECT). taken (either \c ACCEPT or \c REJECT).
Every target manages it's own routing table. Conceptually, every routing message will be Every target manages it's own routing table. Conceptually, every message will be routed to
routed to every target where it will then be matched against each targets routing table (the every target where it will then be matched against each targets routing table (the
implementation is more efficient and utilizes a routing cache). implementation is more efficient and utilizes a routing cache).
Each routing entry consists of the following parameters Each routing entry consists of the following parameters
\li (optional) \e stream. The entry will match only messages directed at that stream \li (optional) \e stream. If specified, the entry will match only messages directed at that
stream
\li (optional) \e area. If the area is specified, only messages directed at that area are \li (optional) \e area. If the area is specified, only messages directed at that area are
matched, otherwise any area will be allowed matched, otherwise any area will be allowed
\li (optional) \e level. If the log level is specified, messages will be accepted if their \li (optional) \e level. If the log level is specified, messages will be accepted if their
...@@ -87,11 +88,13 @@ namespace log { ...@@ -87,11 +88,13 @@ namespace log {
\code \code
target.route<foo::SomeStream, senf::log::NOTICE>(senf::log::Target::REJECT); target.route<foo::SomeStream, senf::log::NOTICE>(senf::log::Target::REJECT);
target.route<foo::SomeStream>(); target.route<foo::SomeStream>();
target.route();
\endcode \endcode
The identical routing statements may be expressed using dynamic routing via: The identical routing statements may be expressed using dynamic routing via:
\code \code
target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT); target.route("foo::SomeStream", "", senf::log::NOTICE::value, senf::log::Target::REJECT);
target.route("foo::SomeStream"); target.route("foo::SomeStream");
target.route();
\endcode \endcode
The static representation has the benefit of being compile-time type checked: Invalid The static representation has the benefit of being compile-time type checked: Invalid
routing parameters will be caught while compiling the code. The dynamic representation is routing parameters will be caught while compiling the code. The dynamic representation is
...@@ -114,11 +117,11 @@ namespace log { ...@@ -114,11 +117,11 @@ namespace log {
To implement a new target type, you need to derive from senf::log::Target and implement the To implement a new target type, you need to derive from senf::log::Target and implement the
single \c v_write member. This member will be called whenever a message should be output. single \c v_write member. This member will be called whenever a message should be output.
The target may process in any arbitrary way: reformat, writing it into an SQL DB, whatever The target may process the message in any arbitrary way: reformat it, write it into an SQL
can be envisioned. However, there is one important limitation: The \c v_write call must not DB, whatever can be envisioned. However, there is one important limitation: The \c v_write
block. So for more complex scenarios, additional measures must be taken (e.g. writing a %log call must \e not block. So for more complex scenarios, additional measures must be taken
backend daemon which receives the messages via UDP and processes them). Of course, in rare (e.g. writing a %log backend daemon which receives the messages via UDP and processes
cases messages might be lost but this cannot be avoided. them). Of course, in rare cases messages might be lost but this cannot be avoided.
\see \ref targets \see \ref targets
*/ */
...@@ -196,12 +199,15 @@ namespace log { ...@@ -196,12 +199,15 @@ namespace log {
/**< Add a route for the given combination of \a Stream, \a /**< Add a route for the given combination of \a Stream, \a
Area and \a Level. All parameters (\a Stream, \a Area Area and \a Level. All parameters (\a Stream, \a Area
and \a Level) are optional (the template signature is and \a Level) are optional (the template signature is
shown simplified here). Examples: shown simplified here). So possible commands are:
\code \code
target.route<SomeLevel>(); target.route();
target.route<SomeStream>(); target.route<SomeStream>();
target.route<SomeStream, SomeLevel>(); target.route<SomeArea>();
target.route<SomeLevel>();
target.route<SomeStream, SomeArea>(); target.route<SomeStream, SomeArea>();
target.route<SomeStream, SomeLevel>();
target.route<SomeArea, SomeLevel>();
target.route<SomeStream, SomeArea, SomeLevel>(); target.route<SomeStream, SomeArea, SomeLevel>();
\endcode \endcode
...@@ -293,6 +299,7 @@ namespace log { ...@@ -293,6 +299,7 @@ namespace log {
# ifndef DOXYGEN # ifndef DOXYGEN
void route(action_t action = ACCEPT, int index = -1);
template <class A1> template <class A1>
void route(action_t action = ACCEPT, int index = -1); void route(action_t action = ACCEPT, int index = -1);
template <class A1, class A2> template <class A1, class A2>
...@@ -300,6 +307,7 @@ namespace log { ...@@ -300,6 +307,7 @@ namespace log {
template <class A1, class A2, class A3> template <class A1, class A2, class A3>
void route(action_t action = ACCEPT, int index = -1); void route(action_t action = ACCEPT, int index = -1);
void unroute(action_t action = ACCEPT);
template <class A1> template <class A1>
void unroute(action_t action = ACCEPT); void unroute(action_t action = ACCEPT);
template <class A1, class A2> template <class A1, class A2>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment