Phil Webb's Blog

Random thoughts from a software developer

Logging a full stacktrace in Spring Web Flow using a FlowExecutionListener

leave a comment »

One problem I sometimes encounter when using Spring Web Flow is that the root cause of exceptions get burred so deep that they are not always logged.

For example, say you have an end-state that calls a bean method, and that method throws an exception:

<end-state id="finish">
    <output name="result" value="someBean.processFinalResultAndSometimesThrow()">
</end-state>

You will probably end up with a log entry like this:

org.springframework.webflow.engine.FlowOutputMappingException: Errors occurred during output mapping in state 'finish' of flow 'exampleFlow'; errors = [[SourceAccessError@3f3a3f3a mapping = someBean.processFinalResultAndSometimesThrow(), code = 'evaluationException', error = true, errorCause = org.springframework.binding.expression.EvaluationException: An ELException occurred getting the value for expression 'someBean.processFinalResultAndSometimesThrow()' on context [class org.springframework.webflow.engine.impl.RequestControlContextImpl], originalValue = [null], mappedValue = [null]]]

We get information about the flow and the state where the error occurred, we even get the bean method that was called, but we don’t have a complete stack trace of the actual root cause. Luckily for us the root cause is available and to log it you need to do is write a FlowExecutionListener:

import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.binding.mapping.MappingResult;
import org.springframework.stereotype.Component;
import org.springframework.webflow.engine.FlowAttributeMappingException;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.RequestContext;

public class LoggingFlowExecutionListener extends FlowExecutionListenerAdapter {
    private final Log logger = LogFactory.getLog(getClass());

    @Override
    @SuppressWarnings("unchecked")
    public void exceptionThrown(RequestContext context, FlowExecutionException exception) {
        if (exception instanceof FlowAttributeMappingException) {
            List<MappingResult> errors = ((FlowAttributeMappingException)exception).getMappingResults().getErrorResults();
            for (MappingResult error : errors) {
                if (error.getErrorCause() != null) {
                    logger.warn("FlowAttributeMappingException thown containing error : " + error.getErrorCause(), error.getErrorCause());
                }
            }
        }
    }
}

Attach the listener in usual web flow way and all exceptions will be logged, complete with full stack trace.

Advertisements

Written by Phillip Webb

July 11, 2011 at 1:56 pm

Posted in Web Flow

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: