Using Instrumentation to record unhandled exception

aspectj, instrumentation, java, javaagents

Solution

I think you should use ASM to manipulate bytecode directly. Here is algoritms:

- Visit all try/catch blocks (see visitTryCatchBlock) and save all `handler` labels

- Visit instructions until one of the `handler` labels met.

After `handler` label insert logging code

GETSTATIC java/lang/System out
LDC "exception X occured"
INVOKEVIRTUAL java/io/PrintStream println (java/lang/String)V

And ensure that your javaagent works fine. Checkt that your MANIFEST.MF file contains proper `premain` declaration and enables class transformation.

About your current code. Here

 if (className.startsWith("com/alu/")) {
      return insertLog(className, classBeingRedefined, classfileBuffer);
 }

you transforming classes inside particular package. That classes contain code that, in particular, throw exceptions.

And here

 if(className.endsWith("Exception")){
     System.out.println("============= exception occured "+className);
 }

you log of class being retransfomed when it is first loaded by JVM, when its name ends with `"Exception"`. Not when exception occured. But transforming exception is useless itself. So I guess you should proceed like this:

if (className.startsWith("com/alu/")) {
    System.out.println("============= class transformed "+ className);
    return insertLog(className, classBeingRedefined, classfileBuffer);
} 

So you could know that your agent at least works.

You have to deal with code like this

    try {
        if(search.equals("Category")){
            //do operation
        }
    } catch (Exception e) {
    }

where exceptions are swallowed. You transform methods that they will be like this:

try {
    try {
        if(search.equals("Category")){
            //do operation
        }
    } catch (Exception e) {
    }
} catch (Exception e) {
    e.printStackTrace();
}

Of course, when exception was swallowed by the first `catch`, the second one never cathes it. Instead, you should transform existing `catch` blocks themself, to get the following code:

try {
    if(search.equals("Category")){
        //do operation
    }
} catch (Exception e) {
    e.printStackTrace();
}

Above I shown you how to achieve this with ASM.

Problem

I was trying to debug java application using instrumentation. The problem with current system are - Hardly written any log statements - Poor exception handling This made very difficult to trace root cause of broken functionality. To handle the situation I have developed tool,java agent using `Instrumentation` API , and I was able to inject log statements and half of the problem solved. But the next problem is to recording the Exception. I want to extend my tool record every exception thrown during the execution of the application. I tried injecting 'try-catch' block using `javaassist` API for methods (using `addCatch`, `insertBefore` and `insertAfter`), and it is effective certain extent. ``` public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (className.startsWith("com/alu/")) { return insertLog(className, classBeingRedefined, classfileBuffer); } if(className.endsWith("Exception")){ System.out.println("============= exception occured "+className); } ``` Here `inserLog(..)` method will inject necessary log statement and works fine,but when there is any Exception it doesn't come to transformer. But the problem is some of the method handles exception inside ( even with out log/sysout). eg: ``` try { if(search.equals("Category")){ //do operation } } catch (Exception e) { } ``` This code eats `NullPointerException` when value of `search` is null, I never know this exception and application fail for some thing else. Ultimately what I want is a mechanism to record any exception thrown by application. following details are to be captured - Exception Type - Excpetion Stacktrace - Method and class name I know there is API `Thread.setDefaultUncaughtExceptionHandler`, but not sure how it use with java instrumentation. I don't have any source access the application. [update 1] I found below link tells to use `retransformation` , I will give a try and update How to instrument java system classes? Any guidance would be greatly helpful.

Original source

Related problems