BIND 10 #555: C++ Logging - multiple destinations and configuration

BIND 10 Development do-not-reply at isc.org
Wed Jun 1 14:15:47 UTC 2011


#555: C++ Logging - multiple destinations and configuration
-------------------------------------+-------------------------------------
                   Reporter:         |                 Owner:  vorner
  stephen                            |                Status:  reviewing
                       Type:         |             Milestone:
  enhancement                        |  Sprint-20110614
                   Priority:  major  |            Resolution:
                  Component:         |             Sensitive:  0
  logging                            |           Sub-Project:  DNS
                   Keywords:         |  Estimated Difficulty:  8.0
            Defect Severity:  N/A    |           Total Hours:  0
Feature Depending on Ticket:         |
        Add Hours to Ticket:  0      |
                  Internal?:  0      |
-------------------------------------+-------------------------------------
Changes (by stephen):

 * owner:  stephen => vorner


Comment:

 Thanks for the very comprehensive review:

 > Is there any reason why the !LoggerManagerImpl is in separate file?...
 You are right about optimisation, but in this case the code has been put
 in a separate file because it very cleanly separates the underlying
 implementation from the interface.  If we need to replace log4cplus, then
 (theoretically) we should only need to replaced the xxx_impl.* files and
 nothing else.  The extra overhead caused by lack of optimisation should be
 negligible compared with the processing done by the various functions.

 > In several conversion functions, when it gets invalid input, it returns
 something anyway and logs a warning. Is there any reason for such
 behaviour?
 It is for robustness - I didn't want BIND10 falling over if someone made a
 spelling mistake in the configuration file.  (Also, it follows the Jon
 Postel dictum: "Be conservative in what you send and liberal in what you
 accept".) However, in some places no warning was logged and the error
 silently ignored.  In these places I've logged a message before coercing
 the value. (Throwing an exception was an option, but is many cases is
 likely to result in program termination.  Logging - at least to the
 console - is enabled early on in the program and so is used where
 possible.)

 > If we ignore the first point for a moment, why is void
 LoggerManagerImpl::processEnd() {} in logger_manager.cc? Shouldn't it be
 in logger_manager_impl.cc?
 It should - it was put there temporarily during testing and never got
 moved. (In fact, being empty it has been moved to logger_manager_impl.h.)


 > In LoggerManager::init, the comment „Log using the logging facility root
 logger“ isn't right. It logs using a logger with name "log".
 An example of where the code was updated but not the relevant comment.
 Removed the word "root" - it logs using the logging facility logger.

 > I don't understand this comment: „There are - sort and remove any
 duplicates“ ‒ what does the „There are“ mean?
 It referred to the previous comment ("Check if there were any duplicate
 message IDs"), but the comment has been clarified.

 > The comment and code don't match:
 > !// File successfully read, list the duplicates
 Comment has been updated.


 > When logging the exception, you use a switch to specify number of
 arguments:
 > :
 > The current implementation actually supports a cycle to provide
 arbitrary number of arguments. It should AFAIK work if you save the result
 of logger.error to variable and then call .arg on it as many times as
 needed (to be implementation detail agnostic, replacing the variable with
 it's result each time, but it would currently work without it as well).
 The original was a direct replacement for the time when a varadic argument
 list was used.  The method you suggest works (although I had to add the
 assignment operator to the Formatter class) and has been implemented.  In
 doing this I noticed that there is no check that a message is generated if
 there is a problem opening a local message file, so one was added.  The
 test also checks that the above code formats the message correctly.

 > This comment is probably true, but it's misleading (it says what happens
 inside, but sounds like there would be no more logging after this)...
 > !/// Given a list of logger specifications, disables all current logging
 > !/// and resets the properties of each logger to that given.
 >
 > Would it be better to say something like it replaces configuration and
 sets it to the new one?
 Yes, and this has been done.


 > LoggerManager::init says This must be the first logging function called
 in the program. What happens if it isn't? Like if some object is
 statically initialized and uses a function in it's constructor which does
 some logging, therefore it's called before main starts, will it crash, or
 will it just log into some default destination?
 The consequences have been noted in the header of the init() functions in
 !LoggerManager and !LoggerManagerImpl.  There will be no crash, just
 messages written to stderr that log4cplus has not been initialized.

 > And, it would be nice to say that the file parameter might be NULL.
 Done, although it is recommended that this not be the case.

 > What does the second sentence mean?
 The comment has been updated.

 > logger_manager_impl.cc talks in two comments at the beginning of the
 file about reset, but there's no reset near it.
 One of the comment blocks has been removed.  The reset talked about at
 that point is in the call to log4cplus's
 getDefaultHierarchy().resetConfiguration()

 > class !UnknownLoggingDestination : public isc::Exception { ‒ shouldn't
 it be in some header file? How can someone catch it?
 Well noticed.  The definition of the exception has been moved to the
 public header file logger_manager.h

 > This isn't too extensible. Maybe we don't need to do anything about it
 now, but in future, we might want to add plugins or something to add
 logging destinations:
 Agreed, but I too think we should defer it.

 > Console test ‒ is there a need to use temporary files? Pipes could be
 enough. Or, alternatively, both stdout and stderr could be redirected at
 once, requiring only one run of each testcase instead of two.
 I suggest leave it as is now it has been written.  Each test checks one
 particular item and is very simple.  I don't think the added complexity is
 worth changing it.

 > This might be wrong, there's no setting of the sentinel char and no
 strncpy:
 It was - comment removed.


 > Well, the compiler might warn because there's a race condition. Using
 more complicated code with the same problem to only silence the compiler
 seems wrong. Is it really needed to delete the file? Wouldn't closing be
 enough
 I think that the race condition is such that two calls to tmpnam at
 exactly the same time might generate the same name.  By creating the file
 in the process, the condition is avoided.  I'm not sure if deleting the
 file re-introduces the race condition, but I've taken that out of the
 !SpecificationForFileLogger class.  Deleting the file before the test now
 happens in just one place, where the ability to create the log file if it
 does not exist is checked.  In other places I've followed your suggestion
 - the file is not deleted and messages are appended to it.


 > What is the reason of this class? And even if you want to group tests
 together with TEST_F instead of TEST, what is the reason for the empty
 constructor and destructor?
 > :
 > The same for !OutputOptionTest.
 They were just place holders.  However, you are right - I've removed them
 and converted the TEST_Fs to TESTs

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


More information about the bind10-tickets mailing list