Exception Sensor

1. Overview

Currently the Exception Sensor is represented in two different views within the UI. The Exception Tree view shows all Exceptions in an ungrouped way over time and allows a tree-like analysis of each Exception. The Exception Tree view makes it also possible access the stack trace of a specific exception. In the Exception Overview you get an overview over different exceptions that are grouped together with the respective event types. No time information is  shown in this view.

2. Design Decisions regarding UI

2.1 Exception Tree

The Exception Tree view retrieves on every refresh all exception objects within the defined limit that have the CREATED event type. By double-clicking on a particular exception object a new request is done and the related objects are retrieved from the CMR. Using the related objects an Exception Tree is created where one can see which event type occured in which method. Currently the event type, Method/Constructor, the Cause, and the Error Message is shown in this detailed view. It is also possible to retrieve the stack trace of a particual exception object. This is done by changing from the Details tab to the Stack Trace tab in the lower left corner.

2.2 Exception Overview

Within the Exception Overview  all exceptions are grouped according to their type. For each exception type the number of occured events is shown. Therefore the user gets a feeling how stable his application is and which exceptions occur very often. All data shown in this view is retrieved by one single query, except the stack traces belonging to a particular error message. By double-clicking on an exception the data for the lower view (Error Message with Stack Trace) is retrieved from the cache and shown. The main idea within the lower view was to show all error messages belonging to a particular exception with the number of occured events. By selecting a specific error message all stack traces are then requested from the CMR having this error message. Of course, only distinct stack traces belonging to an error message are shown. The tree in this lower view will always have max. two levels of depth (error message and the stack traces belonging to this error message). By double-clicking on a particular stack trace, its details can be examined in a tooltip.

If an exception didn't specify an error message, a default message is shown saying "There was no error message provided". If this confuses the user and he thinks that this is a real message that was used in an exception, a better notification or a colored highlighting should be used.

Within the Exception Overview an extended version of the ExceptionSensorData object is used. This is because extended version introduces additional attributes (created, rethrown, handled) for the different event types. Basically ExceptionSensorData is extended and new attributes are added. It is very important to know that the equals() method of this extended object was modified in a way that it considers only some particular attributes when checking for equality. So for equality check only the error message, and the exception type is used.

3. Design Decisions regarding CMR

3.1 Queries

The queries to retrieve all data necessary within the UI were improved in a way that as much data as possible is gathered within a single query. This is especially the case when retrieving the data for the Exception Overview. The below code excerpt shows how this is done. The main thing here is, that all exception events are aggregated and saved. For this task the throwableIdentityHashCode is misused, as there was no other attribute that could be used for saving this value without introducing new attributes. This is an absolute exceptional case, as the identityHashCode is not used within the Exception Overview. This decision was discussed with PB.

public List<ExceptionSensorData> getExceptionOverview(ExceptionSensorData template) {
	DetachedCriteria criteria = DetachedCriteria.forClass(template.getClass());
	criteria.add(Restrictions.eq("this.platformIdent", template.getPlatformIdent()));
	ProjectionList projectionList = Projections.projectionList();
	projectionList.add(Projections.property("throwableType"), "throwableType");
	projectionList.add(Projections.property("exceptionEventString"), "exceptionEventString");
	projectionList.add(Projections.property("errorMessage"), "errorMessage");
	projectionList.add(Projections.property("stackTrace"), "stackTrace");
	projectionList.add(Projections.property("cause"), "cause");
        projectionList.add(Projections.count("exceptionEventString"), "throwableIdentityHashCode");
        projectionList.add(Projections.groupProperty("throwableType"));
	projectionList.add(Projections.groupProperty(...));
	criteria.setProjection(projectionList);
	criteria.addOrder(Order.asc("exceptionEventString"));
	criteria.setResultTransformer(Transformers.aliasToBean(ExceptionSensorData.class));
	return getHibernateTemplate().findByCriteria(criteria);
}

3.2 Steps before persisting ExceptionSensorData objects into the DB