Jboss CommunityのBytemanを利用してみる
昨年末に「BytemanによるJava黒魔術」という記事をみて、どうやって実現しているのだろうかと興味津々でした。
「BytemanによるJava黒魔術」では、Jboss Communityの「Byteman」というツールを紹介しています。
WindowsのEclipseで試したことと、さくらVPSで動かしているCassandraで実行した内容を書いていきたいと
思います。
Bytemanをインストールする
bytemanのDownloadsページからbyteman-1.5.1.zip(byteman binary + docs)をダウンロードします。
まずは、ローカルのWindows環境にダウンロードしたbyteman-1.5.1.zipを任意のパスに解凍しました。
drive:\usr\local\byteman_1_5_1
docs\ProgrammersGuide.pdfにガイドがあったので、流し読みでながめてみました。
EclipseでBytemanを試してみる
試しにBytemanで利用してみるクラスは、下記の通りです。
BytemanSample.java
public class BytemanSample { /** * @param args */ public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ CoordinatorEngine ce = new CoordinatorEngine(); ce.commit(); String value = ce.commit("ce"); ParticipantEngine pe = new ParticipantEngine(); String value2 = pe.commit("pe"); } }
Engine.java
public interface Engine { public void commit(); }
CoordinatorEngine.java
public class CoordinatorEngine implements Engine { @Override public void commit() { System.out.println("CoordinatorEngine#commit() do "); } public String commit(String value) { System.out.println("CoordinatorEngine#<String>commit(String) do "); return new String("bk ce"); } }
ParticipantEngine.java
public class ParticipantEngine implements Engine { @Override public void commit() { System.out.println("ParticipantEngine#commit() do "); } public String commit(String value) { System.out.println("ParticipantEngine#<String>commit(String) do "); return new String("bk pe"); } }
BytemanSampleクラスのmainメソッドを実行する時にVM引数として以下を付与します。
-javaagent:drive:\usr\local\byteman_1_5_1\lib\byteman.jar=listener:true,script:drive:\usr\local\byteman_1_5_1\rule\rule.txt,boot:drive:\usr\local\byteman_1_5_1\lib\byteman.jar -Dorg.jboss.byteman.transform.all -Dorg.jboss.byteman.debug
rule.txtでは、Bytemanで挿入したい処理(ルール)を記述します。
RULE BytemanSample debug CLASS jp.co.sample.common.sandbox.byteman.CoordinatorEngine METHOD commit AT EXIT IF TRUE DO traceln("bytemanDebug()"), traceStack() ENDRULE
実行すると下記の様なログを出力します。
CoordinatorEngine#commit() do Default helper activated Installed rule using default helper : BytemanSample debug bytemanDebug() Stack trace for thread main jp.co.sample.common.sandbox.byteman.CoordinatorEngine.commit(CoordinatorEngine.java:8) jp.co.sample.common.sandbox.byteman.BytemanSample.main(BytemanSample.java:11) CoordinatorEngine#<String>commit(String) do Installed rule using default helper : BytemanSample debug bytemanDebug() Stack trace for thread main jp.co.sample.common.sandbox.byteman.CoordinatorEngine.commit(CoordinatorEngine.java:12) jp.co.sample.common.sandbox.byteman.BytemanSample.main(BytemanSample.java:12) ParticipantEngine#<String>commit(String) do
Bytemanでは、下記の様なルールを設定することができます。(# rule skeleton)
No | ルール | 概要 | |
---|---|---|---|
1 | RULE | ||
2 | CLASS | ||
3 | METHOD | ||
4 | BIND | ||
5 | IF | ||
6 | DO |
rule2.txtでは、INTERFACEに対して処理を追加します。
RULE BytemanSample debug INTERFACE jp.co.sample.common.sandbox.byteman.Engine METHOD commit AT EXIT IF TRUE DO traceln("bytemanDebug()"), traceStack() ENDRULE
Bytemanの詳しいルールに関しては、まだためし中で良くわかりません。
(いろいろできるみたいですが、読みきれて、試しきれていません)
さくらVPSで動かしているCassandraにbytemanを試してみる
wgetでbyteman-1.5.1.zipを取得します。
wget http://downloads.jboss.org/byteman/1.5.1/byteman-1.5.1.zip
任意のパスに展開し、Cassandraのenvスクリプトに追加します。
byteman-1.5.1.zipを展開する
unzip byteman-1.5.1.zip /usr/local/byteman/
Cassandraのenvスクリプト(cassandra-env.sh)に追加する
JVM_OPTS="$JVM_OPTS -javaagent:/usr/local/byteman/lib/byteman.jar=listener:true,script:/usr/local/byteman/rule/rule.txt,boot:/usr/local/byteman/lib/byteman.jar -Dorg.jboss.byteman.transform.all -Dorg.jboss.byteman.debug"
rule.txt
RULE cassandraDebug CLASS org.apache.cassandra.thrift.CassandraDaemon METHOD setup() AT EXIT IF TRUE DO traceln("bytemanDebug()"), traceStack() ENDRULE
起動ログ
INFO 16:02:26,053 Using TFramedTransport with a max frame size of 15728640 bytes. Default helper activated Installed rule using default helper : cassandraDebug bytemanDebug() Stack trace for thread main org.apache.cassandra.thrift.CassandraDaemon.setup(CassandraDaemon.java:114) org.apache.cassandra.service.AbstractCassandraDaemon.activate(AbstractCassandraDaemon.java:217) org.apache.cassandra.thrift.CassandraDaemon.main(CassandraDaemon.java:134)
上記の例では、「org.apache.cassandra.thrift.CassandraDaemon#setup()」メソッド実行時にbytemanに
処理をトレースさせています。
Bytemanの仕組み
Bytemanは、JDK(5以降)の-javaagentというJVMオプションを利用して、処理を実施しているようです。
Instrumentationという処理を利用して実施しているようです。
JavaDocにそれらしい説明がないか探してみましたがみつけられませんでした。
かわりに、「java.lang.instrument」というインターフェイスがあることをみつけました。
IBMのdeveloperworksに「エージェントを作成する」という部分で使い方を説明しているようです。
機会をみていろいろ引き続きいろいろ試してみたいと思います。