BIND 10 #438: C++ Logging
BIND 10 Development
do-not-reply at isc.org
Tue Jan 4 14:48:27 UTC 2011
#438: C++ Logging
--------------------------+-------------------------------------------------
Reporter: stephen | Owner: smann
Type: task | Status: reviewing
Priority: major | Milestone:
Component: logging | Resolution:
Keywords: | Sensitive: 0
Estimatedhours: 0.0 | Hours: 0
Billable: 1 | Totalhours: 0
Internal: 0 |
--------------------------+-------------------------------------------------
Changes (by stephen):
* owner: stephen => smann
Comment:
''Comments quoted are taken from the relevant documents''
> Is there a trace component (I couldn't find one, but I'm sure that I
could have missed it)?
> If there is, perhaps point to it here. If there isn't, I wonder if it
might not be implemented
> in a way similar to DEBUG?
(I assume here that trace means query tracing.)
Messages are output via "loggers" and a program may have multiple loggers,
each with a unique name. In cases where a component corresponds to a
specific module, all messages within the module are output using a single
logger named after the module. Trace messages - which can be generated in
any part of the program - will use a single global logger (named "trace").
The problem with using levels is that enabling a specific level enables
all levels above it (e.g. enabling ERROR also enables FATAL). If TRACE
were lower than DEBUG, enabling TRACE would enable all DEBUG messages; if
higher, then enabling DEBUG would enable all TRACE messages. (The idea
that enabling a level enables all levels above it is common in logging
packages such as log4cxx; following the paradigm allows use of such
packages.)
The suggested method is a compromise. It allows for different levels of
trace messages, e.g. basic tracing at level INFO, more detailed tracing at
various DEBUG levels. If some further discrimination is required (e.g.
enable TRACE only in module XYX), the solution would be to have several
differently-named trace loggers and enable/disable them as required.
> Is it obvious how a logger gets the data from the config database?
At the moment, no. The configuration data is in JSON format, so use of a
C++ JSON parser would seem to be mandated. However this introduces yet
another package dependency in BIND. Perhaps a better way would be to use
an embedded Python module. The configuration would only need to be read
at startup or when the configuration changes, so performance is not an
issue.
> It isn't clear to me, given the explanation in parentheses, why the
number of arguments is
> limited to 4.
It's a case of possible method of implementation getting into the design
:-)
With multiple destinations there is a possibility that different
destinations want the data in different formats. So one destination might
want a message fully expanded with the text of the message. Another might
just want the error code and the arguments. As noted in the text, the
message is passed around as a single string. So the idea is that the
identifier and all arguments are converted to strings and these are
concatenated (using a suitable separator character). This single string
is then passed to the relevant modules which can separate them and, if
required, look up the message text and do the formatting.
The conversion of numeric arguments to strings is easily done in C++ using
inline template methods, e.g.
{{{
template <typename T1, typename T2, typename T3>
void info(T1 code, T2 arg1, T3 arg2) {
string result = boost::lexical_cast<string>(code) + string('\0') +
boost::lexical_cast<string>(arg1) + string('\0') +
boost::lexical_cast<string>(arg2);
:
}}}
(with the obvious restriction that the strings may not contain the
embedded null).
More signatures can be added but if more information is required, a
solution would be to define a message with a general argument (e.g.
"EXCEPTION, exception occurred, reason %s"), formal all the arguments as a
text string and pass that text string as a single argument.
The restriction on four arguments is basically down to the number of
template signatures. I've suggested a limit of four arguments (which
means a total of twenty method definitions - four for DEBUG, four for INFO
etc.) but the number could be higher.
> But the appender must conform to the Logger API as its input source,
i.e. the message
> object. Or am I missing something?
As the internals of the logger are so heavily dependent on the package
being used, it seemed easiest to leave appender implementation as package
dependent - at least for now. I will re-visit this when I get round to
implementing an appender; it may be that an API can be defined at that
point.
> For what it's worth, I am a big fan of using #defines and numerical
codes for
> this sort of thing. static const char* isn't always the right thing to
do (after
> all, there are times when it is appropriate to use goto statements) and
in this
> case, the use of the internal #define code hides the underlying
numerical value
> (which could be organized or not) and the code could be translated into
a string
> in something like an enum.
I prefer the idea of a number as well. However, in this case I am coming
round to the idea that a string is the better idea, principally due to the
need for message replacement.
If the code (used in the program) is just the message ID string, it is
easy for the user to provide message replacements. They provide a file
mapping message ID to replacement text. Internally, the message
ID/message text translation is stored using a std::map, and so lookup is
easy.
If we use numerical codes, either the user must associate the replacement
message with a number (which is somewhat unfriendly), or they still
associate it with the message ID and we have to provide a way of
associating the ID with a number. This means that instead of just a simple
ID to text lookup being required, we require:
* Given ID access text (to allow the user to do message replacement)
* Given numerical code access ID (to include the ID in the log message)
* Given numerical code access text (to include the text in the log
message)
It's this additional complexity that is making me prefer the string
solution.
--
Ticket URL: <http://bind10.isc.org/ticket/438#comment:3>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list