BIND 10 #1704: log output mixed
BIND 10 Development
do-not-reply at isc.org
Wed May 23 01:50:40 UTC 2012
#1704: log output mixed
-------------------------------------+-------------------------------------
Reporter: jreed | Owner: jinmei
Type: | Status: reviewing
defect | Milestone:
Priority: | Sprint-20120529
medium | Resolution:
Component: | Sensitive: 0
logging | Sub-Project: Core
Keywords: | Estimated Difficulty: 15
Defect Severity: N/A | Total Hours: 0
Feature Depending on Ticket: |
Add Hours to Ticket: 0 |
Internal?: 0 |
-------------------------------------+-------------------------------------
Comment (by jinmei):
Okay...I was impressed about the effort of making it testable, but I'd
like to have some more design level discussion.
First, I have to say I'm not really excited about making the `Logger`
class and the way it's used. I'm not sure why some of the
`Logger` or `LoggerImpl` classes have virtual methods (these classes
doesn't seem to be used as a base class), but ignoring these
(ineffective) "virtual" declarations, the wrapper trick really
introduces polymorphism with its own costs such as vtable lookups.
Since some of the logger related methods are expected to be very
efficient (e.g., getSeverity()), I'd like to keep the overhead as
small as possible, especially if the added overhead is just for
testing.
Second, the definition of LoggerWrapper seems to be too ad hoc. It's
mostly a just redundant wrapper and only with fatal() being a virtual
method. There's no documentation about it, so the class definition
just looks so awkward unless you read every other part of the code
including the tests that use it.
Third, with this change it exposes the originally private `LoggerImpl`
at the application-facing `Logger` level as a mutable pointer. While
I understand sometimes ugliness is the least bad for better
testability, this hack seems to be too dangerous and dirty.
Fourth, the separate file lock class isn't tested. Actually, as a
separate class it should be easier to test (also as Stephen
commented), and once we can confirm this class really handles
inter-process synchronization, we'd be able to simplify the logger
tests with some level of abstraction. That would also address the
above concerns.
So, if I may, I'd like to suggest something like this:
- Introduce a base class for interprocess synchronization (at this
level it could even be any type of conceptual lock; doesn't have to
be file based).
- Define a flock based derived class. write tests for it. also note
that it could be a trivial wrapper for something like
boost::file_lock, in which case we could even omit our own tests, to
the extent we trust that library.
- Also define a mock lock class for tests. It could be, e.g., just
dumps log message for lock/unlock operations.
- The `Logger(Impl)` class holds a pointer to the base
interprocess-sync class. By default, it instantiates the file-lock
based one and holds it.
- Allow an application of the `Logger` to dynamically replace the
internal lock object for `Logger`. The logger test uses the mock
lock class, and simply checks if log output is encapsulated with
lock and unlock. No interprocess checking is necessary here.
- Within the logger, we still use a lightweight wrapper like the
util::file_lock class for exception safety. It would be constructed
with a reference (or pointer) to the base lock class instead of FD.
This way, we could separate the complicated interprocess test case
from logging specific tests, which have their own complexity. Also,
we don't have to tweak the main logging related classes. And, the
synchronization class can be further flexible: for example, it could
even be a "null" lock if the user knows there should be no lock issue
or it's very performance sensitive and the user is willing to accept
the consequence of omitting the lock such as mixed log outputs.
What do you think?
Comments on some other points:
- the file permission trick seems to be acceptable (while subtle), but
I'm not sure if the log library is the right place to implement it.
Logging itself is pretty generic, while the permission issue is very
specific to how the entire BIND 10 system is working. So, making it
group writable may not always be appropriate. Now the boss process
tries to remove the file at the end of its lifetime, I wonder
whether it makes sense if we have the boss process creates the file
with necessary permission setting at the beginning, and let the
logging library just open it.
- similar to the previous point, since we have other standalone progams
that (perhaps implicitly) use the logging (at least dbtool for now,
and I guess it's also the case for loadzone), we might even want to
make the file path or whether to use locks customizable. If we
write a "zone checker" script, e.g, which can be run by anyone as an
ordinary user, we don't want to make it emit noisy logs or even fail
to run because of the logging issue, right?
- As for changelog, it basically looks okay, but I'd note log file
permission issue. Also, for that reason, I'd add the '*' mark.
- As for the note about environment variables, I was thinking about
part of doxygen. But in the case of logging, it may also be part of
README because it already has it. Definitely not the guide.
Below I'm making some general comments on the code itself, although
they may become moot depending on the result of the design level
discussions above.
'''general'''
I've noticed several editorial/style issues and fixed them. They are
basically documented in the style guide wiki. Please take a look at
it again.
'''log_messages'''
- I don't like to include test specific log message
(LOG_LOCK_TEST_MESSAGE) in the main source.
'''file_lock.cc/h'''
- naming convention: file_lock class should be (something like) FileLock
- why is the destructor defined as virtual?
- documentation: overall class description is needed. In general all
methods need documentation. If any of the method can throw an
exception, it should be documented (if it never throws it's better
to say so explicitly). Parameters need to be described (also for
the constructor).
'''logger_impl.h'''
On LoggerWrapper: my compiler complains if it doesn't explicitly
define the destructor and make it virtual:
{{{#!cpp
virtual ~LoggerWrapper() {}
}}}
when it has other virtual method.
--
Ticket URL: <http://bind10.isc.org/ticket/1704#comment:46>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list