Exception sensor
The Exception sensor is used to gather information about exceptions in an application. The Exception Tracer is able to trace created, thrown, and handled exceptions within a target application. The Exception Tracer gathers information about methods and constructors that can cause an Exception. It must be specified which classes should be instrumented. There can be as many Exception Tracer configurations defined as you like.
Description
The lifecycle of an Exception consists of the following three events. These events are traversed by the JVM when an exception is created, thrown, and handled. To get the whole exception lifecycle, all events are needed.
- Object creation -> Exception ex = new Exception();
- Throwing of Exception -> throw ex;
- Exception Handling -> catch(Exception ex)
These three events are of interest for the Exception sensor. They show the easiest case of an Exception Lifecycle. To gather information about exceptions, these events are instrumented at different points in the target application. For the first event all constructors of a Throwable class are instrumented at load-time. For the second event, a method is instrumented using the Javassist method addCatch() (addCatch() makes it possible to handle exceptions internally -> better: to gather information when an exception is thrown by the Java API or by the developer). To gather information when an exception is handled, a handler is instrumented with an insertBefore().
To be able to instrument methods and constructors (which can cause an exception) with the Exception Tracer, these methods/constructors must first be instrumented f.e. with the timer sensor, otherwise you will get only information when an exception object is created, but there will be no information about the last two events.
Configuration
To enable the Exception Tracer, the name together with the fully-qualified-name of the class to instrument must be defined. As an optional parameter it is possible to enable superclass or interface matching support. The Exception sensor name must always be defined as exception-sensorin the configuration file, so there is no need to write down the fully-qualified name of this sensor type. There is no limit in how manyexception-sensor configurations can be defined. When defining multiple exception-sensor lines, there is always only one Exception Tracer created, which has one or more configurations.
exception-sensor [Exception Class] [options]
In contrast to method sensor types where the definition will provide the name of the class/method on which the sensor is to be applied, the exception sensor needs the name of the Exception class that should be traced.
The exception sensor is able to use Wildcards (see [ARCHIVE:Agent configuration]) for the definition of the class name. The options can be used to define that the provided exception class should be treated as interface or superclass (see the superclasses and interfaces chapter in [ARCHIVE:Agent configuration]).
Examples
The next table provides samples of how the exception tracer can be used. Bear in mind, that you can define multiple exception-sensors.
Configuration |
Description |
---|---|
exception-sensor java.lang.Throwable superclass=true |
Classes are instrumented that directly or indirectly extend java.lang.Throwable. The class java.lang.Throwable itself is not instrumented. |
exception-sensor my.package.exception.MyException |
Only the class my.package.exception.MyException is instrumented. |
exception-sensor my.package.ex*.*Exception |
All classes are instrumented that match the pattern (like my.package.exception.ParserException and my.package.extension.ExtensionException). |
exception-sensor my.package.exception.IException interface=true |
All classes are instrumented that are implementing the interface my.package.exception.IException. |
exception-sensor my.package.exception.My*Exception |
Classes like my.package.exception.MyException and my.package.exception.MyTestException are instrumented. |
exception-sensor * |
Every class of type Throwable is instrumented. |
exception-sensor my.pack*.ex*.* superclass=true |
Classes are instrumented which are extending the class that matches the pattern my.pack*.ex*.* |
Visualization
In the below picture you can see how the Exception Tracer is represented in the main menu of the User Interface. Currently there are two elements which can be selected. The element Exception Treeshows all Exceptions and allows a tree-like analysis of this Exception. It is also possible to get access to the stack trace of this specific Exception. In the Exception Overview you can see an overview over different Exception classes and f.e. how often a specific Exception class was handled.
The following means of visualization are provided by the exception sensor.
Visualization |
Screenshot (click to enlarge) |
Description |
---|---|---|
Exception overview |
Unable to render embedded object: File (Exception_Overview.png) not found. |
|
Exception tree |
Unable to render embedded object: File (ExceptionTreeDetails.png) not found. |
|
Exception stacktrace |
Unable to render embedded object: File (ExceptionTreeStackTrace.png) not found. |
|
When the JVM traverses the different points in the lifecycle of an exception, a data object is created at each event. Depending on the event this data object is marked with an event type. The below list gives an overview.
- CREATED: describes the creation of the exception object.
- PASSED: describes the implicit passing of the exception object by the JVM (the JVM passes the exception object when it searches for an appropriate handler). This event type also describes the first explicit throw of an exception.
- UNREGISTERED-PASSED: describes the passing of an exception object which was not registered before and has no parent.
- RETHROWN: describes an explicit rethrowing of an exception by reusing the object => f.e.: catch(Exception e) { throw e; }
- HANDLED: describes the handling of an exception object.
Dealing with not instrumented paths
Standard process
try { bar(); // method throws a MyException } catch(MyException e) { // do some stuff throw e; }
try { bar(); // method throws a MyException } catch(MyException e) { // do some stuff throw new MyException(); }
The below picture shows the simplest case in a lifecycle of an Exception. The exception is created and thrown in an instrumented method (method read()), and afterwards handled at another position in the call tree (method create()). After catching the exception object, this object is not needed anymore and made eligible for the GC. But an exception can also be handled rethrown by reusing the exception object. This case is shown in the code snippet below. The lifecycle of the object doesn't end after the object was handled. The object is rethrown and the lifecycle continues until the next handler is found. An exception object can also be handled and rethrown by creating a new exception object of the same type. This case is shown in the code snippet below. The lifecycle of the handled exception is finished and a new exception lifecycle is started (by creating a new exception object).
Unable to render embedded object: File (exception_flow.png) not found.
Not instrumented paths
On the above examples all methods within a target application where instrumented. But with inspectIT we only want to instrumented specific parts (f.e. only methods that are within a specified starting point). Due to this fact, it is possible that events of throwing/handling an exception cannot be gained. The event of an exception object creation is always obtained, because all constructors of a Throwable class are instrumented at load-time (the event is also obtained when the exception object is created on a not instrumented path). The below description shows some possibilities, where not all events of an exception can be obtained.
Unable to render embedded object: File (exception_flow_notInstrumented.png) not found.
In the below picture the methods read() and getInput() can throw an exception of the same type. In this example an exception is created/thrown in the method getInput(), which is not instrumented. The exception object is then passed along the call stack and the JVM searches for a suitable handler. We are getting events of the creation and the handling of the exception object, but not the throwing. This is because the throwing event is on a not instrumented path (the object creation is also on a not instrumented path, but this event is gained due to the fact that all Throwable constructors are instrumented at load-time).
Unable to render embedded object: File (exception_flow_handlerNotInstrumented.png) not found.
It is also possible that an exception is created, thrown, and handled on a path which is not instrumented. This example is shown in the below picture. Due to not instrumented paths, we are getting only the creation event, but not the throwing/handling event.
Unable to render embedded object: File (exception_flow_notInstrumentedPath.png) not found.