Javaアプリケーションがまったく待機していない場合のデバッグ-InTraceアプローチへようこそ

ロギングツールやその他のモニタリングメカニズムを装備する必要のないJavaコードの実行を段階的に学習したことがありますか?

調査中のコードを再コンパイルせず、実際に既存のプロセスを再起動しないという事実によりタスクを複雑にします(再起動時に理解できない動作が浮動する場合もあります)。 もちろん、Javaマシンは最も一般的なオプションで起動されます(デバッガーのアタッチメントやその他の機能のパラメーターはありません)。

そして、私は何が起こっているのかを理解したいと思います。



それが私たちのすることです。



説明のために、簡単なコード、古き良き有名なおとぎ話「カブ」の実装に似たものを取り上げましょう。 以下のコードのデモンストレーションの目的は、クラスやメソッドを整理することの美しさを示すことではなく、名前付け(ここではむしろ不名誉)は言うまでもなく、単に呼び出しの後に多数の呼び出しを行うことです。



1: package skazka; 2: 3: import java.io.BufferedReader; 4: import java.io.InputStreamReader; 5: 6: public class Repka { 7: public static void main(String[] args) throws Exception { 8: new BufferedReader(new InputStreamReader(System.in)).readLine(); 9: 10: try { 11: new Dedka().tyanem("", 200); 12: } catch (Exception ex) { 13: processError(ex); 14: } 15: 16: } 17: 18: public static boolean processError(Exception ex) { 19: // ... 20: return true; 21: } 22: } 23: 24: class Dedka { 25: void tyanem(String target, int weight) { 26: new Babka().tyanem(target, weight - 15); 27: } 28: } 29: 30: class Babka { 31: void tyanem(String target, int weight) { 32: new Vorona().tyanem(target, weight - 10); 33: } 34: } 35: 36: class Vorona { 37: void tyanem(String target, int weight) { 38: if (!target.equals("")) { 39: throw new RuntimeException("    "); 40: } 41: 42: // ... 43: } 44: }
      
      







コンパイルする



 javac skazka/Repka.java
      
      





そして走る



 java skazka.Repka
      
      







次に、すでに実行中のプロセスに何らかの方法で「くさび」をかけ、ニーズに合わせてコードを調整する必要があります。 InTrace mchr3k.github.io/org.intraceと呼ばれる、Martin Robertsonによって作成されたJavaエージェント(多くの、心からの感謝) はこれに完全に適しており、実行中のコードにその場で埋め込み、トレース要素を提供できます。



InTraceエージェントは、いくつかの簡単な方法(選択する方法)で、既に実行中のJavaプロセスに配置されます。

1)ソフトウェア方式

 public static void loadAgent(String pid, String agentFilePath) throws Exception { VirtualMachine vm = VirtualMachine.attach(pid); vm.loadAgent(agentFilePath, ""); vm.detach(); }
      
      







github.com/mchr3k/org.intrace/tree/master/binaries/jars/latest_developmentからJava Agent intrace-agent.jarプロセスをスライドさせる



2) VisualVMを取得し(ここからvisualvm.java.netがない場合はダウンロード)、それにパッチを適用します(ツール->プラグイン)から取得したorg-intrace-visualvm.nbmプラグインでInTrace

github.com/mchr3k/org.intrace/tree/master/binaries/jars/latest_development



問題は、org-intrace-visualvm.nbmが最新のファイルではないため、VisualVMがプラグインを保存する場所を見つけ、対応するdzharnikiをgithub.com/mchr3k/org.intrace/tree/master/binaries/jars/からより新しいものに変更することです。 latest_development

私の場合(Linux OS)、私は置き換えるべきだった

intrace-agent.jarのintrace-agent.jarおよびintrace-ui.jarのintrace-client-gui-linux.jar(下のスクリーンショットを参照してください。プラグインが指示します)



VisualVMを起動し、skazka.Repkaのコンテキストメニューを呼び出し、「InTrace Application ...」を選択します。その後、表示されます。





「Load InTrace Agent」ボタンをクリックすると、コンソールは次のようなテキストでInTraceの実装についてレポートします







実装段階が正常に完了しました。InTraceエージェントがJavaマシンに正常に収まり、バイトコードを変換してトレースコマンドを提供し、結果を報告する準備が整いました。



結果を監視する段階に進み、エージェントの管理と結果の分析(別のアプリケーション)を開始します。



繰り返しますが、2つの簡単なオプションがあります。

1)最初の「ソフトウェアの方法」でエージェントを実装し、実行します

 java -jar intrace-ui.jar
      
      





ここで撮影

github.com/mchr3k/org.intrace/tree/master/binaries/jars/latest_development

2) VisualVMを使用する場合は、「InTrace Clientの起動」ボタンをクリックします。原則として、最初の例とまったく同じファイルが起動されます(新しいintrace-ui.jarにパッチを適用したため)







アドレスを入力し、トレースのパラメーターを構成し(Entry / Exit + Branch + Argsをオンにします)、「Classes ...」ボタンを押してそこにskazkaを指定します(これにより、トレースがskazkaパッケージからクラスに追加されます)。

実行中の「ターニップ」を使用してコンソールで「Enter」を押します(これが彼女が続行するのを待っていることを忘れないでください)。最後に、出力の形式でクライアントのプログラム実行チェーンを取得します。



 [21:52:39.861]:[1]:skazka.Dedka:<init>: {:24 [21:52:39.862]:[1]:skazka.Dedka:<init>: }:24 [21:52:39.862]:[1]:skazka.Dedka:tyanem: {:26 [21:52:39.865]:[1]:skazka.Dedka:tyanem: Arg (target):  [21:52:39.866]:[1]:skazka.Dedka:tyanem: Arg (weight): 200 [21:52:39.868]:[1]:skazka.Babka:<init>: {:30 [21:52:39.869]:[1]:skazka.Babka:<init>: }:30 [21:52:39.871]:[1]:skazka.Babka:tyanem: {:32 [21:52:39.871]:[1]:skazka.Babka:tyanem: Arg (target):  [21:52:39.871]:[1]:skazka.Babka:tyanem: Arg (weight): 185 [21:52:39.878]:[1]:skazka.Vorona:<init>: {:36 [21:52:39.878]:[1]:skazka.Vorona:<init>: }:36 [21:52:39.878]:[1]:skazka.Vorona:tyanem: {:38 [21:52:39.879]:[1]:skazka.Vorona:tyanem: Arg (target):  [21:52:39.879]:[1]:skazka.Vorona:tyanem: Arg (weight): 175 [21:52:39.879]:[1]:skazka.Vorona:tyanem: /:39 [21:52:39.885]:[1]:skazka.Vorona:tyanem: Throw:39: java.lang.RuntimeException:      at skazka.Vorona.tyanem(Repka.java:39) at skazka.Babka.tyanem(Repka.java:32) at skazka.Dedka.tyanem(Repka.java:26) at skazka.Repka.main(Repka.java:11) [21:52:39.885]:[1]:skazka.Vorona:tyanem: }:39 [21:52:39.886]:[1]:skazka.Repka:main: /:13 [21:52:39.890]:[1]:skazka.Repka:processError: {:20 [21:52:39.890]:[1]:skazka.Repka:processError: Arg (ex): java.lang.RuntimeException:      [21:52:39.891]:[1]:skazka.Repka:processError: Return: 1 [21:52:39.891]:[1]:skazka.Repka:processError: }:20 [21:52:39.891]:[1]:skazka.Repka:main: }:16
      
      







各出力行は、次の形式で説明されています

 [ ]:[ ]::: 
      
      





ここで:

現在の時間-それ自体を語る

ストリーム識別子-ストリームの一意の識別子、異なるストリーム-異なる番号(1、2、3、4、...)

パッケージ-名前空間

method-実行が発生するメソッドの名前

追加情報-状況に応じて



サポートされるトレースタイプ:

-メソッド入力\出力

 [21:52:39.861]:[1]:skazka.Dedka:<init>: {:24 [21:52:39.862]:[1]:skazka.Dedka:<init>: }:24
      
      





または

 [21:52:39.890]:[1]:skazka.Repka:processError: {:20
      
      







-枝

 [21:52:39.879]:[1]:skazka.Vorona:tyanem: /:39
      
      





-引数(オブジェクトの表示はtoString()を通過します)

 [21:52:39.865]:[1]:skazka.Dedka:tyanem: Arg (target):  [21:52:39.866]:[1]:skazka.Dedka:tyanem: Arg (weight): 200
      
      





戻り値

 [21:38:31.444]:[1]:skazka.Repka:processError: Return: 1
      
      





-例外

 [21:52:39.885]:[1]:skazka.Vorona:tyanem: Throw:39: java.lang.RuntimeException:      at skazka.Vorona.tyanem(Repka.java:39) at skazka.Babka.tyanem(Repka.java:32) at skazka.Dedka.tyanem(Repka.java:26) at skazka.Repka.main(Repka.java:11)
      
      





一般に、プログラムの進捗を正常に理解するために必要なすべてのこと。



上記の例を使用して出力の分析を練習します(すぐに直観できるものは完全には明確ではありませんが、すぐに理解できれば慣れます)。



コードが何に変わるか(トレースの配置方法)の良い例は、著者のページmchr3k.github.io/org.intrace/howintraceworks.htmlにあります



また、不要なゴミを取り除くのに役立つ非常に便利な「フィルター...」ボタンにすぐに注意することをお勧めします



Eclipseとの既存の統合により、既に実装されたInTraceエージェントでJavaアプリケーションを実行し、トレースパラメーターを構成し、作業の結果を分析できます。 詳細については、 mchr3k.github.io / org.intrace / eclipse.htmlを参照てください



合計



利点:

1)プログラムの進行状況をその場で追跡する:

-メソッド呼び出し、渡された引数、ブランチ、生成された例外、...

-再コンパイルせず、実行中のプログラムを再起動することなく

2)利用可能なコード(OpenSource)

3)セットアップと使用が簡単

4)クロスプラットフォームソリューション(Windows、Linux)

5)一般的な開発ツールとの統合が可能です(Eclipse、VisualVM)



短所:

1)コードバイトをその場で変更します:

-実行速度が低下する(パフォーマンス)

-エージェントの導入により、既存のプロセスが「変化」し、以前のようにはなりません(同じ川に2回入ることはありません)

-コードバイトの変更は「現状のまま」で、当然「自分の責任とリスクで」

2)大規模なサポートはありません-開発者は1人だけですが、プロジェクトのサイズが小さいこととソースコードの可用性によって補われています。 リポジトリの最後の更新がこの投稿の公開から数週間前であったことを嬉しく思います。

3)製品はJava 1.6で十分にテストされていますが、Java 1.7ではテストされていません(それに問題があります。バグgithub.com/mchr3k/org.intrace/issues/28を参照してください)。 私の知る限り、作者は1.6だけを使用し、「自分のために」書いており、商業用にはまったく書いていないので、新しいものが必要な人は、怠けすぎて取り乱さないでください



結論として:InTraceは少なくとも知り合いに値するエージェントであり、おそらくあなたにとって不可欠なツールになり、異なる角度からJavaアプリケーションのデバッグを明らかにし、そしてもちろん、誰かが何度も助けてくれるでしょう。



コメントと追加を考慮に入れて、JavaハブでInTrace(および他の多くの興味深いエージェント)の力を解き放とうとします。私は非常に感謝します。



ご清聴ありがとうございました。興味のある方と共有してください!



All Articles