Apache Velocity を使ったモジュールをLinux環境にリリースしたら、エラーが発生したときの対応方法

Tips

仕事でインフラ周りの作業をやって、出くわしたさまざまな問題を備忘録に残しておきたくて。
今回はVelocity を使ったモジュールでエラーが発生して、開発環境がWin環境、本番環境がLinux環境だったから発生した問題の作業したことをまとめてみました。

「Apache Velocity」とは

「Apache Velocity」とは、Javaベースのテンプレートエンジンです。(以下、Velocity。)
テンプレートエンジンとはプログラムで変更する部分と、 雛形となるドキュメントのテンプレートを別々に扱う仕組みです。

Velocity を使ったモジュール

Velocity を使ったモジュール、今回は「JavaMail」ですね。
本番環境でメール送信の処理に入ると、例外発生してしまい、メール送信ができませんでした。

エラーが起きたサーバー環境は以下の通り。

CentOS 7
Tomcat 8

サーバーの処理の環境は以下の通り。

Java 1.8
Spring MVC 4.3.4
maven 2.9
JavaMail API 1.4.3
velocity 1.7

エラー内容はこんな感じ。

org.apache.velocity.exception.VelocityException: Error initializing log: Failed to initialize an instance of org.apache.velocity.runtime.log.Log4JLogChute with the current runtime configuration.
at org.apache.velocity.runtime.RuntimeInstance.initializeLog(RuntimeInstance.java:875)

…(中略)…

Caused by: org.apache.velocity.exception.VelocityException: Failed to initialize an instance of org.apache.velocity.runtime.log.Log4JLogChute with the current runtime configuration.
at org.apache.velocity.runtime.log.LogManager.createLogChute(LogManager.java:220)
at org.apache.velocity.runtime.log.LogManager.updateLog(LogManager.java:269)
at org.apache.velocity.runtime.RuntimeInstance.initializeLog(RuntimeInstance.java:871)
… 61 more
Caused by: java.lang.RuntimeException: Error configuring Log4JLogChute :
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.apache.velocity.util.ExceptionUtils.createWithCause(ExceptionUtils.java:67)
at org.apache.velocity.util.ExceptionUtils.createRuntimeException(ExceptionUtils.java:45)
at org.apache.velocity.runtime.log.Log4JLogChute.initAppender(Log4JLogChute.java:133)
at org.apache.velocity.runtime.log.Log4JLogChute.init(Log4JLogChute.java:85)
at org.apache.velocity.runtime.log.LogManager.createLogChute(LogManager.java:157)
… 63 more
Caused by: java.io.FileNotFoundException: velocity.log (Permission denied)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.(FileOutputStream.java:213)
at java.io.FileOutputStream.(FileOutputStream.java:133)
at org.apache.log4j.FileAppender.setFile(FileAppender.java:290)
at org.apache.log4j.RollingFileAppender.setFile(RollingFileAppender.java:194)
at org.apache.log4j.FileAppender.(FileAppender.java:109)
at org.apache.log4j.RollingFileAppender.(RollingFileAppender.java:72)
at org.apache.velocity.runtime.log.Log4JLogChute.initAppender(Log4JLogChute.java:118)
… 65 more

「velocity.log」というログファイルがないよーって怒られています。
でも、そもそも、開発中に「velocity.log」使っていた覚えがない。ローカル環境(Win)では出力されていなかった。

原因を探していると、以下の記事に辿りつきました。どうやらLinux環境だけに発生する現象らしい。

http://blogs.yahoo.co.jp/dk521123/36257386.html

解決案

書き込み許可があるvelocity.logファイルを作成する

とりあえず対処したい場合、velocity.logファイルを作成し、tomcat起動ユーザーで書き込みができるようにしていれば、例外が発生しなくなります。
デフォルト設定の場合、カレントディレクトリに作成されます。

カレントディレクトリってどこよ?

カレントディレクトリはTomcatのサービスコマンドを叩いた場所です。

もしくは、どこかに以下の出力して、現在のカレントディレクトリはどこか確認するといいですね。

System.getProperty("user.dir")

ログ出力を無効にする

もっとちゃんと対処したい場合、ログ出力を無効にするのがベターですね。

init()呼び出す際、ログ出力する設定を追加します。
なので、Javaのソースを修正する必要が出てきます。

init()メソッドを呼び出す前に以下を記述する。

Velocity.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.NullLogSystem");

もしくは、

velocity.properties ファイルを用意。

[WEB-INF/velocity.properties]
runtime.log.logsystem.class = org.apache.velocity.runtime.log.NullLogSystem

init()メソッドにプロパティファイルの引数を持たせる。
init()→init( Properties p )

http://java.akjava.com/library/jakarta-velocity/log

まとめ

結構悩んだ事象だったので、他の人の手助けになれば、幸いです。

参考資料