使用Instrumentation记录未处理的异常

Sat*_*eri 6 java instrumentation aspectj javaagents

我试图使用instrumentation调试java应用程序.当前系统的问题是

  • 几乎没有写任何日志声明
  • 恶劣的异常处理

这使得很难追溯功能损坏的根本原因.

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

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

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);
     }
Run Code Online (Sandbox Code Playgroud)

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

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

例如:

try {
            if(search.equals("Category")){
                //do operation
            }
        } catch (Exception e) {
        }
Run Code Online (Sandbox Code Playgroud)

这个代码NullPointerException在值为searchnull 时吃,我从来不知道这个异常和应用程序失败了.

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

  • 例外类型
  • Excpetion Stacktrace
  • 方法和类名

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

[更新1]

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

如何检测java系统类?

任何指导都会有很大帮助.

Ale*_*eev 5

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

  1. 访问所有 try/catch 块(请参阅访问TryCatchBlock)并保存所有handler标签
  2. 查看说明,直到符合其中一个handler标签。
  3. 标签后handler插入日志代码

    GETSTATIC java/lang/System out
    LDC "exception X occured"
    INVOKEVIRTUAL java/io/PrintStream println (java/lang/String)V
    
    Run Code Online (Sandbox Code Playgroud)

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


关于您当前的代码。这里

 if (className.startsWith("com/alu/")) {
      return insertLog(className, classBeingRedefined, classfileBuffer);
 }
Run Code Online (Sandbox Code Playgroud)

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

和这里

 if(className.endsWith("Exception")){
     System.out.println("============= exception occured "+className);
 }
Run Code Online (Sandbox Code Playgroud)

当类首次被 JVM 加载且其名称以"Exception". 发生异常时则不然。但转换异常本身是没有用的。所以我想你应该像这样继续:

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

所以你可以知道你的经纪人至少在工作。


你必须处理这样的代码

    try {
        if(search.equals("Category")){
            //do operation
        }
    } catch (Exception e) {
    }
Run Code Online (Sandbox Code Playgroud)

异常被吞噬的地方。您将方法转换为如下所示:

try {
    try {
        if(search.equals("Category")){
            //do operation
        }
    } catch (Exception e) {
    }
} catch (Exception e) {
    e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

当然,当异常被第一个吞噬时catch,第二个永远不会注意到它。相反,您应该catch自行转换现有块,以获得以下代码:

try {
    if(search.equals("Category")){
        //do operation
    }
} catch (Exception e) {
    e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

上面我向您展示了如何使用 ASM 来实现这一目标。