GWT Remote Loggingで出力されるログを読みやすくする


Google Web Toolkit にはJavaのLoggingインタフェースを利用したロギング機構が用意されています。

中でも強力なのはRemote Loggingが標準でサポートされていることです。
クライアントのエラーをサーバーに集められるため迅速なトラブルシューティングが可能になります。

しかし、GWTのデフォルトのコンパイルスタイル OBFUSCATED だとスタックトレースは以下のように、最も難読化されたモードのまま出力されてしまいます。
例えば、GWT2.5.0のsamplesに含まれるLogExampleを実行して、”Trigger Exception”ボタンをクリックして出力されるスタックトレースは以下のようになります。
[text]
Sat Nov 02 10:15:15 GMT+900 2013 SEVERE: Fake Null Exception Hit
java.lang.NullPointerException: null
at Unknown.Ec(StackTraceCreator.java:174)
at Unknown.jI(StackTraceCreator.java:501)
at Unknown.Rv(OneLoggerController.java:70)
at Unknown.Of(ClickEvent.java:55)
at Unknown.Gh(GwtEvent.java:76)
at Unknown.vh(HandlerManager.java:127)
at Unknown.Sr(Widget.java:129)
at Unknown.Bf(DomEvent.java:116)
at Unknown._r(UIObject.java:557)
at Unknown.ay(DOM.java:1307)
at Unknown.anonymous(DOMImplStandard.java:171)
at Unknown.Xb(Impl.java:189)
at Unknown.$b(Impl.java:242)
at Unknown.anonymous(Impl.java:70)
[/text]
これでは、なかなかエラーを追うのが大変なため、以下のように元のクラス名に変換して出力ように設定していきます。
[text]
2013/11/02 10:15:15 com.google.gwt.logging.server.RemoteLoggingServiceUtil logOnServer
SEVERE: Fake Null Exception Hit
java.lang.Throwable
at com.google.gwt.core.client.impl.StackTraceCreator$CollectorEmulated.$fillInStackTrace(StackTraceCreator.java:174)
at java.lang.NullPointerException.NullPointerException(NullPointerException.java:501)
at com.google.gwt.sample.logexample.client.OneLoggerController_MyUiBinderImpl$Widgets$2.onClick(OneLoggerController_MyUiBinderImpl.java:70)
at com.google.gwt.event.dom.client.ClickEvent.dispatch(ClickEvent.java:55)
at com.google.web.bindery.event.shared.SimpleEventBus.$doFire(SimpleEventBus.java:76)
at com.google.gwt.event.shared.HandlerManager.$fireEvent(HandlerManager.java:127)
at com.google.gwt.user.client.ui.Widget.$fireEvent(Widget.java:129)
at com.google.gwt.event.dom.client.DomEvent.fireNativeEvent(DomEvent.java:116)
at com.google.gwt.user.client.ui.Widget.onBrowserEvent(Widget.java:557)
at com.google.gwt.user.client.DOM.dispatchEvent(DOM.java:1307)
at Unknown.anonymous(DOMImplStandard.java:171)
at com.google.gwt.core.client.impl.Impl.apply(Impl.java:189)
at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:242)
at Unknown.anonymous(Impl.java:70)
[/text]

1. Remote Loggingを有効にする

gwt.xmlで以下のプロパティを設定するとサーバーにログが送信されるようになります。
[xml]
<set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
[/xml]
LogExampleの場合は、既に設定済みですので、samples/LogExample/src/com/google/gwt/sample/logexample/LogExample.gwt.xml を確認してください。

2. コンパイル時にsymbolMapsをwarに含める

symbolMapsは、コンパイルされたJavascriptのメソッド名と実際のクラス/メソッドのマップを保持するファイルを含みます。
デフォルトでは、コンパイル時に -war に指定されたディレクトリの WEB-INF/deplay/<モジュール名>/symbolMaps ディレクトリに出力されるので、そのままwarファイルに含まれます。

3. symbolMapsを読み込むRemoteLoggingServiceを実装する

サーバーでクライアントのログを受けるためには、RemoteLoggingServiceImpl を web.xml に追加します。
samples/LogExample/war/WEB-INF/web.xml で確認できます。

いくつかのブログや掲示板では、この RemoteLoggingServiceImpl の init-param に symbolMaps のパスを渡すとスタックトレースが実際のJavaのクラス/メソッドに変換されて出力される記述されていますが RemoteLoggingServiceImp はinit-paramをハンドリングしません。

そのため、RemoteLoggingServiceImp を拡張するクラスを実装する必要があります。
Removing obfuscation from a stack trace.

LogExampleを用いて確認するために、src/com/google/gwt/sample/logexample/server/MyRemoteLoggingService.java を以下のように記述しました。
[java]
package com.google.gwt.sample.logexample.server;

import com.google.gwt.logging.server.RemoteLoggingServiceImpl;
import javax.servlet.*;
public class MyRemoteLoggingService extends RemoteLoggingServiceImpl {

@Override
public void init() throws ServletException {
super.init();
setSymbolMapsDirectory(getServletContext().getRealPath("/WEB-INF/deploy/logexample/symbolMaps"));
}

}
[/java]
web.xml のサーブレット設定も RemoteLoggingServiceImpl から MyRemoteLoggingService へ変更します。
[xml]
<servlet>
<servlet-name>remoteLoggingServlet</servlet-name>
<servlet-class>com.google.gwt.sample.logexample.server.MyRemoteLoggingService</servlet-class>
<init-param>
<param-name>symbolMaps</param-name>
<param-value>WEB-INF/deploy/logexample/symbolMaps</param-value>
</init-param>
</servlet>
[/xml]

以上を設定して実行すると、上記のJavaのクラス・メソッド名に変換されたスタックトレースが出力されるようになります。

参考:
7 Tips for Exception Handling in GWT
Using the GWT Compiler for Better Builds

,