6

インストルメンテーションを使用して Java アプリケーションをデバッグしようとしていました。現在のシステムの問題点は、

  • ログステートメントはほとんど書かれていません
  • 貧弱な例外処理

これにより、壊れた機能の根本原因を追跡することが非常に困難になりました。

この状況に対処するために、API を使用してツール、Java エージェントを開発しましInstrumentationた。ログ ステートメントを挿入することができ、問題の半分は解決されました。

しかし、次の問題は、例外を記録することです。アプリケーションの実行中に例外がスローされるたびに、ツール レコードを拡張したいと考えています。javaassistメソッドの API を使って ( addCatch、 、を使用しinsertBeforeて)、 try-catch ブロックを挿入してみましinsertAfterたが、ある程度効果があります。

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);
     }

ここで inserLog(..)、メソッドは必要なログ ステートメントを挿入し、正常に動作しますが、例外が発生するとトランスフォーマーに到達しません。

しかし、問題は、一部のメソッドが内部で例外を処理することです (log/sysout がなくても)。

例えば:

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

NullPointerExceptionこのコードは、の値がnullのときに食べsearchます。この例外とアプリケーションが何か他の理由で失敗することはわかりません。

最終的に私が欲しいのは、アプリケーションによってスローされた例外を記録するメカニズムです。以下の詳細を取得する必要があります

  • 例外の種類
  • 例外スタックトレース
  • メソッドとクラス名

API があることは知っていますThread.setDefaultUncaughtExceptionHandlerが、Java インストルメンテーションでどのように使用するかはわかりません。アプリケーションにアクセスするソースがありません。

【アップデート1】

以下のリンクを使用するようretransformationに指示されていることがわかりました。試して更新します

Javaシステムクラスを計測する方法は?

どんなガイダンスも非常に役に立ちます。

4

3 に答える 3

4

バイトコードを直接操作するには、ASM を使用する必要があると思います。アルゴリズムは次のとおりです。

  1. すべての try/catch ブロックにアクセスし ( visitTryCatchBlockhandlerを参照)、すべてのラベルを保存します
  2. handlerラベルの 1 つが満たされるまで、指示にアクセスしてください。
  3. ラベル挿入後handlerのロギング コード

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

そして、javaagent が正常に動作することを確認してください。MANIFEST.MF ファイルに適切なpremain宣言が含まれており、クラス変換が有効になっていることを確認してください。


現在のコードについて。ここ

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

特定のパッケージ内のクラスを変換します。そのクラスには、特に例外をスローするコードが含まれています。

そしてここ

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

名前が"Exception". 例外が発生したときではありません。しかし、例外を変換すること自体が役に立たない。したがって、次のように進める必要があると思います。

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

したがって、エージェントが少なくとも機能していることを知ることができます。


このようなコードを処理する必要があります

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

例外が飲み込まれる場所。メソッドを次のように変換します。

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

もちろん、例外が最初の によって飲み込まれたcatch場合、2 番目の はそれを決してキャッチしません。代わりに、既存のcatchブロック自体を変換して、次のコードを取得する必要があります。

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

上記で、ASM を使用してこれを実現する方法を示しました。

于 2013-11-29T11:05:59.803 に答える