Boost logo

Boost :

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


Hi Christian,

----- Original Message -----
From: "Christian Holmquist" <c.holmquist_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Monday, April 07, 2008 11:46 PM
Subject: [boost] thoughts on logging library

> Hi,
>
> I saw that the previously proposed logging library went into the
> review queue again, so I thought of pointing out some remarks prior
> the actual review.
>
> First of all, I think that a boost logging library should come up with
> one, and one only, way of expressing a log line.
>
> BOOST_LOG(some, kind, of, args);
>
> Now, how should the interface of BOOST_LOG(...) look like? To find
> that out, I'll start by explaining how I would like boost log to
> behave from a users point of view, for instance using boost.Asio.
>
> #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.

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 boos {
namespace asio {

atomic_log_level_type log_level=BOOST_ASIO_LOG_LEVEL_DEFAULT;

}
}

#endif

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?
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.

> 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. 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.

>
> Regards,
>
> Christian

Do you think that this approach allows to configure the libraries using the
log library?

Best regards

_____________________
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