Table of Contents
Weblogicのインスツルメンテーション機能に対して以下の課題が抱えていたため、Bytemanを使 うことにしました。
DisplayArgumentsAction
でメソッドの引数と戻り値が取れない- 採集結果がバイナリのため、利用不便(テキスト形式が望ましい)
- アプリ再デプロイするとインスツルメンテーション定義が消える
Byteman
はRed HatがリードするJBoss Communityプロジェクトのひつとであるため
Weblogic
でちゃんと動くが不安でした。検証したところ問題なく動いたので手順を残してお
きます。
1 環境
- Red Hat Enterprise Linux Server release 5.8 (Tikanga)
- WebLogic Server 10.3.6.0
- Byteman 2.2.2
2 インストール
$ cd /tmp $ wget http://downloads.jboss.org/byteman/2.2.2/byteman-download-2.2.2-bin.zip $ unzip byteman-download-2.2.2-bin.zip
3 WLS起動オプションの変更
$DOMAIN_HOME/bin/startWebLogic.sh
に -javaagent
オプションにてBytemanを取り込む。
167| # START WEBLOGIC 168| 169| echo "starting weblogic with Java version:" 170| 171| ${JAVA_HOME}/bin/java ${JAVA_VM} -version +| +|## add byteman agent +|## 必要に応じてSERVER_NAME変数を利用し、特定の管理対象サーバのみに適用する +|## if [ "${SERVER_NAME}" = "xxx_server" ]; then +|BYTEMAN_HOME=/tmp/byteman-download-2.2.2 +|JAVA_OPTIONS="-javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all ${JAVA_OPTIONS}" +| 172| 173| if [ "${WLS_REDIRECT_LOG}" = "" ] ; then 174| echo "Starting WLS with line:" 175| echo "${JAVA_HOME}/bin/java ${JAVA_VM} ${MEM_ARGS} -Dweblogic.Name=${SERVER_NAME} -Djava.security.policy=${WL_HOME}/server/lib/weblogic.policy ${JAVA_OPTIONS} ${PROXY_SETTINGS} ${SERVER_CLASS}" 176| ${JAVA_HOME}/bin/java ${JAVA_VM} ${MEM_ARGS} -Dweblogic.Name=${SERVER_NAME} -Djava.security.policy=${WL_HOME}/server/lib/weblogic.policy ${JAVA_OPTIONS} ${PROXY_SETTINGS} ${SERVER_CLASS} 177| else 178| echo "Redirecting output from WLS window to ${WLS_REDIRECT_LOG}" 179| ${JAVA_HOME}/bin/java ${JAVA_VM} ${MEM_ARGS} -Dweblogic.Name=${SERVER_NAME} -Djava.security.policy=${WL_HOME}/server/lib/weblogic.policy ${JAVA_OPTIONS} ${PROXY_SETTINGS} ${SERVER_CLASS} >"${WLS_REDIRECT_LOG}" 2>&1 180| fi
+
が追加内容となります。
4 テスト用サーブレット
URLパラメータを画面に返す単純なサーブレットをWLSにデプロイする。
1| package testwebapp; 2| 3| import java.io.IOException; 4| import java.io.PrintWriter; 5| 6| import javax.servlet.*; 7| import javax.servlet.http.*; 8| 9| public class HelloWorldServlet extends HttpServlet { 10| private static final String CONTENT_TYPE = "text/html; charset=UTF-8"; 11| 12| public void init(ServletConfig config) throws ServletException { 13| super.init(config); 14| } 15| 16| public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 17| 18| System.out.println("--doGet--"); 19| 20| request.setCharacterEncoding("UTF-8"); 21| 22| response.setContentType(CONTENT_TYPE); 23| PrintWriter out = response.getWriter(); 24| out.println("<html>"); 25| out.println("<head><title>HelloWorldServlet</title></head>"); 26| out.println("<body>"); 27| out.println(String.format("<p>Hello %s</p>", request.getParameter("Name"))); 28| out.println("</body></html>"); 29| out.close(); 30| } 31| }
20行目、マルチバイト文字化けを防ぐために setCharacterEncoding("UTF-8")
にてデコード用の文字コー
ドを指定しています。
5 トレースして見る
下記Bytemanスクリプトで setCharacterEncoding("UTF-8")
前後で request.getParameter("Name")
の値を出力する。
/tmp/trace_HelloWorldServlet.btm
4行目と13行目はトレース対象Javaソースコードの行数
を指定しています。
1| RULE trace before setCharacterEncoding 2| CLASS testwebapp.HelloWorldServlet 3| METHOD doGet 4| AT LINE 18 5| IF TRUE 6| DO traceln("request.getParameter(\"Name\") = " + $request.getParameter("Name")) 7| ENDRULE 8| 9| 10| RULE trace after setCharacterEncoding 11| CLASS testwebapp.HelloWorldServlet 12| METHOD doGet 13| AT LINE 24 14| IF TRUE 15| DO traceln("request.getParameter(\"Name\") = " + $request.getParameter("Name")) 16| ENDRULE
スクリプトをByteman Agentにロードする、この時点でバイトコードのインジェクションが実施 される。
$ export BYTEMAN_HOME=`pwd` $ export JAVA_HOME=/u01/jdk1.7.0_75/ $ export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.65.x86_64 $ ${BYTEMAN_HOME}/bin/bmsubmit.sh /tmp/trace_HelloWorldServlet.btm install rule trace before setCharacterEncoding install rule trace after setCharacterEncoding
curl
でテスト用サーブレットをキックする。
$ curl http://10.185.136.15:8001/TestWebApp/HelloWorldServlet?Name=あきら <html> <head><title>HelloWorldServlet</title></head> <body> <p>Hello あきら</p> </body></html>
WLSサーバの標準出力を確認する。
request.getParameter("Name") = ããã --doGet-- request.getParameter("Name") = あきら
バッチリですね!
最後に、登録したトレーススクリプトをアンロードし、バイトコードを元に戻す。
$ export BYTEMAN_HOME=`pwd` $ export JAVA_HOME=/u01/jdk1.7.0_75/ $ export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.65.x86_64 $ ${BYTEMAN_HOME}/bin/bmsubmit.sh -u /tmp/trace_HelloWorldServlet.btm uninstall RULE trace before setCharacterEncoding uninstall RULE trace after setCharacterEncoding