
Hi Christian, ----- Original Message ----- From: "Christian Holmquist" <c.holmquist@gmail.com> To: <boost@lists.boost.org> 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