0 and 1’s

Analysing application flow using Throwable object

Posted in Java by Rama Krishna on May 5, 2008

Often it will be required to find out how a particular method is invoked in order to investigate a bug or to understand the application flow. This can be done easily in small application using debugging tool or reading through the code. Even though, it is possible to debug large applications to find out the flow, it will obviously difficult to try the wide variety of usage scenarios. In case of large web applications, the developer may not even know every usage scenarios. Even missing a single usage scenario, also misses  method usage scenario.

This blog is about how to track various usage scenario in Java from code perspective.

The stack trace provides an excellent way to track the code flow. You would have seen in stack trace logs when exceptions are thrown, the stack trace has detail information on the classes, methods and the line numbers. We will use the same approach to trace the code flow without waiting for exceptions to happen.

In this scenario, we create a Throwable object, which the parent class of Exception. The Throwable object contains the entire stackTrace at the point where the object is created. We can use the getStackTrace() method on the Throwable object to obtain the stackTrace. The method returns an array of StackTraceElement. Each StackTraceElement represent a single stack frame and has information regarding the method which was invoked in the execution sequence. Also, the java class file name, complete java class name and the line number of invocation is also present.

Consider the following simple code scenario.


public String getName() {
          return "SOL_APP_MANG";
}

Inorder to trace, how the method getName is used in a application, the method is modified as follows.


public String getName() {
          Throwable throwable = new Throwable();
          StackTraceElement[] stElements = throwable.getStackTrace();
          for (StackTraceElement ste: stElement)
                   system.out.println("File Name:" + ste.getFileName());
                   system.out.println("Class Name:" + ste.getClassName());
                   system.out.println("Method Name:" + ste.getMethodName());
                   system.out.println("Line number:" + ste.getLineNumber());
          return "SOL_APP_MANG";
}

The code is very straightforword and simple.

I have implemented a small library for analyzing the stackTrace of the Throwable object. The library is a very small jar file with size of just 6.5 kb. The UML diagram is shown below.

Class diagram of ast.jar

It consists of 2 classes and a interface. The interface IDisplayableStackTrace has the method


public String getDisplayedStackTrace(StackTraceElement st)

Every implementation of the IDisplayableStackTrace should implement the method and implement the functionality of how a StackTraceElement should be represented as a String.

This allows any implmentation to be plugged based on requirement.

The following SimpleDisplayableStackTrace is an implementation.


package com.ast.sampleExample;

import com.ast.analyse.IDisplayableStackTrace;

public class SimpleDisplayableStackTrace implements IDisplayableStackTrace {

    @Override
    public String getDisplayedStackTrace(StackTraceElement st) {
        StringBuilder sb = new StringBuilder();
        sb.append(":$FILE$:").append(st.getFileName())
          .append(":$CLASS$:").append(st.getClassName())
          .append(":$METHOD$:").append(st.getMethodName())
          .append(":$LINE$:").append(st.getLineNumber());
        return sb.toString();
    }
}

You can write your own implementation of IDisplayableStackTrace depending on requirement.

The AnalyseThrowable class is the single most important class of the library. The AnalyseThrowable class has a static method.


public static void dumpStackTrace(IDisplayableStackTrace dst, PrintStream pw, Throwable throwable)
            throws AnalyseThrowableException

This method has the following arguments.

  • IDisplayableStackTrace dst – An implementation of the class IDisplayableStackTrace
  • PrintStream pw – A PrintStream object to where the customized stack trace needs to be written
  • Throwable throwable – A Throwable whose stack trace needs to be analysed

Also, the class provides the method


public void dumpStackTrace(Throwable throwable) throws AnalyseThrowableException

which can be invoked using an instanceof AnalyseThrowable. The AnalyseThrowable has a parameterized constructor which accepts an implementation of IDisplayableStackTrace and PrintStream.

One of the variations of the dumpStackTrace method can be used depending on the scenario.

The class AnalyseThrowableException extends Exception class and some of the methods of class
AnalyseThrowable throws the AnalyseThrowableException exception object which needs to be
handled by the client using the library.

A typical usage scenario of the library is given below.


public String getName() {
          try {
                AnalyseThrowable.dumpStackTrace(new SimpleDisplayableStackTrace(), System.out, new Throwable());
          }
          catch(AnalyseThrowableException ex) {
                ex.printStackTrace(System.out);
          }
          return "SOL_APP_MANG";
}

An sample stack trace, when executed through a junit test case is shown below.

:$FILE$:AnalyseThrowableTest.java:$CLASS$:com.ast.analyse.AnalyseThrowableTest:$METHOD$:testDumpStackTraceIDisplayableStackTracePrintStreamThrowable:$LINE$:13
:$FILE$:NativeMethodAccessorImpl.java:$CLASS$:sun.reflect.NativeMethodAccessorImpl:$METHOD$:invoke0:$LINE$:-2
:$FILE$:NativeMethodAccessorImpl.java:$CLASS$:sun.reflect.NativeMethodAccessorImpl:$METHOD$:invoke:$LINE$:39
:$FILE$:DelegatingMethodAccessorImpl.java:$CLASS$:sun.reflect.DelegatingMethodAccessorImpl:$METHOD$:invoke:$LINE$:25
:$FILE$:Method.java:$CLASS$:java.lang.reflect.Method:$METHOD$:invoke:$LINE$:597
:$FILE$:TestMethodRunner.java:$CLASS$:org.junit.internal.runners.TestMethodRunner:$METHOD$:executeMethodBody:$LINE$:99
:$FILE$:TestMethodRunner.java:$CLASS$:org.junit.internal.runners.TestMethodRunner:$METHOD$:runUnprotected:$LINE$:81
:$FILE$:BeforeAndAfterRunner.java:$CLASS$:org.junit.internal.runners.BeforeAndAfterRunner:$METHOD$:runProtected:$LINE$:34
:$FILE$:TestMethodRunner.java:$CLASS$:org.junit.internal.runners.TestMethodRunner:$METHOD$:runMethod:$LINE$:75
:$FILE$:TestMethodRunner.java:$CLASS$:org.junit.internal.runners.TestMethodRunner:$METHOD$:run:$LINE$:45
:$FILE$:TestClassMethodsRunner.java:$CLASS$:org.junit.internal.runners.TestClassMethodsRunner:$METHOD$:invokeTestMethod:$LINE$:66
:$FILE$:TestClassMethodsRunner.java:$CLASS$:org.junit.internal.runners.TestClassMethodsRunner:$METHOD$:run:$LINE$:35
:$FILE$:TestClassRunner.java:$CLASS$:org.junit.internal.runners.TestClassRunner$1:$METHOD$:runUnprotected:$LINE$:42
:$FILE$:BeforeAndAfterRunner.java:$CLASS$:org.junit.internal.runners.BeforeAndAfterRunner:$METHOD$:runProtected:$LINE$:34
:$FILE$:TestClassRunner.java:$CLASS$:org.junit.internal.runners.TestClassRunner:$METHOD$:run:$LINE$:52
:$FILE$:JUnit4TestReference.java:$CLASS$:org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference:$METHOD$:run:$LINE$:38
:$FILE$:TestExecution.java:$CLASS$:org.eclipse.jdt.internal.junit.runner.TestExecution:$METHOD$:run:$LINE$:38
:$FILE$:RemoteTestRunner.java:$CLASS$:org.eclipse.jdt.internal.junit.runner.RemoteTestRunner:$METHOD$:runTests:$LINE$:460
:$FILE$:RemoteTestRunner.java:$CLASS$:org.eclipse.jdt.internal.junit.runner.RemoteTestRunner:$METHOD$:runTests:$LINE$:673
:$FILE$:RemoteTestRunner.java:$CLASS$:org.eclipse.jdt.internal.junit.runner.RemoteTestRunner:$METHOD$:run:$LINE$:386
:$FILE$:RemoteTestRunner.java:$CLASS$:org.eclipse.jdt.internal.junit.runner.RemoteTestRunner:$METHOD$:main:$LINE$:196

Download jar file

OR

Download jar file

Tagged with: , ,