åã ããæ°ã«ãªã£ãŠããã®ãšãå°ãåã«è³Œå ¥ãããã¡ãã®æ¬ã«ã玹ä»ãããŠããã®ã§ãJBoss Projectsã®Bytemanã詊ããŠã¿ãããšã«ããŸããã

JBoss Enterprise Application Platform6 æ§ç¯ã»éçšããŒãã§ã¯ãã¬ã€ã
- äœè : NTTãªãŒãã³ãœãŒã¹ãœãããŠã§ã¢ã»ã³ã¿,ã¬ãããããæ ªåŒäŒç€Ÿ
- åºç瀟/ã¡ãŒã«ãŒ: æè¡è©è«ç€Ÿ
- çºå£²æ¥: 2013/06/22
- ã¡ãã£ã¢: 倧忬
- ãã®ååãå«ãããã° (10ä»¶) ãèŠã
ããããBytemanã£ãŠãªãã§ããïŒã£ãŠãšããã§ãããjavaagentã䜿çšããŠãã€ãã³ãŒãã®å€æŽãè¡ãããŒã«ã§ãããããå©çšããŠãã¢ããªã±ãŒã·ã§ã³ã®åäœã倿Žãããã§ããŸãã
Byteman
https://www.jboss.org/byteman
äœ¿ãæ¹ãšããŠã¯ã
- 察象ã®Javaã¢ããªã±ãŒã·ã§ã³ã«Bytemançšã®èšå®ãä»èŸŒãã§èµ·åãã
- èµ·åæžã¿ã®Javaã¢ããªã±ãŒã·ã§ã³ã«ãBytemanãæäŸããã¹ã¯ãªããã䜿ã£ãŠã¢ã¿ãããã
ã®2ã€ããããã©ã®ãããªåŠçãå ¥ãããã¯ãBytemanãæäŸããã«ãŒã«ã«æ²¿ã£ãŠèšè¿°ããå¿ èŠããããŸãã
ã€ã³ã¹ããŒã«
ãŸãã¯ãã¡ãããããŠã³ããŒãã
https://www.jboss.org/byteman/downloads
çŸæç¹ã§ã®ææ°ããŒãžã§ã³ã¯ã2.1.3ã§ãã
ãšãããããå±éããŸãã
$ unzip byteman-download-2.1.3-bin.zip
æäœéã¯ããããŸã§ããªããã¹ã¯ãªããã§ã¢ã¿ããããããå Žåã«ã¯ãã€ã³ã¹ããŒã«ãã£ã¬ã¯ããªã«å¯ŸããŠç°å¢å€æ°BYTEMAN_HOMEãèšå®ããŠããå¿ èŠããããŸãã
$ export BYTEMAN_HOME=/path/to/byteman-download-2.1.3
ã«ãŒã«ãæžã
ãã€ãã³ãŒãæäœãè¡ãããã«ã¯ãã«ãŒã«ãæžãå¿ èŠããããŸãããããŸãã«ã¯ã
RULE [ã«ãŒã«å] CLASSïŒãŸãã¯INTERFACEïŒ [ã¯ã©ã¹åãŸãã¯ã€ã³ã¿ãŒãã§ãŒã¹å] METHOD [ã¡ãœããå] [é©çšã¿ã€ãã³ã°] IF [ã«ãŒã«ãå®è¡ããæ¡ä»¶] DO [å®è¡ãããã¢ã¯ã·ã§ã³] ENDRULE
端æã£ãŠããšããããããŸããã倧ãŸãã«ã¯ãããªæãã§ãã1ãã¡ã€ã«äžã«ãè€æ°ã®ã«ãŒã«ãèšè¿°ããããšãã§ããŸããã³ã¡ã³ãã¯ãã#ãã§å§ããŠæžããŸãã
ã«ãŒã«ãã¡ã€ã«ã®æ¡åŒµåã¯ãã.btmããšããããã§ãã
æçµçã«ã¯ããã®ãããã®ããã¥ã¡ã³ãã«ããã€ãããšã«ãªããšæããŸãâŠã
https://community.jboss.org/wiki/ABytemanTutorial#top
http://downloads.jboss.org/byteman/2.1.3/ProgrammersGuideSinglePage.2.1.3.1.html
Javaããã°ã©ã ã«ã«ãŒã«ãé©çšãã
2ã€ã®é©ç𿹿³ãããããã玹ä»ããŸãã
Javaã¢ããªã±ãŒã·ã§ã³ã®èµ·åæã«é©çšãã
javaã³ãã³ãã®ãªãã·ã§ã³ã«ãjavaagentãšããèšå®ããŸãã
$ java -javaagent:$BYTEMAN_HOME/lib/byteman.jar=script:[ã«ãŒã«ãã¡ã€ã«] [ã¡ã€ã³ã¯ã©ã¹å]
ãããã¯
$ java -javaagent:$BYTEMAN_HOME/lib/byteman.jar=script:[ã«ãŒã«ãã¡ã€ã«],boot:$BYTEMAN_HOME/lib/byteman.jar -Dorg.jboss.byteman.transform.all [ã¡ã€ã³ã¯ã©ã¹å]
äžã®å Žåã¯ãJavaãæäŸããã¯ã©ã¹ã«ã¢ã¿ããããå Žåã«äœ¿ããŸãã
ãªãããã®æ¹æ³ã§å®è¡ããå Žåã¯ãç°å¢å€æ°BYTEMAN_HOMEã¯å¿ é ã§ã¯ãããŸããã
èµ·åäžã®ã¢ããªã±ãŒã·ã§ã³ã«ã¹ã¯ãªããã§é©çšãã
ãã¡ãã§ã¯ãç°å¢å€æ°BYTEMAN_HOMEã®èšå®ã¯å¿ é ãšãªããŸãã
ãŸãã¯ãã¢ã¿ããããJavaã¢ããªã±ãŒã·ã§ã³ã®PIDãç¹å®ããŸãã
$ jps
ç¹å®ãããããã®PIDã«å¯ŸããŠbminstall.shãå®è¡ããŸãã
$ $BYTEMAN_HOME/bin/bminstall.sh [PID]
ã«ãŒã«ãã¡ã€ã«ã®é©çšã«ã¯ãbmsubmit.shãã-lããªãã·ã§ã³ã§äœ¿çšããŸãã
$ $BYTEMAN_HOME/bin/bmsubmit.sh -l [ã«ãŒã«ãã¡ã€ã«] install rule [ã«ãŒã«å]
ã«ãŒã«ãã¢ã³ããŒãããã«ã¯ãbmsubmit.shãã-uããªãã·ã§ã³ã§äœ¿çšããŸãã
$ $BYTEMAN_HOME/bin/bmsubmit.sh -u [ã«ãŒã«ãã¡ã€ã«å] uninstall RULE [ã«ãŒã«å]
ã-bããªãã·ã§ã³ã§bootstrap classpathã«å ããããšãã§ããã-Dname=valueãã§ã·ã¹ãã ããããã£ãèšå®ã§ããããã§ãã
.batãã¡ã€ã«ãããã®ã§ãWindowsã§ã䜿ããããªæãïŒ
䜿ã£ãŠã¿ã
ã§ã¯ãå®éã«äœ¿ã£ãŠã¿ãŸããããã¹ã±ãŒããŽãŒããšãªã£ãŠããã ãããã«ããã®ãããªã¯ã©ã¹ãçšæããŸããã
// sample/MainClass.java package sample; public class MainClass { public static void main(String[] args) { while (true) { execute(); } } private static void execute() { SimpleImpl si = new SimpleImpl(); si.echo(); si.echo("Message From Main"); System.out.println("count = " + si.getCount()); System.out.println("totalCount = " + si.getTotalCount()); System.out.println("myMethod = " + si.myMethod("Call MyMethod")); try { si.throwException(); } catch (Exception e) { } try { Thread.sleep(3 * 1000L); } catch (InterruptedException e) { } } } // sample/SimpleInterface.java package sample; public interface SimpleInterface { void echo(); void echo(String message); } // sample/SimpleImpl.java package sample; public class SimpleImpl implements SimpleInterface { private static int totalCount = 0; private int count = 0; public String myMethod(String message) { return "***" + message + "***"; } public void echo() { System.out.println("Default Message"); count++; totalCount++; } public void echo(String message) { System.out.println("Echo = " + message); count++; totalCount++; int localCount = count; int localCount2 = localCount; } public int getCount() { return count; } public static int getTotalCount() { return totalCount; } public void throwException() { throw new RuntimeException("Oops!!"); } }
ãã£ãšèµ·åãããŸãŸãç¡éã«ãŒããç¶ããããã°ã©ã ã§ããããã£ãšã€ã³ã¿ãŒãã§ãŒã¹ãå ¥ããŠããŸãã
ã§ã¯ãããã«å®éã«ã«ãŒã«ãé©çšããŠã¿ãŸãã
ãããªãã«ãŒã«2ã€ã§ããããããªã®ãæžããŠã¿ãŸãã
sample.btm
# ã³ã¡ã³ãã¯ãã#ãã§èšè¿° RULE trace entry getCount CLASS sample.SimpleImpl METHOD getCount AT ENTRY IF TRUE DO traceln("========== called getCount =========="), traceStack() ENDRULE # ã«ãŒã«åãåããã°ãè€æ°ã«ãŒã«ã¯èšè¿°å¯èœ RULE trace entry getTotalCount CLASS sample.SimpleImpl METHOD getTotalCount AT EXIT IF TRUE DO traceln("========== called getTotalCount =========="), traceStack() ENDRULE
ãããããSimpleSimple#getCountã®åŒã³åºãæãšgetTotalCountã®çµäºæã«printlnããŠãã¹ã¿ãã¯ãã¬ãŒã¹ãåºåããŸãã
æ®éã«å®è¡ãããš
$ java sample.MainClass Default Message Echo = Message From Main count = 2 totalCount = 2 myMethod = ***Call MyMethod*** Default Message Echo = Message From Main count = 2 totalCount = 4 myMethod = ***Call MyMethod***
ã¿ãããªçµæã«ãªããŸãããBytemanã䜿ã£ãŠãã®ã«ãŒã«ãé©çšãããš
$ java -javaagent:$BYTEMAN_HOME/lib/byteman.jar=script:sample.btboot:$BYTEMAN_HOME/lib/byteman.jar -Dorg.jboss.byteman.transform.all sample.MainClass Default Message Echo = Message From Main ========== called getCount ========== Stack trace for thread main sample.SimpleImpl.getCount(SimpleImpl.java:-1) sample.MainClass.execute(MainClass.java:14) sample.MainClass.main(MainClass.java:6) count = 2 ========== called getTotalCount ========== Stack trace for thread main sample.SimpleImpl.getTotalCount(SimpleImpl.java:32) sample.MainClass.execute(MainClass.java:15) sample.MainClass.main(MainClass.java:6) totalCount = 2 myMethod = ***Call MyMethod*** Default Message Echo = Message From Main ========== called getCount ========== Stack trace for thread main sample.SimpleImpl.getCount(SimpleImpl.java:-1) sample.MainClass.execute(MainClass.java:14) sample.MainClass.main(MainClass.java:6) count = 2 ========== called getTotalCount ========== Stack trace for thread main sample.SimpleImpl.getTotalCount(SimpleImpl.java:32) sample.MainClass.execute(MainClass.java:15) sample.MainClass.main(MainClass.java:6) totalCount = 4 myMethod = ***Call MyMethod***
ã®ããã«ãã³ã³ãœãŒã«ã«ã¡ãã»ãŒãžãšã¹ã¿ãã¯ãã¬ãŒã¹ã®åºåã远å ãããŸãã
ãã¡ããã
$ java sample.MainClass
ã§å®è¡ããåŸã«
## PIDç¹å® $ jps 22913 MainClass 22928 Jps ## ã¢ã¿ãã $ $BYTEMAN_HOME/bin/bminstall.sh 22913 ## ã«ãŒã«ã€ã³ã¹ããŒã« $ $BYTEMAN_HOME/bin/bmsubmit.sh -l sample.btm install rule trace entry getCount install rule trace entry getTotalCount
ã§ãããã§ããããã
ã§ã¯ãããã€ãã«ãŒã«ã®ãµã³ãã«ãèšèŒããŠçµããã«ããŸããã
ãªãŒããŒããŒããå«ãç¹å®ã®ã¡ãœããã«å¯ŸããŠãã«ãŒã«ãé©çšãã
ã¡ãœããåã®åŸã«()ãä»ããªããšãåãååã®ã¡ãœããã«å¯ŸããŠã«ãŒã«ãé©çšãããŸãã
RULE trace all echo CLASS sample.SimpleImpl # ()ãçç¥ããå Žåã¯ãåŒæ°æãç¡ãã®ãã¹ãŠã®ã¡ãœããã«é©çšããã # ã¡ãªã¿ã«ãã³ã³ã¹ãã©ã¯ã¿ã«å¯ŸããŠé©çšãããå Žåã¯ã<init> ãã§æå® METHOD echo AT ENTRY IF TRUE DO traceln("========== call echo method START ==========") ENDRULE
ã¡ãœããã®åŒæ°ãæå®ããŠãã«ãŒã«ãé©çšãã
ã¡ãœããåã®åŸã«()ãä»ããŠããã®äžã«åŒæ°ã®åãæå®ïŒãããã¯æžããã«åŒæ°ãªãã®ã¡ãœãããæå®ïŒããŸãã
RULE trace param echo CLASS sample.SimpleImpl METHOD echo(String) # $0ã¯èªåèªèº«ïŒthisïŒã$1以éã§ã¡ãœããåŒã³åºããã©ã¡ãŒã¿ BIND this = $0, param = $1 AT ENTRY IF TRUE DO traceln("========== this[" + this.getClass().getName() + "] call echo method[" + param + "] START ==========") # BINDããã«ããããªã$0ã$1ãªã©ã䜿ã£ãŠãOK # DO traceln("========== this[" + $0.getClass().getName() + "] call echo method[" + $1 + "] START ==========") ENDRULE
ããã§ã¯ãBINDã䜿ã£ãäŸãæžããŠããŸãã$0ãthisã§ã$1ããå§ãŸã$Nã¯ã¡ãœããã®åŒæ°ã衚ããŸãããã¡ãããBINDèªäœã¯ã¡ãœããã®åŒæ°ã䜿ãå Žåã«éã£ãããšã§ã¯ãããŸããã
ã¡ãœããã®æ»ãå€ãååŸãã
$!ã§ã¡ãœããã®æ»ãå€ããã£ããã£ããããšãã§ããŸããã¡ãªã¿ã«ããRETURNãã¯EXITã®ã·ããã ãããã§ãããŸããããããã¡ãœããã®çµäºæã§ããã
RULE trace method return CLASS sample.SimpleImpl METHOD getCount() AT RETURN IF TRUE # $!ã§ã¡ãœããã®æ»ãå€ DO traceln("========== getCount Return Value[" + $! + "] ==========") ENDRULE
ã€ã³ã¿ãŒãã§ãŒã¹ã«å¯ŸããŠãã«ãŒã«ãé©çšãã
CLASSããŒã¯ãŒãã§ã¯ãªããŠãINTERFACEããŒã¯ãŒãã§ã€ã³ã¿ãŒãã§ãŒã¹åãæå®ããããšã§ãã€ã³ã¿ãŒãã§ãŒã¹ã®å®è£ ã¯ã©ã¹ã«å¯ŸããŠã«ãŒã«ãé©çšããããšãã§ããŸãã
RULE trace interface INTERFACE sample.SimpleInterface METHOD echo() AT ENTRY IF TRUE DO traceln("========== call Interface echo method START ==========") ENDRULE
ã¡ãœããããäŸå€ãã¹ããŒãããæã«ãã«ãŒã«ãé©çšãã
AT THROWã§äŸå€ã¹ããŒæã$^ã§ã¹ããŒãããäŸå€ã䜿ãããšãã§ããŸãã
RULE trace throw exception CLASS sample.SimpleImpl METHOD throwException AT THROW IF TRUE # $^ã§æããããäŸå€ DO traceln("========== in throwException() e = [" + $^ + "] =========="), traceStack() ENDRULE
ä»åã®äŸã§ã¯ãäŸå€ãæ¡ãã€ã¶ããŠããè¡åã®æªãã³ãŒããªã®ã§ãã¹ã¿ãã¯ãã¬ãŒã¹ãåºåããŠããŸãã
ãã£ãŒã«ãã®èªã¿æžã
ãAT READãããAFTER READãã§ãã£ãŒã«ããèªãæãèªãã åŸã
RULE trace field read CLASS sample.SimpleImpl METHOD echo AT READ count IF TRUE DO traceln("========== in echo() read count[" + $0.count + "] ==========") ENDRULE
ãAT WRITEãããAFTER WRITEãã§ãã£ãŒã«ãã«æžã蟌ãæããæžããåŸ
RULE trace field write CLASS sample.SimpleImpl METHOD echo AFTER WRITE count IF TRUE DO traceln("========== in echo() writed count[" + $0.count + "] ==========") ENDRULE
ããããã«å¯ŸããŠãã«ãŒã«ãé©çšã§ããŸãã
staticãã£ãŒã«ãã«å¯ŸããŠé©çšãã
å®ã¯ããã£ãŒã«ããšäžç·ã§ãã
RULE trace static field read CLASS sample.SimpleImpl METHOD echo AFTER WRITE totalCount IF TRUE DO traceln("========== in all echo totalCount writed = [" + sample.SimpleImpl.totalCount + "] ==========") ENDRULE
ããŒã«ã«å€æ°ã«å¯ŸããŠãé©çšãã
æ¡ä»¶ä»ãã§ããAT READãããAFTER WRITEããªã©ãããŒã«ã«å€æ°ã«å¯ŸããŠãé©çšããããšãã§ããŸãã
æ¡ä»¶ã¯ãã³ã³ãã€ã«æã«ã-gããªãã·ã§ã³ãæå®ãããã
$ javac -g [ãœãŒã¹ãã¡ã€ã«]
ãããã¯ãã-gããªãã·ã§ã³ã«å°ãªããšããvarsããå ããŠããå¿ èŠããããŸãã
$ javac -g:vars [ãœãŒã¹ãã¡ã€ã«]
ã«ãŒã«ã®ãµã³ãã«ã
# ããŒã«ã«å€æ°ã䜿ãã«ã¯ã #ãjavac -gããããã¯ãjavac -g:varsããå«ããŠã³ã³ãã€ã«ããŠããå¿ èŠããã RULE trace local var write CLASS sample.SimpleImpl METHOD echo(String) # $ããŒã«ã«å€æ°åã§åç §å¯èœ AFTER READ $localCount IF TRUE # $ããŒã«ã«å€æ°åã§åç §å¯èœ DO traceln("========== in echo(String) writed localVar[" + $localCount + "] ==========") ENDRULE
ããŒã«ã«å€æ°ã¯ãã$ããŒã«ã«å€æ°åãã§åç §ããããšãã§ããŸãã
å®é䜿ã£ãŠã¿ãŠããã£ã±ããªããªãé¢çœãã£ãã§ããæ©äŒãèŠã€ããŠã掻çšããŠããããšæããŸãã