Boost logo

Boost :

From: vicente.botet (vicente.botet_at_[hidden])
Date: 2008-04-14 09:52:20


Hello Christian,

I think that I start to understand your concern. We need to see which is the
minimal interface a log library must have in order to be be used by a
library allowing user customizations.

I dont know why a thought that this interface was already provided by the
Boost.logging library, and maybe it was in his first version, but it is sure
that it isnot the case for log2.

From: "Christian Holmquist" <c.holmquist_at_[hidden]>
To: <boost_at_[hidden]>
Subject: Re: [boost] thoughts on logging library: orthogonal
runtimeconfiguration

> On 09/04/2008, vicente.botet <vicente.botet_at_[hidden]> wrote:
>> From: "Christian Holmquist" <c.holmquist_at_[hidden]>
>> Subject: [boost] thoughts on logging library

<snip>

>> >
>> > #define BOOST_ASIO_LOG_ENABLE
>> > #define BOOST_ASIO_LOG_MIN_LEVEL boost::log::level::debug
>> > #include <boost/asio/asio.hpp>
>>
>> I'm not sure it is a good idea to place these macros in the source code
>> files. First you can define the macros on several header files, needing
>> some
>> test undef and so one. Which will be the result when two source files
>> (.cpp)
>> defines different configurations? IMO the macros you purpose should be
>> defined at the build level of the executable.
>
> Of course.
> It was only an example of the defines.

I prefer :)

>> I really think that we need runtime configuration and I suspect that
>> this
>> configuration should be centralized. But I don't think that this is a
>> particular case of the logging library. logging and configuration are
>> orthogonal. A runtime configuration library will be welcome and should
>> be
>> able to configure the asio log level as well as other configurable
>> features
>> as for example the boost::log::level of a global log.
>>
>> Let me show how I will use the current Boost.Log library interface if I
>> were
>> the maintainer of asio library.
>> I will define un internal macro like that:
>>
>> #ifdef BOOST_ASIO_LOG_ENABLE
>> #define BOOST_ASIO_LOG(LEVEL, MSG) \
>> if (boost::asio::log_level <= LEVEL)
>> { \
>> BOOST_LOG(LEVEL) << "[asio] " << MSG \
>> }
>> #else
>> #define BOOST_ASIO_LOG(LEVEL, MSG)
>> #endif
>>
>> I will place the definition of the boost::asio::log_level variable in a
>> specific header file, which should be included by the user in only one
>> comilation unit.
>>
>> // boost/asio/log_level_def.hpp
>>
>> #ifndef BOOST_ASIO_LOG_LEVEL_DEF__HPP
>> #define BOOST_ASIO_LOG_LEVEL_DEF__HPP
>>
>> #ifndef BOOST_ASIO_LOG_LEVEL_DEFAULT
>> #define BOOST_ASIO_LOG_LEVEL_DEFAULT boos::log::level::debug
>> #endif
>>
>> #include <boost/asio/log_level_fwd.hpp>
>>
>> namespace boost {
>> namespace asio {
>>
>> atomic_log_level_type log_level=BOOST_ASIO_LOG_LEVEL_DEFAULT;
>>
>> }
>> }
>>
>> #endif
>>
>
> Sure, this could work, but I think asio::log_level should be a
> function returning the current level instead of a global variable.
> Then it's up to the user to choose where from this variable is read
> and how it's updated. There may be more things to consider, again
> something for a log library to decide best practice.

Why? Do you mean that you prefer

    if (asio::log_level()) ...
and
    asio::log_level() = debug

to

    if (asio::log_level) ...
and
    asio::log_level = debug

?
Why asio::log_level should not be an object?

>> As the boost::asio::log_level reading and writing could be done by
>> different
>> threads the read and write operations must be atomics. So
>> atomic_log_level_type must be convertible to boost::log::level and must
>> is
>> assignable from boost::log::level atomically.
>>
>> typedef atomic<boost::log::level> atomic_log_level_type ;
>>
>> An other history is how can we configure the boost::asio::log_level
>> variable
>> at runtime?
>>
>> Well this can be done in a lot of ways. But at the end what you realy
>> need
>> is to do a the following
>>
>> boost::asio::log_level = new_value;
>>
>> Is for this raison that the atomic_log_level_type assignation operator
>> must
>> be atomic.
>>
>> We can use also a configurator class which store a mapping between some
>> key
>> and a reference of such variables.
>>
>> rtc::runtime_configurator<std::string, atomic_log_level_type&> conf;
>>
>> Note the mapped type is a reference to the real atomic_log_level_type.
>> The advantage is that now the owner of the configured variable do not
>> depends on how this variable is configured.
>> It is up to the user to make the association between the configured
>> variable
>> and the configurator.
>> This runtime_configurator could be based on the property_tree library.
>>
>> The user can add the configurable variables as follows
>>
>> conf.register("boost.asio.log_level", boost::asio::log_level);
>>
>> The runtime configuration library can provide a callable backdoor to
>> configure any registered variable using cli, as for example
>>
>> $$ push boost
>> $$ push asio
>> $$ log_level = debug
>> $$ log_level
>> $$ pop
>> $$ asio.log_level = debug
>> $$ asio.log_level
>>
>> The push and pop command are used to change the context.
>> the var = value command assign the value, and the variable command
>> prints
>> its value
>>
>> This backdoor will look up the corresponding configurable variable and
>> read
>> o write depending on the command.
>>
>> To allow symbolic values wee need manage with the conversion from
>> std::string to boost::log::level and vice versa. We can use the
>> lexical_cast
>> library for this purpose as soon as the we have the output and input
>> operators defined for boost::log::level.
>>
>> If the register is done at initialization time before the backdoor
>> thread is
>> lunched, the runtime_configurator instance will be used only for reads,
>> so
>> no thread safety problem at the map or tree_map level.
>>
>> Then the user can start the backdoor as follows
>> boost::thread configurator_backdoor(rtc::backdoor)
>>
>> The user can provide its own external configuration means with a
>> graphical
>> interface if he consider convenient.
>>
>> Do you think that a such runtime configurator variables library has a
>> place
>> in Boost?
>
> I haven't thought about it, but it sounds useful. It's probably an
> often reinvented wheel.

I thougth that Boost was there exacltly for that. To avoid that every one
reinvent the wheel. Am I wrong?
Isn't the Boost.Log library a wheel reinvented by every body?

>> This could be a complement to a larger configuration library starting
>> from
>> program_options, extending to property_tree storage and making the CLI a
>> specific parser, other parsers can be reading from some configuration
>> file
>> formats, the backdoor I'm proposing or other as has been already
>> proposed in
>> this mailing list (CGI parameter parser).
>>
>> <snip>
>>
>> > Configuring the above with a compiled library like boost serialization
>> > is an interesting task as well, that I definitely think should be
>> > addressed. could be that the flexibility decreases some in such a
>> > scenario, or it could be configued in site-config.jam or whatever.
>>
>> Once the serialization library provide traces or log, if you want to use
>> the
>> serialization library with logs you should add a define at compile time
>> e.g. -DBOOST_SERIALIZATION_LOG_ENABLE and link with the serialization
>> logged
>> variant e.g. -lboost_lserialization.
>>
>>
>
> Agreed. Should the maintainer of serialization invent his own
> build/jam/config thingie to make this possible? I think not.

Please, could you be more precise? What do you propose instead?

>> > Is this along the line what boost.log has in mind, or will it be a
>> > logging library not to be used by the boost libraries themselves?
>>
>> I think that this has nothing to be with the Boost.Log library. It is
>> up to
>> the other Boost libraries to use or not the loging library.
>
> Sorry, I disagree, I think that it has everything to do with the log
> library.
> It should show how boost libraries should use the library to make them
> customizable for end users of boost.

As I said I think that I start to understand your concern. We need to see
which is the
minimal interface a log library must have in order to be be used by a
library allowing user customizations.

Once this minimal interface will be clear I think that if a library provides
logs, it is up to the library autor to describe how to configure it. Isn't
it?

The role of a Boost.Configuration library will be to provide generic
mechanisms to configure applications and of course libraries.

>> The single flaw is that these libraries either must use a single global
>> variable log or
>> extend their interface with a log parameter. This problem has already
>> been
>> discused during the Boost.Singleton review.
>>
>
> Some boost libraries already use singletons. Religious views on
> globally accessible data aside, what would be the flaw with a single
> log instance?

I have no particular problem, I'm not the maintainer of any Boost library
:).
I'm not so sure that there will be a lot of maintainers that like to
use a external global variable, or even add to his library some logs. Are
there some Boost maintaniers that plans to add log support for his library
once the Boost.Library is accepted?

Any way and independently of which library wil have logs, as you have stated
from the begining, we need to define the minimal interface a logging library
must provide. What are really these minimal features?
* It is clear that the instantiation of the log and its configuration is
reserved to the application.
* Should work for example with the std::cerr stream.
* As the minimal logging library do not provide configuration, the output
for the default log will have a predefined format.
* Logiging client libraries should be able to be configured Boost::logging
logs and filters

Comments?

Best
_____________________
Vicente Juan Botet Escriba


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