This is the Requirements and Design document for language independent Exception Definition, Handling, and Logging. It is a corba-based system for use by C++ and Java programs. It is not part of AIDA, but AIDA will be the first to make use of it.
There is a companion document called ESD Software Exceptions: Programmer's Guide. If your objective is to write programs that make use of the ESD Software Exception handling and logging system, then the Programmer's guide is the place to look. The Programmer's Guide contains important guidelines for programming exceptions and example code.
Meeting minutes from the Sept 12, 2002 design review are here.
Project Components
Requirements - High level
Requirements - Assumptions
Requirements - Restrictions
Requirements
- Detailed and High level design
Phase I - Remaining Issues.
File Names and Locations.
Make and run
Phase II and beyond
Definitions / Glossary
References and Pointers
Connections of the exception handling classes to Message Logger.
Click here to see the Classes and Data Flow (you may need to maximize
your browser to view the image correctly):
DATA FLOW
This project will be implemented in Phases. The reader can assume
that any given requirement or design item is to be implemented in Phase
I unless explicitly stated otherwise.
#include "Err.h" // Err logging class is defined here. #include "except.h" // IDL Exceptions are here.Then, the programs will simply instantiate the Err object and then log exceptions like this (for example in C++):
Err err('Magnet Server'); try { ... } catch (CORBA::Exception ex) { err.log(e,"for QUAD:LI01 while moving magnet"); }Even though programs making use of ESD Exception Handling will not need to know anything about CORBA , some of them will be either CORBA servers or clients. So, there is much discussion related to CORBA in this document to support those servers and clients.
Looking ahead from requirements to design, you can see that we're going to be using a class called Err to log messages.
User Exceptions will be defined in IDL. There will be a central repository (a single IDL file) which contains all user exceptions. Having exceptions defined in IDL will mean that we have to live with the restrictions of IDL exceptions including:
The user exceptions will be throwable from server, client, and also across the CORBA boundary (i.e. thrown back from the server to the client).
A common set of user exceptions will be available for use by the server and the client (there will not be one set for clients and one set for servers).
By definition, every CORBA invocation can raise a system exception even if it does not have an IDL "raises" clause. There will be a way for CORBA user AND system exceptions to be logged. This logging may occur on either the server or client. For phase I of the project, it will be necessary for the catcher to invoke the Err object's log method to cause the logging to occur (this is like the SLC system and epics where an explicit call is made to cause a message to be logged).
Exceptions must be time stamped as close as possible to the source (where the exception is created). Because of the limitations of IDL exceptions, time-stamping will occur when the exception is logged (i.e. in the Err class when the user calls err.log(e);). The IDL limitation here is that one isn't allowed to add code to the IDL exceptions. If it were possible, code would be added to the constructors to cause them to be time-stamped when they are instantiated. So, exceptions will be timestamped when they are logged instead
There is no requirement for severity code in the initial release.
There is no requirement for metering(throttling) in the initial release.
If the event service is down and then is brought back up, then, the Err.log() method shall automatically reconnect to the event service without loosing any messages.
If the event service is down, the consumer process shall reconnect automatically when the event service is brought back up.
When the message destinations (e.g. CMLOG) is down, the consumer process shall reconnect automatically when the message destination is brought back up.
The Err class will not throw any exceptions itself. It will try the best it can to send the exception to the event service for logging as explained above.
The Event Service, and errClient process shall be restarted automatically if they fail. Accomplishing this restart is beyond the scope of this document. Standard AIDA-like methods will be used. cmlogServer shall be run without a watchdog as it is now in the PEPII and Babar production environments.
There is no requirement for the Err classes to support fail over (i.e.
If the event service, message forwarder, or cmlogServer dies, there is
no requirement for the Err class to fail over to another service).
But, if failure is to be added in a future release, it will be encapsulated
inside the Err class and it's addition will be transparent to the programs
logging messages.
Here are the findings:
Test 1)
A 'flood' test was run to verify what happens if too many messages
are sent to the Event Service for it to handle. What happens is (as
defined by the Event Service), that events are dropped when the event service
becomes overloaded. The test that was run involved six clients logging
messages through the Err class. The test ran in a loop where there
was no task delay (sleep). The wonderful thing is, that the logging
clients were not slowed down by the fact that the event service gets overloaded.
Test 2)
9600 messages were sent from one test program process on flora in 30
seconds. Results were similar to the Test 1) 'flood' test above. Event
service drops messages as it should as it gets behind. But, nothing
crashes and test application spins in it's loop sending messages without
getting delayed significantly.
It is assumed that all target C++ compilers will support Exception
Handling (some older compilers don't). Therefore the CORBA alternate
mapping for exception handling (which is used for compilers that don't
support exceptions) will not be supported. [Advanced CORBA Programming
P322].
No special considerations will be made for throwing exceptions in multithreaded programs. It is assumed that the programmer throwing the exception knows what they are doing in the language/platform on which they are working.
The exceptions will be defined in an IDL file and the IDL compiler
will be used.
OMG IDL does not support exception Nesting [Advanced CORBA Programming
P88].
This means that we can't hold one exception inside another which would
be the normal way we'd try to do exception chaining.
OMG IDL does not support exception Inheritance [Advanced CORBA ProgrammingP88]
This means that we can't implement our own exception base class which
would provide methods of it's own to log the exception and/or chain. Here's
a little bit of code offered as proof that it's not supported.
In the IDL file we have this example code:
module chads { exception chadsException {}; };In the IDL generated .java file: chadsException is final.
final public class chadsException extends org.omg.CORBA.UserExceptionAlso, Marc Laukien (of IONA) says this on the Orbacus news group:
OMG IDL does not support passing exceptions as arguments to methods.
This means that the exception logger (Err) can not be an IDL Interface,
even if we wanted it to be. Remember, for performance reasons
we don't
want to make it an IDL interface anyway.
So, to accomplish writing a method that works like this: err.log(ex);,
we have
to write the Err class in Java and C++ (the two supported languages)
which
do support the passing exceptions as arguments.
Click here to see the Classes and Data Flow (you may need to maximize
your browser to view the image correctly):
DATA FLOW
Err.log() will receive an exception as an argument. It will create an
ExceptionTransporter object to hold information
about the exception. The ExceptionTransporter object will then
be passed through the Event Service an on to ErrClient and CmLogger.
CmLogger will then log the contents of the ExceptionTransporter to CMLOG.
Details of theExceptionTransporter are presented below.
The design will support the logging of arbitrary text (like err_text(); on VMS). This is accomplished by logging an TextOnlyException and providing the text.
It shall be possible to support DEV and PROD connections but exactly how this will be done is TBD. The DEV and PROD issues are:
The Err and ErrClient classes will not use AIDA util classes for
ORB creation etc. They will do it themselves.
AIDA Makefiles like MakefileAida and MakefileCommon will not be used. The ESD Exception logging system will be independent of AIDA.
See the section below "Catching Exceptions" for a detailed description
and example of how to catch all types of exceptions;
For example, when a java server indexes an array out of bounds, causing an ArrayIndexOutOfBoundsException, that (in this case) java exception gets translated to the CORBA "UNKNOWN" exception and thrown back to the client.
As a general guideline, Server and Client application code should be written to catch system exceptions (like UNKNOWN) in addition to User Exceptions.
See the section below "Catching Exceptions" for a detailed description and example of how to catch all types of exceptions;
Instead, exceptions will be defined in a single, centralized IDL file and they will be associated with error conditions. These exceptions can be used by any interface.
We would therefore expect there to be many of them (not just one per service (or interface).
This means that there will not be just one exception for all of AIDA (like "aidaException") and not one exception per service (like "magnetServiceException") where the member fields alone would indicate the error condition instead of the name indicating it.
The problem with that type of scheme (e.g. "magnetServiceException") is that it hides information that you're really supposed to expose. That is, IDL operations are supposed to tell the a programmer exactly what user exceptions can be raised by the operation. The operations are not supposed to hide the description of what can go wrong within a general purpose exception.
In Phase II of the project, it is expected that the database will contain a string like this corresponding to NoDataSourceException:
"Data source not found".Then, the program that instantiates the exception (in Java) will set the 'Reason' member to:
" for LB60:DCCT:SUNY".Then, the program that logs the exception (in Java) will set the 'Supplemental String' to
"when attempting to acquire the LER current".Then, the message will be displayed (by the browser as):
DBstring && Reason && Supplemental String.
Notice that imbedded parameters are not allowed (as they are on
VMS).
Detailed information on the creation, throwing, and catching of ESD exceptions is given in the Exceptions: Programmer's Guide. Detailed coding examples are also provided in C++ and Java. The following sections provide requirements and design information not contained in the Guide.
The identifier (i.e. name) of each ESD exception shall take a standard
form and shall, by it's name indicate the error condition that caused the
exception.
The form of the identifier shall be: [NAME][EXCEPTION].
For example, the IDL for the user exception "no such data source"
would look like this:
exception NoDataSourceException // <--identifier { };To maintain compatibility with Java, user exceptions should have the word "Exception" at the end.
See the File Names and Locations section below for the location of the ESD Software IDL file where exceptions will be defined.
new NoDataSourceException('for LB60:DCCT:SUNY');The "for LB60:DCCT:SUNY" is known as the 'reason' field or string.
Interestingly, if the user exception is thrown across the CORBA boundary
(back from a server to a client), then the "Reason" is lost. So,
it isn't logged if that exception is then logged on the client. This
is not really that bad a thing because it is expected that most servers
would catch and log their exceptions rather than throwing them back to
the client. That way, the "Reason" would get logged by the Err class.
This loosing of the "Reason" has been confirmed with 2 simple
test
programs (they are just the OB hello demo with an exception thrown).
Those programs are in ~ronm/dev/AIDA/except/reasonLost. To run them,
just source mySetenv and then run the server then the client.
Here's what Orbacus said about the "Reason" field of the exception:
Orbacus
Article.
The article says that, if you want to send a string message as part
of your exception across the CORBA boundary, you'll have to add a string
member to the IDL definition of your exception. But, we don't want
to have string members of the exceptions, so we'll just live without that
capability.
Phase II design note:
There is no way to const (preset) data members of IDL exceptions.
So, passing per-exception items like status, severity and error code in
the exception is impossible. So, to provide for those items, it is
expected, that the database will contain constants for status and severity
(and any other appropriate per-exception items). For destinations
like the current CMLOG browser implementation(where the browser can't do
lookup based on an string or code), the lookup will occur in the logger
program (CmLogger). For destinations where the browser can look up
things in the database, the XXLogger programs can simply forward the information
it receives. Then, that browser will look up the associated information
in the database as it displays the messages (like the VMS errdsp and errlog
programs do. That leaves us with error codes. Well, since there
is no way to const (preset) data members of IDL exceptions, there will
be no error codes used. Instead, the string representation of the
exception will be used as a (possibly hashed) key for database lookup.
More Detailed information on throwing, and catching of ESD Software exceptions is given in the Exceptions: Programmer's Guide.
try{ class.method(); // Invoke some method. } catch (ExcptnNoDataSource aends) { err.log(e); // Take corrective action and/or log the exception. } catch (Exception e) { err.log(e); // Take corrective action and/or log the exception. }The CORBA exception hierarchy allows you to also catch these classes of exceptions. They lie between Exception and the User Exceptions in the hierarchy. It is expected that users would seldom catch these classes.
catch (org.omg.CORBA.SystemException se) { // Handle system exception here } catch (org.omg.CORBA.UserException cue) { // Handle User Exception here (this would be an ESD Exception). }
Click here to see the Classes and Data Flow (you may need to maximize
your browser to view the image correctly):
DATA FLOW
Err.log() will receive an exception as an argument. It will create an
ExceptionTransporter object based to hold information
about the exception. The ExceptionTransporter object will then
be passed through the Event Service an on to ErrClient and CmLogger.
Here is the IDL definition of the ExceptionTransporter. It is contained in a file called errTrans.idl:
module err { struct ExceptionTransporter { string destination; // Which logger this msg is going to. string name; string suppl; long time; // IDL long is java int. string facility; string host; }; };
Err.log and ErrClient will be completely resilient in respect to
the Event Service. That is, it will be possible to invoke the Err
class and/or start the ErrClient standalone independently of the Event
service and when the event service becomes available, they will then connect
to it. In the mean time, with the Event Service down, Err.log() logs
to System.out of the process that invoked it.
Likewise, if the event service dies while Err.log and ErrClient are connected to it, they will keep trying to connect until the Event service becomes available again.
CmLogger.log() will be "mostly resilient" in respect to cmlogServer. If cmlogServer is not available when Cmlogger is started, then, CmLogger will keep trying to connect until it is available. Also, if cmlogServer is killed after CmLogger is connected to it, and then restarted, messages will resume flowing to it. The only thing that won't work (because the CMLOG java API doesn't support it) is that CmLogger won't realize that cmlogServer has gone away. It will just keep sending messages and they will go off into the bit bucket without giving an error indication. This is OK, since there's not much ErrClient could do about it except output an error message to a log file. Besides, our experience with cmlogServer in production is that it very rarely has any problems. If needed, we could write a watchdog to restart cmlogServer if it dies (but we have not found this necessary in production).
Question: Why not make Err an IDL interface?
Because you can't pass exceptions as parameters in IDL.
This code does not compile with jidl:
interface Err { void log (in exception ex); };Client or Server programs which use the Err class will not have to surround calls to Err.log() with try/catch statements. Err.log() will catch all exceptions internally that it can and not throw them to the caller.
In C++, Exceptions will be passed to Err.log(e) 'by-reference', and not 'by-value'. This will eliminate extra object constructions that would occur if they were passed 'by-value'. The 'Advanced CORBA/C++ programming' book talks about this concept on P 377,378.
In C++, the ostream operator will be overloaded. That means that, the exceptions can be easily output to stdout:: if the event service is not available. 'Advanced CORBA/C++ programming' book talks about this concept on p321, p331.
The Err class (in each supported language) will implement a form of
the 'singleton' design pattern so that users may instantiate more than
one Err object and not waste resources or cause problems with connections
to the Event Service. This will be accomplished by making the ORB,
and connection related variables static class variables. The constructor
will test if the variables have already been set up. If they
have, then the existing values will be used instead of creating a new ORB
and connection for each instance. In this case (the already constructed
case), no error condition will be returned and no exception will be thrown
because it is not considered a serious error condition.
The ErrClient class will be implemented in Java. It will be
a CORBA Event service Pull Client which receives messages from the event
service and forwards them to CMLOG. In a future releases, it will
send to other destinations too.
It will be based on the Orbacus event service demo PullClient.java
It will not be an IDL based interface.
It will be a standalone UNIX program that does it's own ORBInit and
connection to the event service.
The ErrClient class will receive a CORBA any from the event service.
The any will contain an IDL defined ExceptionTransporter.
It will extract the ExceptionTransporter from the any using the IDL
generated helper function ExceptionTransporterHelper.extract(any);
The ErrClient class will instantiate the CmLogger class in order to send messages to CMLOG. It will call CmLogger.log(ExceptionTransporter) in order to log the messages, passing the ExceptionTransporter object that it received from the event service.
In it's log method, it will receive an ExceptionTransporter it's only
argument. It will take the contents of the ExceptionTransporter and
put them into a CDEV data object. Then, it will post the data object
to cmlogServer using the cmlog API call client.postData (data);.
TBD:
See CVS
Repository Description for why. the following packages could
go under $CD_SOFT/ref/app instead of under package.
http://www.slac.stanford.edu/grp/cd/soft/slaconly/req/unix/cvsRep.txt
$CD_SOFT/ref/package/except/idl/except.idl ESD exceptions are defined in IDL here.
$CD_SOFT/ref/package/except/src/except*.cc (*)
IDL Generated C++ files.
except.h (*)
except.o (*)
Makefile.sun4
Low level makefile
$CD_SOFT/ref/package/except/inc/except.h (*) .h file from above copied here by make.
$CD_SOFT/ref/package/except/lib/libexcept.so created by makefile.
$CD_SOFT/ref/package/except/edu/slac/stanford/except/*Exception*.java
(*) JIDL Generated Java files.
*Exception*.class (*)
Makefile.sun4
Low level makefile.
$CD_SOFT/ref/package/err/idl/exTrans.idl IDL Definition of ExceptionTransporter structure.
$CD_SOFT/ref/package/err/src/exTrans*.cc (*)
IDL Generated C++ files.
exTrans*.h (*)
err.cc
C++ implementation of the Err exception logger
err.o
Compiled .o file created by make file.
Makefile.sun4
Low level makefile
$CD_SOFT/ref/package/err/inc/err.h
.h for Err class
exTrans.h (*)
.h file from above copied here by make.
$CD_SOFT/ref/package/err/lib/libErr.so object library created by makefile.
$CD_SOFT/ref/package/err/bin/ErrClient exectable created by makefile.
$CD_SOFT/ref/package/err/edu/slac/stanford/err/Err.java
Java implementation of the Err excepiton logger
Err.class
Created by the make file.
CmLogger.java
The CmLogger java class
CmLogger.class Created
by the make file.
ErrClient.java
The ErrClient java program
ErrClient.class
Created by the make file.
ExceptionTransporter*.java (*) IDL Generated Java files
ExceptionTransporter*.class (*)
Makefile.sun4
Low level makefile.
Note: 'dev' below may be any of new/prod/dev/test.
$CD_SOFT/dev/include/except.h
Include files used by multiple packages.
err.h
exTrans.h
$CD_SOFT/dev/@sys/bin/ErrClient Exacutable for this unix standalone
$CD_SOFT/dev/@sys/lib/libErr.so
Shared libraries for these classes.
libExcept.so
$CD_SOFT/dev/@sys/javalib/edu/slac/stanford/err/*.class
err classes coped from package location above
$CD_SOFT/dev/@sys/javalib/edu/slac/stanford/except/*.class
except classes copied from package location above
$CD_SOFT/dev/@sys/bin/StartErrEvent.sh
Startup script for Err's Corba Event Service
StartErrClient.sh
Startup script for ErrClient Standalone.
Startup files for ErrClient and the Event Service need to be ported from the alpha version in /afs/slac/package/aida.
The problem of DEV and PROD configurations will be addressed after the
ESD Software environment is developed more.
The Aida Servers System Management Guide indicates how the Event Service and Err Client processes were started for the ALPHA release.
In later phases of this project, the following requirements will
be considered for possible implementation:
EXCEPTION: - An object.Exceptions are objects that describe
an exceptional error condition.
When an error condition arises, an object representing that error is
created and thrown in the method that causes the error. The exception is
then caught and processed. Exceptions can be generated by the run-time
system or generated by the code.
ERROR: - A condition. The word "Error" is often used interchangeably with the word "Exception" in the literature. In this document, we will consider it to mean the condition that causes an Exception object to be generated in the program. Many kinds of errors can cause exceptions--problems ranging from serious hardware errors, such as a hard disk crash, to simple programming errors, such as trying to access an out-of-bounds array element.
USER EXCEPTIONS (CORBA user exceptions) They are indicated in the 'raises' clause for a method. User exceptions are defined by the application programmers by writing IDL definitions.
SYSTEM EXCEPTIONS (CORBA system exceptions) The ORB indicates
infrastructure related failures by raising system
exceptions. They are NOT listed in the 'raises' clause for a
method. OMG IDL defines 29 system exceptions, but new ones may be
added in the future as the CORBA specification evolves.
LANGUAGE-SPECIFIC-NON-CORBA EXCEPTIONS. These are local java
or C++ exceptions generated on either the client or server.