The ZOOM ErrorLogger Package
Fundamentals
Purpose and Scope
The purpose of this package is:
- to let user code issue ("log") error and warning messages;
- to provide a uniform syntax and set of concepts for logging,
across the different experiments and different groups in an
experiment;
- to provide a uniform and sensible logger behavior, in terms of
information output and formatting;
- to provide means of controlling multiple log destinations, output
limitations, and other behavior;
- to be integrated with the ZOOM exception mechanism, such that a
user may ZMthrow an exception containing an error message to be
logged;
- to allow for (to the greatest reasonable extent) customizations
tailoring to various environmental and system consideration.
In terms of concepts explained below, a "physicist" inserts logging statements
into the code. These work because a "frameworker" has set up the logger,
specified one or more log destinations, and established various behavior
controls. A standard form of behavior is performed when errors occur or
summaries are requested.
Ease and cost of use is critical:
-
Overall, using the standard features and and basic controls is not
burdensome:
- very easy for the physicist to use (one
#include,
and then simple statements to issue or add to an error message)
- clear and simple for the frameworker to set up (3-5 lines of code,
plus one line for each option you want to control)
- zero runtime cost in the main program loops unless messages are
actually formed and logged
- not a heavy burden in terms of code to compile or executable code
pulled in
The package is designed such that certain things can easily be customized
without discarding the rest.
For instance, the formatting of the error text may be modified beyond the
ways the standard framework controls permit; or the customization may avoid
the use of C++ features and
system support assumptions that may not be desired in a Level 2 context.
Having said what the package does, we set some boundaries by listing
issues this package does not address:
- Beyond providing clear ways to derive classes for customization, the
issue of implementing these customizations is not addressed.
- This package addresses issues of "collective logging," that is,
coordination by some central entity of error log destinations stemming
from multiple processes, in the simplest possible manner:
-
The collection mechanism leaves the details of interprocess
communication completely up to the experiment.
-
A way for code to access a history of error messages is provided
in the form of a (flitered) std::list of error message objects.
If this list is desired, the user code is responsible for periodically
examining and clearing it.
Classes and Concepts
Let us define a "physicist" as anyone coding "on top of" some framework level,
whose code may want to issue log messages. And define a "frameworker" as the
person providing the means for the physicists to do things (like error logging)
WITHOUT extraneous knowledge of the mechanism; the frameworker, in a sense,
controls the flow of the job.
The structure of the framework we have in mind is that there are a collection
of classes, which for the purpose of this document we shall refer to as
"modules" (D0 calls these packages). Each module is a class derived from a
standard Module class; and the overall framework has some way of registering
all the modules and seeing that some key method of each one is invoked when
appropriate. Anything in the framework above the level of modules, or in the
Module base class itself, we will say is in the realm of the frameworker;
anything in methods of the derived specific modules is said top be physicist
code.
The fundamental idea is that the framework instantiates
an ELadministrator
object, and through its methods attaches various forms of sinks derived from
ELdestination. Then the base Module class will have an instance of
ErrorLog as a protected (or public) variable; for illustrations in this
document we assume that is assigned the name "errlog."
Since this is a variable
at module scope, all methods of the specific module class can use errlog, but
methods of different modules will be using different ErrorLog instances; that
is, an ErrorLog owns information about the module.
The variable "errlog" makes the logger is made available to the user, who can
issue errors in a syntax like
errlog (ELerror, "Too much energy") << "E = " << totalEnergy << endmsg;
The frameworker, through the ELadministrator that the framework instantiates,
can control aspects of the behavior of the logger and the
individual destinations, such as limits on how may times a given message
is to be output.
This ELadministrator is not in scope in the user code in individual modules,
so only the framework has this centralized control.
Key Classes
The first three of these classes are of relevance to the ordinary physicist
user.
The remaining classes are of relevance only to the frameworker.
- ErrorLog
-
Encapsulation of the fundamental behavior supporting
issuing of messages. Each module would ordinarily
instantiate one of these, and make it available to
all its subroutines; we assume it would be called
errlog.
- ELseverityLevel
-
A class allowing for the definition of a fixed set of
severity levels. The package provides the levels.
- ErrorObj
-
An error message object. A program can prepare
one of these independent of the act of logging it.
The users forms an ErrorObj when the ZMthrow mechanism
is used in conjunction with error logging.
- ELadministrator
-
Object providing methods for overall control of the
error logger. This class uses the "Singleton" pattern.
The framework should instance() one ELadministrator,
and through it, attach various ELdestination sinks
for log message to flow to.
- ELdestination
-
Encapsulation of the behavior of a "sink" for the
logged information to go to.
- Derived from ELdestinationI:
- ELoutput
-
A destination implementing our agreed behavior and
formatting for sending messages to an ostream (which
could be cout, cerr, or an ofstream for a file).
- ELcollected
-
A destination derived from ELouput, which invokes
a user-supplied transport mechanism to send the
formatted message which ELoutput would have streamed,
to a central message logger.
- ELerrorList
-
A destination derived from ELouput, which inserts
each ErrorObj onto a std::list. User code can
use methods of std::list to access the objects
and/or clear the list, and can use methods of
ErrorObj to get information about each message.
- ELstatistics
-
A destination implementing storage and output of
message frequency statistics and summary tables.
- ELdestControl
-
An object to act as a proxy for an ELdestination
providing the full spectrum of public methods
available to control a destination's behavior.
- ELcontextSupplier
-
An interface for an object providing methods
to obtain text describing run,
event, and other framework-wide concepts.
- ELstring
- Because quite a few methods throughout this package
work with strings of characters, it is very useful
to have a data type with the semantics of std::string.
To allow for substitution of a different class,
(for example in a Level 2 context where generic
strings would be unacceptable) the
interfaces use ELstring instead. Our provided
classes typedef this to std::string.