Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
{float:side=right}{panel:title=Contents|borderStyle=solid|borderColor=black}{toc:minLevel=1|maxLevel=3}{panel}{float}

h1. 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.

h2. 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.

h2. 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-sensor{*}in 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 many{_}exception-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.

{code}exception-sensor [Exception Class] [options]
{code}

{tip} 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. {tip}
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]).

h4. 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*.\* |

h2. Visualization

The following means of visualization are provided by the exception sensor.

|| Visualization\\ || Screenshot (click to enlarge)\\ || Description\\ ||
| *Exception overview*\\ | !Exception_Overview.png|thumbnail!\\ | * Provides an overview of all exceptions that were thrown by the system.
* Provides the count of all events of these exceptions |
| *Exception tree*\\ | !ExceptionTreeDetails.png|thumbnail!\\ | * Illustrates where exceptions are thrown, were they are catched and where they are handled
* This is very time-consuming as for each and every exception a trace is created |
| *Exception stacktrace*\\ | !ExceptionTreeStackTrace.png|thumbnail!\\ | * Provides the stacktrace of an exception |
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.

h2. Dealing with not instrumented paths

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).

{code:title=Rethrowing exceptions}try {
    bar();   // method throws a MyException
} catch(MyException e) {
    // do some stuff
    throw e;
}
{code}
{code:title=Throw a new exception}
try {
    bar();   // method throws a MyException
} catch(MyException e) {
    // do some stuff
    throw new MyException();
}
{code}