How the Physicist Logs Errors
When an anomolous condition occurs, or when it is necessary to log some information, the physics code can use the ErrorLog directly to log messages of various severities. The information comes out in each of the desitnations, filtered according to what the framework has specified, and with suitable time, module, and context information attached.
The framework may also provide one or more ZMexception types derived from ZMxel. This allows the physics code to use the ZMthrow exception mechanism, which supports error handlers and so forth. ZMxel exceptions make use of the ErrorLogger mechanism: They take an ErrorObj argument, and if information is to be logged, they hook into the same ErrorLog. Thus you can use the Exceptions package and also get the formatting, dispatching and statistics capabilities of the ErrorLogger package.
Each module has an object at scope of the Module class, which for illustration sake, we will name "errlog." (The steps the writer of the base Module class must take to establish this log object are presented in How the Module Sets Up errlog.)
So the physicist working in a methods of that module sees "errlog" as an instance of ErrorLog. A physicist coding for a different module will see some other instance of ErrorLog (with the same name "errlog" if things are set up as we recommend). But these are thin shells attached to a single instance of an ELadministrator object that represents the actual logger.
A logger can be associated with one or more destinations. Each destination represents a "sink" for error information; it is a class with methods to accept and deal with error message information, and to allow the frameworker to control various behavior aspects. In any event, the frameworker has established the logger and set up the destinations (possibly driven by information from a job control file). The physicist logging errors need not be concerned with the destinations which have been set up.
To get the headers allowing the use of ErrorLog, the compilation unit has to include one header:
#include "ErrorLogger/ErrorLog.h".
However, since the physicist code is going to be part of a class that is derived from a Module base class, and the Module base sets up errlog, that will already have included the necessary ErrorLog.h. So in normal use the physicist does not have to include that line; nothing extra need be included to get access to errlog.
Also, since this product is namespace protected, the user must specify that namespace zmel is in general use:
using namespace zmel;
ZOOM provides a mechanism to use if you wish the use of namespaces to be disabled/enabled depending on a define. Instead of "using namespace zmel":
ZM_USING_NAMESPACE( zmel ) /* using namespace zmel; */
errlog (ELerror, "Too much energy") << "E = " << totalEnergy << endmsg;
a b c d e f
Here is the breakdown of this syntax:
An alternative to doing errlog (sev, id) is to use the provided ERRLOG macro:
ERRLOG ( sev, id )
equivalent to
errlog ( sev, id ) << __FILE__ <<":" << __LINE__ << " "
This assumes that the ErrorLog available is named errlog; a second macro is
ERRLOGTO ( logname, sev, id )
equivalent to
logname ( sev, id ) << __FILE__ <<":" << __LINE__ << " "
How a physicist can issue a log message
in multiple statements
errlog (ELerror, " "Too much energy") << "E = " << totalEnergy;
if ( condition ) {
errlog << "more stuff";
}
errlog << "yet more stuff" << endmsg;
g h
How the physicist can indicate what is being done
The physicist may OPTIONALLY declare the name of the subroutine
currently executing. When an error is logged, this name will go
into the message, and also into the overall statistics. The user
will generally only declare fairly large steps, to avoid some overhead.
errlog.setSubroutine( "myName" );
An alternative is available: If after the ID string, the next item
is a string of the form "@SUB=myname", then
myname is treated as the
subroutine name, regardless of what setSubroutine has set up.
errlog ( ELsevere "Bank Confusion" ) << "@SUB=prepare_IO" << endmsg;
std::string modname = errlog.moduleName();
std::string subname = errlog.subroutineName();
Of course, the user need not use these explicit queries to include
the module and subroutine in an error message (the message formatting does
this automaticaaly), but there may be cases where this information is useful for the program logic.
for the program logic.
These methods are in no way magic: They only return the same information that some other portion of the program has supplied via setModule() or setSubroutine().
Severity object Symbol Full name Intention --------------- ------ --------- --------- ELzeroSeverity -- -- ELincidental .. .. flash this on a screen ELsuccess -! SUCCESS report reaching a milestone ELinfo -i INFO information ELwarning -w WARNING warning ELwarning2 -W WARNING! more serious warning ELerror -e ERROR error detected ELerror2 -E ERROR! more serious error ELnextEvent -n NEXT advise to skip to next event ELunspecified ?? ?? severity was not specified ELsevere -s SEVERE future results are suspect ELsevere2 -S SEVERE! more severe ELabort -A ABORT! suggest aborting ELfatal -F FATAL! strongly suggest aborting! ELhighestSeverity !! !!The frameworker can control whether declaring severe, abort, or fatal errors actually will abort the job. The intentions listed for all the error types are only advisory; it is up to the framework to do what the experiment intends. If no abort threshold is set, then even ELfatal errors will not automatically abort the job.
ELzeroSeverity and ELhighestSeverity are not supposed to be used in forming error messages but are available to the frameworker when setting up various thresholds.
An ELseverityLevel may be constructed from a string (or char*). This
allows a user or framework to accept run-time input specifying what
severity to assign to a given possible error.
ELstring input; cin >> input;
ELseverityLevel mysev (input);
// ...
errlog (mysev, "this error");
The options accepted for a given level are its symbol, its full name,
the name of its severity object -- these are as listed in the above table --
and all-caps names:
"ZERO" "INCIDENTAL" "SUCCESS" "INFO"
"WARNING" "WARNING2" "ERROR" "ERROR2"
"NEXT" "UNSPECIFIED" "SEVERE" "SEVERE2"
"ABORT" "FATAL" "HIGHEST"
The translation used is case-sensitive. If no match is found, then
ELunspecified will be used.
<<
operator.
So if the experiment framework wishes to use the ZOOM exceptions mechanism,
the user can ZMthrow an exception yet still have the output go to the
logging destinations and the statistics be kept.
#include "Exceptions/ZMxel.h"
ErrorObj myMsg ( ELwarning, "Suspicious Pt" );
ZMthrow ( myMsg );
The physicist (or the frameworker) works with an ErrorObj directly when the ZMxel mechanism is used to ZMthrow an exeption but put its information into the error log.
Less commonly, one might wish to one can form an ErrorObj just in case it later needs to be logged. This might be done, for example, if you want to build up some history of what was done, but only log it if some ghastly condition later occurs.
The semantics of constructing and adding to an ErrorObj are similar to those for ErrorLog:
ErrorObj myMsg ( ELwarning, "Suspicious Pt" );
j k l
ZMthrow (myMsg);
m
myMsg = ErrorObj ( ELsevere, "Out of space" );
myMsg << "was doing step" << 20 << "@SUB=tracker" ;
n p q
errlog (myMsg);
r
try loop, and in case the exception is
not handled at the ZOOM exceptions level, can have a catch.
Although each possible destination may do different things with an
error message, the ErrorLogger package supplies a standard ELoutput
destination which will output (to a stream or file) as follows:
%ERLOG-w Too much energy: E = 834.750032 d0L2proc5 CTCDRVmodule
CTCTRKsubr 10-Jul-1999 14:49:03 CST run=234 event=543
This is the default formatting; if some portion of the message would overrun
the end of an 80-column line, it will instead be started on the next line,
indenting to align with the first character of the id.
A space is inserted to separate each item (each object put to the log via the << operator) from the next. The user can force line breaks by putting a \n as the first or last character in an item. (If \n appears in the middle of an item, indentation will not be done and the column formatter may introduce an unneeded new line when it thinks 80 columns would be exceeded.)
The frameworker can control some aspects of the format produced by ELoutput. A custom ELdestination can make more complex format changes.
A second part supplies up to 3 example contexts for each message type: The first two occurences, and the last one.
In a third part there will be information about total counts at each severity level. Counts are given since the last clear, and also a total for the whole job.
The responsibility of triggering the output of summary information belongs to the frameworker rather than the individual physicists. An illustration of the format of the summary information is given in the section on Obtaining error statistics summaries.