LoginSignup
2
2

More than 5 years have passed since last update.

JavaEEサーバーでLog4j2を使ってみた

Last updated at Posted at 2018-12-21

環境について

環境は、以前書いた記事のものと同一です。
IntelliJ Community で Tomcat の実行環境を整備する

一応雑にまとめると以下のような感じになります。

種類 ソフトウェア
言語 Java SE 8
サーバーAPI JavaEE
Log API Log4j2
IDE IntelliJ Community
ビルドツール Gradle
コンテナ Tomcat

webappフォルダを作成する

JavaEEプロジェクトであれば既に作成済みかもしれませんが、以下のようにディレクトリを作成します。
<プロジェクト> -> src -> main -> webapp (※) -> WEB-INF (※)
(※) 作成するディレクトリ
また、ディレクトリはちゃんと"webapp"、"WEB-INF"としましょう。

そして、WEB-INF内に"classes"、"lib"というディレクトリも作成しておきましょう。

プロジェクトにlog4j2を追加

build.gradleのdependancesに以下のように追加します。

dependencies {
    // log4jを使えるようにする
    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.1'
    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.1'
    compile group: 'org.apache.logging.log4j', name: 'log4j-web', version: '2.11.1'
}

Loggerクラスを作成する

Logを書き込む際、毎回前準備のコードを書くのは面倒であるため、以下のようにラップクラスを作成します。
コードは、以下のリンクを参考にしました。
SpringMVC の小径 ちょっと寄り道 ロギングの小径

import org.apache.logging.log4j.LogManager;

import java.io.File;

/**
 * ロギング処理を行う
 */
public class Log4j {

    private static Log4j logger = null;

    private Log4j() {
    }

    public static synchronized Log4j getInstance() {
        if (logger == null) {
            logger = new Log4j();
        }
        return logger;
    }

    private String getMessage(final String msg) {
        String thisClassName = this.getClass().getName();
        //クラス名を取得
        String SuperClassName = Logger.class.getName();
        Thread t = Thread.currentThread();
        StackTraceElement[] stackTraceElements = t.getStackTrace();
        int pos = 0;
        for (StackTraceElement stackTraceElement : stackTraceElements) {
            String steClassName = stackTraceElement.getClassName();
            if (thisClassName.equals(steClassName) || SuperClassName.equals(steClassName)){
                break;
            }
            pos++;
        }
        pos += 2;
        StackTraceElement m = stackTraceElements[pos];
        return m.getClassName() + ":" + m.getMethodName() + "() \n" + msg;
    }

    private String getErrorMessage(final Exception e) {
        StringBuilder sb = new StringBuilder();
        StackTraceElement[] st = e.getStackTrace();
        if (st != null && st.length > 0) {
            sb.append("Class:")
                    .append(e.getClass().getName())
                    .append("¥n")
                    .append("Detail:")
                    .append(e.getMessage())
                    .append("¥n");
            for (StackTraceElement s : st) {
                sb.append(s.toString())
                        .append("¥n");
            }
        }
        return sb.toString();
    }

    public void debug(final String msg) {
        LogManager.getLogger(this.getClass()).debug(getMessage(msg));
    }

    public void info(final String msg) {
        LogManager.getLogger(this.getClass()).info(getMessage(msg));
    }

    public void info(final Object obj, final String msg) {
        LogManager.getLogger(obj.getClass()).info(msg);
    }
    public void warn(final String msg) {
        LogManager.getLogger(this.getClass()).warn(getMessage(msg));
    }

    public void error(final Exception e) {
        LogManager.getLogger(e.getClass()).error(getErrorMessage(e));
    }

    public void trace(final String msg) {
        LogManager.getLogger(this.getClass()).trace(getMessage(msg));
    }

    public void fatal(final String msg) {
        LogManager.getLogger(this.getClass()).fatal(getMessage(msg));
    }
}

EndPoint内では、以下のように呼び出して利用します。

Log4j logger = Log4j.getInstance();
logger.info("ここにログ内容を書く");

log4jには、以下のようなレベルのログが用意されており、それに合わせてラップメソッドを定義してあります。

fatal > error > warn > info > debug > trace

Log4J徹底解説

log4j2設定ファイルを作成する

log4j2の設定ファイルは、"log4j2.xml"という名前のxmlファイルに記述します。
また、Tomcatでは、webapp -> WEB-INF -> classesフォルダに置くことで、自動で読み込むことが出来ます。
log4j2.xmlの記入例を示します。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="off">

    <Properties>
        <Property name="loglayout">[%d{yyyy-MM-dd HH:mm:ss.SSS}], %-5p, %t, %c, %m%n</Property>
    </Properties>

    <Appenders>
        <!--
            fileName:ログを出力するファイル名
            filePattern:ログが溜まってきたときに圧縮するファイルのパターン
        -->
        <RollingFile name="rolling" fileName="./log/webapp.log" filePattern="./log/webapp-%d{yyyy-MM-dd}-%i.zip">
            <PatternLayout pattern="${loglayout}"/>
            <Policies>
                <OnStartupTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="20 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <DefaultRolloverStrategy max="10"/>
        </RollingFile>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="${ptn}" />
        </Console>
    </Appenders>

    <Loggers>
        <!--
            name:ログ出力を行うパッケージ名
            level:ログの出力レベル
            additivity:上位のログを出力するかどうか
        -->
        <Logger name="Logger" level="info" additivity="true">
            <AppenderRef ref="rolling"/>
        </Logger>
    </Loggers>
</Configuration>

詳しい説明については、以下のリンクに記載されています。

Log4j2でログ出力

war化した時にファイルパスを変更する

Gradleプロジェクトでは、相対パスがプロジェクト直下であるため、ファイルのディレクトリを
. -> log
としていましたが、Tomcatでは、相対パスのルートがtomcatインストールフォルダになっているので、
. -> webapps -> -> WEB-INF -> log
にする必要があります。
xml内で指定する方法もあるようでしたが、
log4j2.xml //開発用
log4j2_exe.xml //本番用
これを、war化するときだけ
log4j2_test.xml //開発用
log4j2.xml //本番用
に名前変更することで対応しました。

実際には、build.gradleに、以下のコードを追加します。

// warタスク実行前に実行
war.doFirst {
    //子ファイルを取得
    java.io.File[] flist = (new java.io.File("./src/main/webapp/WEB-INF/classes")).listFiles();
    for(i in flist) {
        //ファイル名判定
        switch (i.getName()) {
            case "log4j2.xml":
                //リネーム
                i.renameTo(new java.io.File("./src/main/webapp/WEB-INF/classes/log4j2_test.xml"));
                break;

            case "log4j2_exe.xml":
                i.renameTo(new java.io.File("./src/main/webapp/WEB-INF/classes/log4j2.xml"));
                break;
        }
    }
}

//warタスク実行後に実行
war.doLast {
    java.io.File[] flist = (new java.io.File("./src/main/webapp/WEB-INF/classes")).listFiles();
    for(i in flist) {
        switch (i.getName()) {
            case "log4j2_test.xml":
                i.renameTo(new java.io.File("./src/main/webapp/WEB-INF/classes/log4j2.xml"));
                break;

            case "log4j2.xml":
                i.renameTo(new java.io.File("./src/main/webapp/WEB-INF/classes/log4j2_exe.xml"));
                break;
        }
    }
}

問題点

warタスク実行ごとにファイルを作成すると、gitに管理ファイルとして認識されない
-> 設定をほにゃほにゃして1つのxmlでできるようにするべき

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2