本来、会社ブログで書いていた記事なのだけど、そろそろサイト毎消そうかという話が出てきて、でも「はてなブックマーク」やらgoogle検索からアクセスやらが非常に多い記事なので、こちらに転記しておきます(2012/02/25)。
※元記事の執筆は、2010/01/14です。

———————————————

年末年始休暇からGoogle App Engine for Java(以下、GAE/J)を触り始めてみました。環境を整えていく最中に、ログ出力がJSTで出力できない点が気になったので、色々試行錯誤した流れを、つらつらと。

#2009年はほとんどPHPを触ってたせいで、ほぼ1年ぶりにjavaをガリガリしてるので、細かな間違いはご容赦。頭がPHPからJavaに切り替わりきれていないので、文字列を結合しようとして思わず”+”じゃなくて”.”を使ってしまう状況と言っておくとわかりやすいかも(単なる言い訳)

さてさて、調査を続けるも、なかなか「これだ!」という解決方法が見つかりません(そもそもlog4jってどう使うんだっけ?からスタートしたのは内緒)。国際化とか言語ファイルとか、ソフトウェアを使う側としては何度も経験してるけど、作る側としてはなかなか・・・頭では分かっているのだけど、ここしばらく限定された社内システムしか作ってなかったし、TimeZoneとか時差の問題なんて、航空システムにかかわっていた時に多少は触ったけれど・・・何年前?という程度。錆びついた頭をガタゴト言わせる時間が続きます。

最初に見つけたのがGoogle App Engine Log Timezone Adjusterでした。ただ、どうもFireFoxのプラグインで表示された時刻をJavaScriptで書き換えてあげるものらしく(詳しくは見てないけれど)、Operaユーザーの私にはちょっと不向き。それはまあ、わざわざGAE/Jで何かしようとする人なら、FireFoxの一つや二つ使っているでしょうし、私もサブ・ブラウザとして使っていますが、ログを見るときにいちいち別のブラウザを起動するのはしんどいです。

というわけで、別の方法を模索・・・。

そもそも、上のプラグインを作成した方も書いているように、要望の高い機能ではないのかと思うのだけど・・・世界中の人々が悲鳴をあげているし

・・・世界中でこれだけ騒がれているのに決定版がないということは、やっぱり(現時点では)できないのかも。。と心が折れ始めるも、もうちょっと頑張ろうと自分を奮い立たせること3日。

TimeZoneとLocale – @yanaginの日記
Google App Engine/Javaでcommons-logging+Log4jでロギングする。 – 北海道を愛するプログラマの覚書

結論から言うと、管理コンソールの出力時間を変更することはできなかったので(つまりPSTでしか出力時刻フィルタできない)、出力されるログの日付を日本時間(JST)で出力して代用することに方針変更。

そして見つけたのが、このフォーラムでの問答。
Timezone information in Log4j logs – nabble.com

Das,Amarさんの質問

I have a program running on a server in Dallas. I need to generate log4j
output in timezone “America/New_York”. How can I do that?
(ダラスで動かしてるシステムで、log4jのログをニューヨーク時間で出したいんだ。どうすればいいんだろう?)

に対する、carnold-3さんの答え

The enhanced pattern layout in the extras companions supports time
zone specifiers on date formats.
(拡張版のパターンレイアウトがタイムゾーンをサポートしてるよ)

アーノルドっ(勝手に命名)!!これだ!

さっそく、log4jの拡張版をダウンロードしてきて(http://logging.apache.org/log4j/companions/extras/)、apache-log4j-extras-1.0.jarをWEB-INF/libに放り込みます。

アーノルドの助言によると、log4j.propertiesに下記2点の修正を入れればよいらしい。

  • EnhancedPatternLayoutクラスを指定する
  • パターンに%d{yyyy-MM-dd HH:mm:ss}{TimeZone}と指定する
    (日時パターンの次に中括弧で設定したいTimeZoneを入れてあげればよいらしい)

なので、こんな感じ。

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.EnhancedPatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss}{Asia/Shanghai} %-5p - %m%n

※TimeZoneにはローカル環境なので、仮に上海とする。

appengine-web.xmlも変更して、

<system-properties>
 <property name="java.util.logging.config.file" value="WEB-INF/classes/log4j.properties"/>
</system-properties>

テスト用のServletを作って・・・

public class Log4JSampleServlet extends HttpServlet
{
 private static Log logger = LogFactory.getLog(Log4JSampleServlet.class);
 public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException
 {
  Date date = new Date();
  logger.info("time : " + date);
 }
}

Go!

出力されたログ↓

2010-01-13 16:17:50 INFO - time : Wed Jan 13 08:17:50 UTC 2010

実行したのが日本時間の17:17。それが、UTCだと08:17で、上海だと16:17。
ばっちり!

レッツ、本番!
TimeZoneの指定を{Asia/Tokyo}に変更し、デプロイ。

使用前

2010-01-13 16:18:35 INFO - time(before) : Wed Jan 13 16:18:35 UTC 2010

使用後

2010-01-14 01:22:35 INFO - time(after) : Wed Jan 13 16:22:35 UTC 2010

・・・できた!
GAEの管理コンソールの画面イメージを貼り付けろと言われたのだけど、ちょっともう眠いので省略。。あとで貼っておくので、各自で試してみてください。。

というわけで、今回の教訓。

  1. 「log4jなんて枯れ切ってる技術じゃん。今使っている機能以上のものなんてないよ!」みたいな先入観はいけない
  2. そもそも国内に4つものTimeZoneを持つ米国の企業たるGoogle様が作ったGAEが、TimeZoneを考慮していないなんてあり得ない。
  3. EnhancedPatternLayoutを教えてくれたアーノルドには、2010年1月度の月間MVPを進呈
  4. さくっと画面イメージを取れるツール、何かオススメない?

・・・おやすみ。
最後グダグダになってしまったので、あとできちんと清書します。。

[amazon asin=”059652272X” /] [amazon asin=”4797357606″ /]