Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
434 views
in Technique[技术] by (71.8m points)

java - Using Instrumentation to record unhandled exception

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

  1. Visit all try/catch blocks (see visitTryCatchBlock) and save all handler labels
  2. Visit instructions until one of the handler labels met.
  3. 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...