Akira's Tech Notes

Java/JVM | GNU/Linux | Emacs/Lisp | 知的好奇心駆動

header-icon
ネイティブでない日本語で思い付くことや気になることをダラダラ書く、体裁とかは気にしない。読みづらいと感じた時に随時更新する。

[検証]BytemanでWeblogicのアプリをトレースする

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

Comments