2017年1月29日日曜日

Bytemanチュートリアル(日本語意訳)
実行中のプログラムにルールを動的適用する方法は?

Byteman (http://byteman.jboss.org/docs.html)のチュートリアルを日本語意訳したものです。

長時間動くプログラムの場合、プログラム実行後にルールをロードしたり、ルールの再ロードをしたいことがあります。これらは Byteman にエージェント・リスナーを起動されば可能になります。エージェント・リスナーはルールのロード状況の確認もできます。

AppMain3 を使って、リスナーの動作を確認しましょう。

    ----- AppMain3.java -----
    package org.my;
    import java.io.DataInputStream;
 
    class AppMain3  {
        public static void main(String[] args) {
            try {
                DataInputStream in = new DataInputStream(System.in);
                String next = in.readLine();
                while (next != null && next.length() > 0 && !next.contains("end")) {
                    final String arg = next;
                    Thread thread = new Thread(arg) {
                        public void run() {
                        System.out.println(arg);
                        }
                    };

                    thread.start();

                    try {
                        thread.join();
                    } catch (Exception e){ }

                    next = in.readLine();
                }
            } catch (Exception e) {}
        }
    }
    -----

AppMain3 は入力されたテキストをそのまま出力します。"end" 文字列、または EOF が入力されると止まります。Byteman エージェント・リスナーと一緒に AppMain3 を起動すると、AppMain3 の読み込み待機中にルールのロード/アンロードができます。またプログラムに解析され注入されたルールの型チェックや実行された状態チェックもできます。

エージェント・リスナーを有効にするには、エージェント・オプション「listener:true」を使います。

<Linux>
 -----
 $ java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3
-----

<Windows>
-----
> java -javaagent:%BYTEMAN_HOME%\lib\byteman.jar=listener:true,boot:%BYTEMAN_HOME%\lib\byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3
-----

エージェント・リスナーは通信口(サーバー・ソケット)を開いてコマンド入力を待ちます。エージェント・オプションにルールスクリプトが指定しなかったので、まずは入力内容が繰り返されるのみです(★)。

----- 実行例 ---
> java  -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3
    foo
    foo  --★
    bar
    bar  --★
-----

<Linux>
エージェント・リスナーに処理させる際は bmsubmit.sh を使います。bmsubmit.sh を引数なしで実行すると、インストールされているルールをすべて表示します。

-----
> bmsubmit.sh
 no rules installed  
>
(※現在、ルール未インストール)
-----

※ bmsubmit.sh は別シェルを立ち上げ実行してください。また、AppMain3 は先に起動すして、 bmsubmit.sh と Byteman エージェントがサーバーソケットを経由して対話できるようしておきます。

<Windows>
bmsubmit.bat を実行します。(Byteman リリース 2.0.1 以降)

-----
> bmsubmit
  no rules installed
>
(※現在、ルール未インストール)
-----

(2.0.1 以前のリリースは、リスナーにコマンドを送信するために Java コマンドで Submit クラスを呼び出す必要があります。)
-----
> java -classpath %BYTEMAN_HOME%\lib\byteman-submit.jar org.jboss.byteman.agent.submit.Submit
  no rules installed
>
-----

次に bmsubmit.sh を使って実行中のプログラムにルール・スクリプトをロードします。

<Linux>
-----
> bmsubmit.sh -l thread.btm
 install rule trace thread start
>
(※ルール・スクリプト trace がインストールされました。)
-----

<Windows>
bmsubmit.bat を使います。
 
(リリース 2.0.1 以前は、Submitクラスに -l 引数を付与して実行します。
-----
> java -classpath %BYTEMAN_HOME%\lib\byteman-submit.jar org.jboss.byteman.agent.submit.Submit -l thread.btm
  install rule trace thread start
>
(※ルール・スクリプト trace がインストールされました。)
-----

インストールされたルールのステータスを再確認すれば、ルールがロードされ解析されて Thread.start() メソッドに注入されていることが確認できます。もしルールの完全な解析に失敗した場合は、注入が阻止されたことと詳細を含む解析エラーが出力されます。
-----解析エラー-----
> bmsubmit.sh
  # File thread.btm line 4
  RULE trace thread start
  CLASS java.lang.Thread
  METHOD start()
  AT ENTRY
  IF true
  DO traceln("*** start for thread: "+ $0.getName())
  ENDRULE
  Transformed in:
  loader: sun.misc.Launcher$AppClassLoader@5acac268
  trigger method: java.lang.Thread.start() void
>
-----

実行中のAppMain3で入力を進めるとルールが実行されたことが確認できます。
    -----
    . . .
    bar
    bar
    baz
    *** start for thread: baz
    baz
    mumble
    *** start for thread: mumble
    mumble
    -----

0 件のコメント:

コメントを投稿