BIND 10 #558: Disable log4cxx dependency in logging API

BIND 10 Development do-not-reply at isc.org
Mon Feb 14 11:31:47 UTC 2011


#558: Disable log4cxx dependency in logging API
-------------------------------------+-------------------------------------
                 Reporter:  stephen  |                Owner:  jinmei
                     Type:  defect   |               Status:  reviewing
                 Priority:  major    |            Milestone:  R-Team-
                Component:  logging  |  Sprint-20110222
                 Keywords:           |           Resolution:
Estimated Number of Hours:  2.0      |            Sensitive:  0
                Billable?:  1        |  Add Hours to Ticket:  0
                Internal?:  0        |          Total Hours:  0
-------------------------------------+-------------------------------------
Changes (by stephen):

 * owner:  stephen => jinmei


Comment:

 >> If there is no reference to "initiator" in the code, what causes the
 linker to pull in
 >> this file? (But see below.)
 >
 > The same question applies to your original solution, and that's
 > exactly why I asked the question in my previous comment. This
 > approach is effective only if the call to the constructor with the
 > reference to the mesagedef_... symbol isn't removed. I didn't
 > figure out how exactly this one worked. I guess it was because it
 > happened in a different translation unit, but I was not sure about
 > that, and I was not sure whether it's always guaranteed.
 In the original solution, the reference to the external symbol and the
 declaration of the !MessageInitiator were in the header file, so were
 included in files that would be pulled into the link for other reasons.
 Although the compiler's optimiser would have probably removed the external
 reference had it been there alone (as there would be nothing in the module
 that referred to it), passing it as an argument to the !MessageInitiator -
 which the optimiser could not remove as the declaration will cause the
 running of its constructor which is in another module - should mean that
 it would remain.  So the module containing the #include should contain a
 reference to the initialization object, which should cause it to be pulled
 in.

 >> It also solves the problem of the referencing of the
 !MessageInitializer - that can be in the
 >> same file as the definitions of the the message symbols. Since the file
 will be included at
 >> link time to resolve the message symbol references, the
 !MessageInitializer object will also
 >> be included.
 > I'm still not sure if it's always guaranteed. Isn't it possible that
 > the linker detect we actually don't need "initializer" and removes the
 > corresponding code as optimization?
 I think it's unlikely under Unix, but possible under Windows Visual
 Studio.  The latter contains a "Whole program optimization" switch that
 defers the optimization to link time.  However I would have thought that
 the optimization would detect that !MessageInstantiator refers to
 !MessageInitializer whose constructor invokes !MessageDictionary which is
 referred to by other modules in the program.  It will be interesting to
 find out when we finally port BIND10 to Windows - although I suspect that
 that will be one of our lesser problems :-)


 > root_logger_name.cc
 > * regarding root_name_: to be pedantic, namespace level static is
 deprecated in C++. I would
 > use an unnamed namespace (but read the next bullet first). I'd also
 remove the trailing _ from
 > the variable name as it's not a member variable of a class.
 > * the use of namespace level static object (root_name_) opens up the
 possibility of
 > initialization fiasco again, even though it's much less likely to happen
 (consider, e.g. the
 > case where another static object calls getRootLoggerName() in its
 constructor). One compromise
 > would be to note the restriction in the documentation (such as
 get/setRootLoggerName()
 > shouldn't be used inside a constructor of a class). We could also use a
 proxy function like:
 A case of "more haste, less speed" when I made the changes.  Both points
 are entirely correct, and I've altered the code to use an anonymous
 namespace and a proxy function (and have updated the documentation).

 > I'd make things more cost:
 >
 > //extern const isc::log::MessageID MSG_DUPLNS = "DUPLNS";
 > extern const isc::log::MessageID const MSG_DUPLNS = "DUPLNS";
 Not needed.  MessageID is typedef'ed to "const char*".

 > const isc::log::!MessageInitializer initializer(values);
 Good catch, done.

 > The comment line isn't accurate: There's now no root logger declaration.
 Corrected.

 > also, does logger_xxx have to be in the namespace level? if not, I'd
 move them inside main().
 > it would generally be better to use narrower scope.
 In logger_support_test.cc I've moved one of them inside main().  This will
 be another check that the logger works at both function and namespace
 level.

 > the call to (isc::log::)init() seems to suggest the name is too generic,
 especially when we
 > omit the namespace:
 > :
 >  While it could sound redundant, I'll be a bit more verbose, e.g.
 initLogger()
 Changed.

 > why does Logger have virtual functions? It doesn't seem to be (intended
 to be/become) a base
 > class.
 For flexibility, e.g. someone may want to intercept or modify logger
 messages (or a subset of them) for some reason or another, which they can
 do by using a derived class.  When we come to doing a programme of
 comprehensive performance improvement, we can remove the virtual keyword
 if there are no derived classes.

 > maybe a matter of taste, but I'd avoid using a temporary variable
 "format":
 >
 > //const string format =
 MessageDictionary::globalDictionary().getText(ident);
 > //vsnprintf(message, sizeof(message), format.c_str(), ap);
 > vsnprintf(message, sizeof(message),
 >      MessageDictionary::globalDictionary().getText(ident).c_str(), ap);
 My preference is to keep it as it does perform small bit of of
 documentation and prevents the function call from being excessively long.

 > in general, I don't like to override the end of a buffer with a nul,
 possibly changing the
 > meaning of the string:
 >
 >          message[sizeof(message) - 1] = '\0';    // Guarantee trailing
 NULL
 >      ...
 >          chr_time[sizeof(chr_time) - 1] = '\0';  // Guarantee a trailing
 NULL
 >
 > The best is to use a sufficient size of buffer so that there should be
 no need for overriding.
 > At least it seems we should be able to do that for the latter case
 (until year 10000). And, in
 > that sense, using a magic number of "32" doesn't seem to be good.
 Besides, since both vsnprint
 > f() and strftime() should guarantee nul termination, the above code is
 actually redundant, too
 > If we worry about buggy implementation of such library functions, I'd
 rather use an assertion:
 >
 >         message[sizeof(message) - 1] = '\0'
 >         vsnprintf(message, sizeof(message), format.c_str(), ap);
 >         assert(message[sizeof(message) - 1] == '\0');
 For the format supplied, 32 is the next power of two above the 20
 characters needed for the string.  The trailing nulls are, I'm afraid, a
 hangover of long years of "C" programming with "strncpy" which doesn't
 guarantee a trailing null - I got into the habit of terminating strings
 with a null, "just in case".

 I've removed the addition of the training nulls.

-- 
Ticket URL: <http://bind10.isc.org/ticket/558#comment:18>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list