BIND 10 #2445: suppress initial log
BIND 10 Development
do-not-reply at isc.org
Wed Dec 5 08:16:25 UTC 2012
#2445: suppress initial log
-------------------------------------+-------------------------------------
Reporter: jinmei | Owner:
Type: defect | jinmei
Priority: medium | Status:
Component: Boss of BIND | reviewing
Keywords: | Milestone:
Sensitive: 0 | Sprint-20121218
Sub-Project: Core | Resolution:
Estimated Difficulty: 4 | CVSS Scoring:
Total Hours: 0 | Defect Severity: N/A
| Feature Depending on Ticket:
| Add Hours to Ticket: 0
| Internal?: 0
-------------------------------------+-------------------------------------
Comment (by jinmei):
Basic approach looks good. I have several points to discuss in detail
though.
'''changelog'''
I think we need a changelog entry for this task.
'''design'''
- In general I'd like to avoid relying on singleton whenever possible
(for many reasons, but most notably because it's very unfriendly
with tests). In this case it seems we can avoid making the buffer
object a singleton: let createBufferAppender() make a new one for
the given logger, and maintain it in the appender. In
`LoggerManagerImpl::processSpecification` we retrieve it from
the logger using getAppender() (we need RTTI here though), and get
access to the internal buffer and flush it.
'''log_buffer.h'''
- If I understand it correctly, I think `friend` is too strong a tool
in this case:
{{{#!cpp
friend class LogBufferTest;
}}}
AFAICS (and also as commented in the code) the only purpose for the
`friend` is to give `LogBufferTest` read-only access to `stored_`.
In that case I'd rather provide a read-only getter for the vector,
noting it's only for testing and it's possible we'll remove/change
the interface (so normal apps shouldn't use it). Also AFAIC, we
could even hide the fact that it's a vector: all we need for the
test seems to be an interface to return the number of stored
messages.
- flush() isn't documented.
- `flush_stdout` should be renamed `flushStdout` (or something) per naming
convention.
- it directly depends on log4cplus internal. My first question is
whether it's a good idea or we should introduce a higher level
interface for the concept of buffering. If the answer to the first
question is yes, maybe it's better to clarify the intent by renaming
log_buffer.h to log_buffer_impl.h. Same for .cc
- is it okay to store `InternalLoggingEvent` objects in a vector?
This class seems to be inheritable according to the log4cplus doc,
so in general there can be a risk of slicing due to the inevitable
copy in the vector. To be really safe, I guess we should make a
pointer-based copy by `InternalLoggingEvent::clone()`, release it
from auto_ptr, move it to shared_ptr, and then store it in a vector.
'''log_buffer.cc'''
- I'd include `<iostream>` if we keep using std::cout etc (but see below
too)
- with this implementation, the singleton `LogBuffer` object will be
destoryed at an unpredictable timing, and its `stored_` member could
be a non empty (though which may be less likely in practice) vector
of a third-party type (`InternalLoggingEvent`). I'm afraid it's
quite fragile in terms of "static destruction" fiasco.
- `LogBuffer` constructor: a minor point in this case, but I'd initialize
`flushed_` in the initialization list.
- `LogBuffer` destructor: flush_stdout() seems to do non trivial task,
and it can throw. If the dumping behavior isn't crucial, I'm simply
releasing the stuff here; if it's necessary, I'd at least ensure no
exception (if any) leaks from the destructor:
{{{#!cpp
LogBuffer::~LogBuffer() {
try {
flush_stdout();
} catch (...) {}
}
}}}
- `LogBuffer::flush`: why is `event` copied?
{{{#!cpp
const log4cplus::spi::InternalLoggingEvent event(stored_.at(i));
}}}
I guess a reference should suffice here. See also discussion about
copying event objects and slicing above.
- `LogBuffer::flush`: what if it throws before clear()?
'''log_buffer_unittest.cc'''
- Isn't it better to use a mock appender to inspect what happens
on flush()?
- I don't understand why we need this trick (or what exactly it does):
{{{#!cpp
// If any log messages are left, we don't care, get rid of them,
// by flushing them to a null appender
log4cplus::SharedAppenderPtr null_appender(
new log4cplus::NullAppender());
logger.removeAllAppenders();
logger.addAppender(null_appender);
buffer1.flush();
buffer2.flush();
}}}
Maybe some more comments are needed.
- `LogBuffer::add()` doesn't seem to be directly tested.
- `BufferAppender::append()` doesn't seem to be directly tested.
- Related to the point of directly relying on log4cplus API, I wonder
whether the original intent is to exclude tests directly depending
on log4cplus from the unittests. I think direct unit tests are a
good practice anyway, but maybe you want to ask Stephen about the
original plan.
'''buffer_logger_test.cc'''
- I'd hide usage() in an unnamed namespace.
'''buffer_manager_impl.h'''
- `createBufferAppender`: has a non existent parameter description:
{{{#!cpp
/// \param opt Output options for this appender.
}}}
'''buffer_manager_impl.cc'''
- why is scoped_ptr.hpp included?
- `processSpecification`: due to the complexity I cannot be 100% sure,
but if I understand it correctly this change breaks existing
behavior. Consider the case only severity level is set without any
output option. Previously existing appenders are preserved, but
they are now cleaned up and replaced with a single default appender.
- `processSpecification`: this change also seems to be fragile:
{{{#!diff
- log4cplus::Logger logger = log4cplus::Logger::getInstance(
+ log4cplus::Logger logger;
+ // If this is an 'empty' specification, just set the root logger
+ if (spec.getName() == "") {
+ logger = log4cplus::Logger::getInstance(getRootLoggerName());
+ } else {
+ logger = log4cplus::Logger::getInstance(
expandLoggerName(spec.getName()));
+ }
}}}
I guess it's intended to be called via `LoggerManager::process()`,
but what if a spec whose name is "" is explicitly given? In the
previous code it result in
{{{#!cpp
logger = log4cplus::Logger::getInstance(expandLoggerName(""));
}}}
but now it results in
{{{#!cpp
logger = log4cplus::Logger::getInstance(getRootLoggerName());
}}}
- Considering these, I guess we should handle cases with buffering
more explicitly, instead of abusing existing states of the class.
For example, introduce a member variable to indicate whether any
spec has been given, and flush-buffer-and-remove-it only for the
first time it's configured.
'''logger_manager.h'''
- what's the purpose of the change?
{{{#!diff
- for (T i = start; i != finish; ++i) {
- processSpecification(*i);
+ if (start == finish) {
+ process();
+ } else {
+ for (T i = start; i != finish; ++i) {
+ processSpecification(*i);
+ }
}}}
hmm, okay, after seeing everything I think I understand it, but it
doesn't seem to be tested, and in any case I think we should revisit
the interface (see the previous points).
- "empty iterator" should be "empty specification"?
{{{#!cpp
void process() {
// empty iterator; set defaults
const LoggerSpecification spec;
processSpecification(spec);
}
}}}
also, we don't need a temporary object in this case:
{{{#!cpp
processSpecification(LoggerSpecification());
}}}
and, like the previous case, I guess it's better to clearly separate
the interface for buffer flushing.
'''cfgmgr.py'''
- I don't understand the purpose of the changes (and there's no test
for these changes). Please explain and/or add comments.
'''log/README'''
- I'd also note that process() is normally called from
`ModuleCCSession` if the program uses the config framework (so it
doesn't do it explicitly in its program code).
{{{
be flushed according to the specification. Note that if this option is
used,
the program SHOULD call one of the LoggerManager's process() calls. If the
}}}
'''python log.cc'''
- supporting keyworded parameters is nice, but we should probably test
it.
- there's an unbalanced parenthesis
{{{
"severity (optional): one of 'DEBUG', 'INFO', 'WARN', 'ERROR' or "
"'FATAL')\n"
}}}
- s/pointed/point/?
{{{
"to be stored internally until log_config_update is called, at "
"which pointed they shall be logged."},
}}}
--
Ticket URL: <http://bind10.isc.org/ticket/2445#comment:12>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list