Boost logo

Boost :

Subject: Re: [boost] [logging] Interest check on logging library.
From: Jason Wagner (jason_at_[hidden])
Date: 2009-01-01 22:30:10


On Wed, 31 Dec 2008 21:43:22 -0500, Jamie Allsop <ja11sop_at_[hidden]>
wrote:

> Andrey Semashev wrote:
>> Jason Wagner wrote:
> [...]
>> Sorry, couldn't resist. I think, my library fits these requirements
>> quite well. Why would you start your own implementation from scratch?
>> Is there something that doesn't suit you in my implementation?
>
> If I recall your library requires a lib to be linked in. That's a deal
> breaker for me. This library seems to move away from that. What I really
> need is captured in my review of John Torjo's second library
> <http://lists.boost.org/Archives/boost/2008/02/133462.php>
>
> I'd be interested if either library can support this minimal use case.
>
> Jamie

The design on my version is for the core to be a hierarchical
configuration utility. There is a root logger config that everything
descends from. It's actually the area I'm trying to work on now and looks
like:

   bl::core core;
   core.action("test_action")
       .set_filter(bl::severity() > bl::severity::warning())
       .on_success(core.file_sink("warnings.txt"));

   core.channel("")
       .set_filter(bl::severity() > bl::var("LOGGING_THRESHOLD"))
       .on_success(core.file_logger("my_log.txt"))
       .on_failure(core.file_logger("my_failure.txt"))
       .value("LOGGING_THRESHOLD", bl::severity::info::value)
       ;

   core.channel("server")
       .value("LOGGING_THRESHOLD", bl::severity::debug::value);

   core.channel("server.network")
       .on_success(core.action("test_action"));

   bl::logger<> logger(core.channel("server.network"));

This code is not in the tarball I threw up and shouldn't be considered
final, btw.

Each channel has a variable set and a filter chain associated with it.
Channels can share filter chains. Channels are created on the fly when
referenced, defaulting to their closest defined ancestor. Variables sets
are inherited, so in this example "server.network" inherits the value of
"LOGGING_THRESHOLD". Filter actions are not defaulted but not inherited.
That means that:

bl::logger<> log2(core.channel("server.network.foo"));

will use the filter actions of "server.network", but "server.network" does
not use the actions of "server" because it has a definition and is
constructable anywhere.

The core is mutable, so at any time you can call

core.channel("server").value("LOGGING_THRESHOLD",bl::severity::warning::value);

and change the value for everything that defaults to that value. If I
understand what you wrote in the review, I belive I have a similar
use-case. Formatters are not finalized, but would be attached to the sink
(core.file_logger("") in the example).

That's how you'd do it at runtime, which has a cost to evaluate. At
compile time, you could use tags similar to my server example:

// in some header
typedef boost::mpl::vector<
     bl::condition::not_in<build_type::server>
> conditions;

typedef bl::logger<conditions> my_logger_type;

// in impl
my_logger_type log;
log << build_type::server() << "some logging";

This still has non-zero cost, but as near as I can determine it's on the
same order as an empty function call.

-- 
Jason Wagner
jason_at_[hidden]

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk