[bind10-dev] are static Logger objects safe?

Stephen Morris stephen at isc.org
Mon Jun 13 09:54:48 UTC 2011


On 10/06/2011 19:47, JINMEI Tatuya / 神明達哉 wrote:
> At Fri, 10 Jun 2011 15:47:29 +0100,
> Stephen Morris <stephen at isc.org> wrote:
> 
>> The loggers are built on the "pimpl" idiom.  All the declaration does is
>> store the name of the logger within the object - there are no
>> dependencies on other objects.
>>
>> The implementation class is instantiated using the stored name the first
>> time a method within the logger is called (which should be when
>> initialization has finished and the program is running).
> 
> I'm not so confident about that.  The following indirectly relies on a
> std::string object:
> 
> isc::log::Logger logger("some_module");
> 
> so, if a particular std::string implementation depends on some another
> static object, a strange thing will happen.

True, although given that std::string is part of the standard C++
library, I think it unlikely that it would be implemented in such a way
as to fail when used (legally) as a static external variable.

However, if you are concerned, we could always alter the code such that
the name is stored in a char array.

> 
> We should (in general) also worry about the other direction of
> dependency, i.e. dependency *to* the static Logger object.  What if
> (though admittedly as a result of a bad practice) an application does
> this?
> 
> namespace {
> class SomeInitializer {
> public:
>     SomeInitializer() {
>         LOG_DEBUG(logger, DBG_TRACE_BASIC, SOMETHING_INITIALIZED);
>     }
> };
> 
> SomeInitializer init;
> }
> 
> As you know this type of fiasco can be avoided relatively easily via a
> proxy factory function:
> 
> isc::log::Logger&
> getLogger() {
>   static isc::log::Logger logger("some_module");
>   return (logger);
> }
> 
> SomeInitializer::SomeInitializer() {
>     LOG_DEBUG(getLogger(), DBG_TRACE_BASIC, SOMETHING_INITIALIZED);
> }

As the logging has not been initialized at that point (it it initialized
by a function call, probably from main()), it is unlikely to work even
with the presence of proxy factory functions.

All the static logger does at initialization is store the name of the
logger.  The first time any logging function is run, it instantiates the
underlying logger implementation class and stores a pointer to that. The
implementation object in turn locates and stores a reference to the
log4cplus logger.  This means that any subsequent call using the static
logger immediately gets the pointer to the log4cplus logger without the
overhead of instantiating a string and doing string comparisons to find it.

The idea of this is to reduce run-time overhead.  Even if logging is
disabled, automatic logger objects will still have to be instantiated
because the decision whether a message is logged is a run-time check,
not a compile-time one. I wanted the overhead of not logging something
to be a small as possible and this was one way of doing it.  (The use of
macros to avoid argument evaluation when a message will not be logged is
another.)

Stephen



More information about the bind10-dev mailing list