Top > Blog > Programming

Log4J でログファイル名を動的に変更する

以前参加していたプロジェクトでバッチプログラムを開発する事案があり、 ログ出力には Log4J を採用してプログラムを開発しました。
ところが、後付けでログ出力方式が決まり^^; ログファイル名をサーバーの環境変数から取得しなければならなくなってしまいました。

環境変数からログファイル名を取得…それぐらい Log4J なら簡単だよね、と思いつつやってみたら、出来ません。 ログファイル名は設定ファイルに記述されていて、固定なのです…。

しかし、Log4J は簡単に拡張することが出来ます。
「環境変数からログファイル名を取得する」というような場合には Appender を自作すれば解決できます。

今回の場合、バッチプログラムの動作環境が JRE 1.4 なので環境変数が取得できない件も考慮し、 JVM の起動引数からファイル名を取得する Appender を自作しました。

独自の Appender クラス
package jp.javable.sample.log4j;

import java.io.IOException;

import org.apache.log4j.Layout;
import org.apache.log4j.RollingFileAppender;

public class JavableFileAppender extends RollingFileAppender {
    
    /**
     * コンストラクタです。
     */
    public JavableFileAppender() {
        super();
        setFile(getFile());
    }

    /**
     * コンストラクタです。
     * 
     * @param layout レイアウトオブジェクト
     * @param filename 出力ログファイル名
     * @throws IOException IO例外が発生した場合
     */
    public JavableFileAppender(Layout layout, String filename)
            throws IOException {
        super(layout, filename);
        setFile(getFile());
    }

    /**
     * コンストラクタです。
     * 
     * @param layout レイアウトオブジェクト
     * @param filename 出力ログファイル名
     * @param append ログファイルに追記するかどうかのフラグ
     * @throws IOException IO例外が発生した場合
     */
    public JavableFileAppender(Layout layout, String filename, boolean append)
            throws IOException {
        super(layout, filename, append);
        setFile(getFile());
    }
    
    
    /**
     * JVM の起動引数(-Dlog.file.name)からファイル名を取得するメソッドです。<br/>
     * {@link FileAppender#getFile()}をオーバーライドします。
     * 
     * @see org.apache.log4j.FileAppender#getFile()
     */
    public String getFile() {
        String filename = System.getProperty("log.file.name");
        if (filename == null) {
            filename = super.getFile();
        }
        return filename == null ? "" :  filename;
    }
}
Log4J の設定ファイル
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    
    <appender name="Log4JFileAppender"
              class="org.apache.log4j.RollingFileAppender">
        <param name="File" value="test1.log"/>
        <param name="MaxFileSize" value="1MB"/>
        <param name="MaxBackupIndex" value="10"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                    value="%d{yyyy/MM/dd HH\:mm\:ss.SSS}[%-5p](%c{1}) %m%n"/>
        </layout>
    </appender>
    
    <appender name="SampleFileAppender"
              class="jp.javable.sample.log4j.JavableFileAppender">
<!--        <param name="File" value="test2.log"/> -->
        <param name="MaxFileSize" value="1MB"/>
        <param name="MaxBackupIndex" value="10"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="%d{yyyy/MM/dd HH\:mm\:ss.SSS}[%-5p](%c{1}) %m%n"/>
        </layout>
    </appender>

    <logger name="jp.javable.sample.log4j">
        <level value="DEBUG"/>
        <appender-ref ref="SampleFileAppender"/>
    </logger>
    
    <root>
        <level value="WARN"/>
    </root>

</log4j:configuration>
テスト用のクラス
package jp.javable.sample.log4j;

import org.apache.log4j.Logger;

public class LogTest {
    
    private static Logger logger = Logger.getLogger(LogTest.class);
    
    public static void main(String[] args) {
        // 起動引数で指定したファイル名で出力されればOK
        logger.debug("テスト");
    }
}
実行例
H:\temp> java -Dlog.file.name=sample.log \(実際は一行)
        -classpath classes;lib\log4j-1.2.13.jar jp.javable.sample.log4j.LogTest

上記のように実行すると、 実行を行ったディレクトリに sample.log というファイル名でログが出力されました。

今回作成したクラスは Log4J 標準の RollingFileAppender を継承して getFile() メソッドをオーバーライドした後、 コンストラクタでファイル名を再設定するように記述してあります。
通常の RollingFileAppender と同じように設定して、設定ファイルでログファイル名を記述せずにいると、起動引数からファイル名を取得するようになります。

作成したソースはこちらです。

Log4J は、簡単に様々な機能を追加することが出来そうです。

コメントの投稿