使用 Instrumentation 记录未处理的异常 [英] Using Instrumentation to record unhandled exception

查看:31
本文介绍了使用 Instrumentation 记录未处理的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用检测来调试 Java 应用程序.当前系统的问题是

  • 几乎没有写任何日志语句
  • 糟糕的异常处理

这使得追踪功能损坏的根本原因变得非常困难.

为了处理这种情况,我使用Instrumentation API 开发了工具,java 代理,并且我能够注入日志语句并解决了一半的问题.

但下一个问题是记录异常.我想扩展我的工具记录在应用程序执行期间抛出的每个异常.我尝试使用 javaassist API 为方法注入try-catch"块(使用 addCatchinsertBeforeinsertAfter),而且有一定的效果.

public byte[] transform(ClassLoader loader,字符串类名,类classBeingRedefined,保护域保护域,字节[] 类文件缓冲区)抛出 IllegalClassFormatException {如果(className.startsWith(com/alu/")){返回 insertLog(className, classBeingRedefined, classfileBuffer);}if(className.endsWith("异常")){System.out.println("==============发生异常"+className);}

这里 inserLog(..) 方法会注入必要的日志语句并且工作正常,但是当有任何异常时它不会出现在转换器中.

但问题是一些方法在内部处理异常(即使没有 log/sysout).

例如:

尝试{if(search.equals("类别")){//做操作}} 捕获(异常 e){}

search 的值为 null 时,这段代码会吃掉 NullPointerException,我从不知道这个异常和应用程序因其他原因而失败.

最终我想要的是一种记录应用程序抛出的任何异常的机制.以下细节将被捕获

  • 异常类型
  • 异常堆栈跟踪
  • 方法和类名

我知道有 API Thread.setDefaultUncaughtExceptionHandler,但不确定它如何与 java 检测一起使用.我没有任何来源访问该应用程序.

[更新 1]

我发现下面的链接告诉使用 retransformation ,我会尝试并更新

如何检测 java 系统类?>

任何指导都会非常有帮助.

解决方案

我认为你应该使用 ASM 直接操作字节码.这是算法:

  1. 访问所有 try/catch 块(参见 visitTryCatchBlock) 并保存所有handler标签
  2. 访问说明,直到遇到 handler 标签之一.
  3. handler标签后插入日志代码

    GETSTATIC java/lang/System out最不发达国家发生异常 X"INVOKEVIRTUAL java/io/PrintStream println (java/lang/String)V

并确保您的 javaagent 工作正常.检查您的 MANIFEST.MF 文件是否包含正确的 premain 声明并启用类转换.

<小时>

关于您当前的代码.这里

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

您在特定包内转换类.这些类包含的代码尤其会引发异常.

这里

 if(className.endsWith("Exception")){System.out.println("==============发生异常"+className);}

当它的名字以"Exception" 结尾时,当它第一次被JVM 加载时,你记录了类被重新转换的日志.不是发生异常时.但是转换异常本身是没有用的.所以我想你应该像这样继续:

if (className.startsWith("com/alu/")) {System.out.println("==============类转换"+ className);返回 insertLog(className, classBeingRedefined, classfileBuffer);}

所以你可以知道你的代理至少有效.

<小时>

你必须处理这样的代码

 试试 {if(search.equals("类别")){//做操作}} 捕获(异常 e){}

吞下异常的地方.你将方法转换成这样:

尝试{尝试 {if(search.equals("类别")){//做操作}} 捕获(异常 e){}} 捕获(异常 e){e.printStackTrace();}

当然,当异常被第一个 catch 吞下时,第二个从不捕获它.相反,您应该自己转换现有的 catch 块,以获得以下代码:

尝试{if(search.equals("类别")){//做操作}} 捕获(异常 e){e.printStackTrace();}

上面我向您展示了如何使用 ASM 实现这一点.

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.

解决方案

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.

这篇关于使用 Instrumentation 记录未处理的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆