Logback 使い方メモ

  • 202
    Like
  • 0
    Comment
More than 1 year has passed since last update.

Logback とは

Java のロギングライブラリ。

Log4j の開発者が作った別のロギングライブラリ。

歴史的な背景とか、 SLF4J との関係については、 Javaのログ出力: 道具と考え方 というスライドがとても参考になります。

Hello World

インストール

build.gradle
    compile 'ch.qos.logback:logback-classic:1.1.3'

実装

Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);
        logger.info("Hello Logback!!");
    }
}
実行結果
11:14:22.582 [main] INFO  sample.logback.Main - Hello Logback!!

説明

  • 依存関係には、とりあえず logback-classic を追加すれば動かせる。
    • 推移的な依存関係の解決で、 logback-coreslf4j-api などが付いてくる。
  • Logback を使う場合、 API はログファサードである SLF4J を使用する。
  • 設定ファイル(logback.xml)が存在しない場合、デフォルトでコンソールにログが出力される。
  • ロガーの取得には、 LoggerFactory#getLogger() を使う。
    • 引数にはロガーを特定するための名前を渡す。
    • 普通は、ロガーを使うクラスの Class オブジェクトを渡す。
    • すると、クラスの FQCN を名前にしたロガーを取得できる。

Logger インターフェースの使い方

ログレベル

Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.Level;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);

        ch.qos.logback.classic.Logger log = (ch.qos.logback.classic.Logger)logger;
        log.setLevel(Level.TRACE); // ★デフォルトだと trace レベルは出力されないので、出力のレベルを TRACE にしている

        logger.trace("trace message");
        logger.debug("debug message");
        logger.info("info message");
        logger.warn("warn message");
        logger.error("error message");
    }
}
実行結果
11:16:15.220 [main] TRACE sample.logback.Main - trace message
11:16:15.222 [main] DEBUG sample.logback.Main - debug message
11:16:15.222 [main] INFO  sample.logback.Main - info message
11:16:15.222 [main] WARN  sample.logback.Main - warn message
11:16:15.222 [main] ERROR sample.logback.Main - error message
  • trace, debug, info, warn, error の5つのログレベルがある。

パラメータ

Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);

        logger.info("{}",    "HOGE");
        logger.info("{} {}", "HOGE", "FUGA");
        logger.info("{} {}", "HOGE");
        logger.info("{}",    "HOGE", "FUGA");
        logger.info("\\{}",  "HOGE");
        logger.info("{ }",   "HOGE");
    }
}
実行結果
11:16:36.758 [main] INFO  sample.logback.Main - HOGE
11:16:36.762 [main] INFO  sample.logback.Main - HOGE FUGA
11:16:36.762 [main] INFO  sample.logback.Main - HOGE {}
11:16:36.762 [main] INFO  sample.logback.Main - HOGE
11:16:36.762 [main] INFO  sample.logback.Main - {}
11:16:36.762 [main] INFO  sample.logback.Main - { }
  • 第一引数にパラメータ {} を宣言した文字列を渡し、第二引数以降にパラメータに埋め込む値を渡す。
  • すると、 {} の部分に、第二引数以降の値が順番に埋め込まれる。
  • パラメータの数と引数の数が一致しない場合は、数が少ない方に合わせられる(エラーにはならない)。
    • パラメータの方が多い場合は、そのまま {} と出力される(空文字にはならない)。
  • バックスラッシュでエスケープできる。
  • {} の間に文字が入ると埋め込み対象にならなくなる。

スタックトレースの出力

Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);

        try {
            throw new Exception("test exception");
        } catch (Exception e) {
            logger.info("error", e);
        }
    }
}
実行結果
11:16:57.064 [main] INFO  sample.logback.Main - error
java.lang.Exception: test exception
    at sample.logback.Main.main(Main.java:12) ~[bin/:na]
  • 第一引数に文字列、第二引数に例外を渡すと、スタックトレースをログに出力できる。

設定ファイル

コンソールに出力するアペンダーを定義する

フォルダ構成
src/main/
  |-java/
  |  `-sample/logback/
  |    `-Main.java
  `-resources/
     `-logback.xml
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);
        logger.info("Hello Logback!!");
    }
}
実行結果
Hello Logback!!
  • 設定ファイルは、 logback.xml という名前で作成して、クラスパス直下に配置する。
  • <root> タグで、ルートロガーの設定を記述する。
    • <appender-ref> でアペンダー(ログの出力先)を指定する。
  • <appender> タグで、アペンダーを定義する。
    • <encoder> タグの <pattern> タグで、出力のフォーマットを定義する。
    • ch.qos.logback.core.ConsoleAppender クラスを指定することで、コンソールに出力するアペンダーを定義できる。

メッセージのパターンを指定する

変換指定子

メッセージのパターン定義には、 %m のように % で始まる特別なパラメータを定義することができる。

パラメータは、次のような書式になっている。

パラメータの書式
%<変換指定子>{オプション}

変換指定子には、 loggermsg など、出力する内容ごとに決められた値を設定する。

オプションには、変換識別子ごとに固有の設定値を渡す。例えば、日付を出力する date には %date{yyyyMMdd} のようにフォーマットを渡すことができる。
オプションなので、必要でなければ省略できる。

以下に、よく使いそうな変換指定子の使い方をまとめる。
詳細な使い方や、その他の変換指定子については、PatternLayout | 第6章レイアウトを参照のこと。

実装

Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);
        logger.info("Hello Logback!!");
    }
}
変換指定子 設定例 実行結果 説明
c, lo, logger %c sample.logback.Main ロガーの名前を出力する。
d, date %d 2015-10-24 00:36:55,947 日時を出力する。
%d{HH:mm} 00:57 オプションでフォーマットを指定できる。
m, msg, message %m Hello Logback!! ロガーに渡したメッセージを出力する。
n a%n b a<改行> b 実行環境に合わせた改行コードを出力する。
p, le, level %p INFO ログレベルを出力する。
t, thread %t main ログ出力時のスレッド名を出力する。

変換指定子の直後に文字列を出力する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>hoge%nfuga</pattern>
    </encoder>
  </appender>

  ...
</configuration>

改行を表す %n の直後に fuga と出力しようとしている。

しかし、このまま動かすと、 Logback は nfuga という変換指定子が指定されたものと勘違いして、「そんな変換指定子はない!」とエラーになる。

これを回避するには、空のオプションを指定してあげる。

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>hoge%n{}fuga</pattern>
    </encoder>
  </appender>

  ...
</configuration>
実行結果
hoge
fuga

書式修飾子

% と変換指定子の間に、パディングなどの書式修飾子を指定できる。

書式修飾子のフォーマット

%[書式修飾子]<変換指定子>

書式修飾子:
    [最小幅][.最大幅]

最小幅, 最大幅:
    整数
設定例 出力文字列 実行結果 説明
[%5m] "123" [ 123] 最小幅を指定した場合、右寄せして半角スペースでパディング。
"123456" [123456] 桁数を越える場合は、省略されずに出力される。
[%.5m] "123" [123] 最大幅を指定した場合、桁数を超えた分が左から順に省略される。
"123456" [23456]
[%-5] "123" [123 ] 最小幅をマイナスにすると、左寄せになる。
[%.-5] "123456" [12345] 最大幅をマイナスにすると、桁数を超えた分が右から順に省略される。
[%3.5m] "12" [ 12] 最小幅と最大幅を同時に指定することもできる。
"1234" [1234]
"123456" [23456]
[%-3.-5m] "12" [12 ] それぞれマイナスにすることもできる。
"1234" [1234]
"123456" [12345]

グループを作成する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%-7([%level]) : %m%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);
        logger.debug("debug");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");
    }
}
実行結果
[DEBUG] : debug
[INFO]  : info
[WARN]  : warn
[ERROR] : error
  • () で括ると、その部分をグループ化させられる。
  • グループには書式修飾子を指定できる。
  • (, ) を普通の文字として使いたい場合は、バックスラッシュ \ でエスケープする。

変数を定義する

基本

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <!-- ★ property タグで宣言 -->
  <property name="hoge" value="HOGE" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>hoge = ${hoge}%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);
        logger.info("");
    }
}
実行結果
hoge = HOGE
  • <propety> タグを使うことで、変数を定義できる。
  • ${<変数名>} で、変数を参照できる。

システムプロパティの値を参照する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>hoge = ${hoge}%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        System.setProperty("hoge", "Hoge"); // ★システムプロパティを設定

        Logger logger = LoggerFactory.getLogger(Main.class);
        logger.info("");
    }
}
実行結果
hoge = Hoge
  • ${<システムプロパティ名>} で、システムプロパティの値を参照できる。

OS の環境変数を参照する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <property file="./fuga.properties" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>OS = ${OS}%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
実行結果
OS = Windows_NT
  • ${<環境変数名>} で OS の環境変数を参照できる。
  • <property> で宣言された変数 → システムプロパティ → 環境変数の順に検索され、最初に見つかった値が採用される。

変数を別ファイルに定義する

fuga.properties
fuga=FUGA
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <property file="./fuga.properties" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>fuga = ${fuga}%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
実行結果
fuga = FUGA
  • <property> タグの file 属性を指定すれば、別途作成したプロパティファイルを読み込める。
  • file 属性の代わりに resource 属性を指定すれば、クラスパス上のファイルを指定することもできる。

変数のデフォルト値を指定する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>hoge = ${hoge:-default value}%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
実行結果
hoge = default value
  • ${<変数名>:-<デフォルト値>} という形式で、変数が定義されていなかった場合のデフォルト値を指定できる。

変数名のネスト

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <property name="nest" value="hoge" />

  <property name="value.hoge" value="HOGE" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>value.${nest} = ${value.${nest}}%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
実行結果
value.hoge = HOGE
  • ${} は入れ子にできる。
  • ${value.${nest}}${value.hoge} になって HOGE になってる。

設定ファイルを分割する

フォルダ構成
src/main/
  |-java/
  |  `-Main.java
  `resources/
     |-logback.xml
     `-hoge.xml
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <include resource="hoge.xml" />

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
hoge.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<included>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>hoge : %m%n</pattern>
    </encoder>
  </appender>
</included>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);
        logger.info("hello world");
    }
}
実行結果
hoge : hello world
  • <include> タグを使うと、分割した他の設定ファイルを読み込むことができる。
    • クラスパス外のファイルを指定する場合は file 属性でパスを指定する。
    • クラスパス上のファイルを指定する場合は resource 属性で指定する。
  • 読み込まれる側のファイルは、 <included> タグで囲んだ場所に設定を記述する。

ロガー

ロガーの設定を宣言する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <logger name="sampleLogger" />

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger("sampleLogger");

        logger.debug("hello sampleLogger");
    }
}
実行結果
hello sampleLogger
  • <logger> タグを使って sampleLogger というロガーの設定を宣言している。
  • getLogger() メソッドの引数でロガーの名前を渡すことで、指定したロガーを取得できる。

ロガーの出力レベルを指定する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <!-- ★level 属性を指定 -->
  <logger name="sampleLogger" level="info" />

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger("sampleLogger");

        logger.debug("debug");
        logger.info("info");
    }
}
実行結果
info
  • <logger> タグの level 属性で、そのロガーのレベルを指定できる。
  • 指定したレベル以上のログだけが出力されるようになる。

ロガーの親子関係

全てのロガーは、ルートロガーを最上位とした親子関係になっている。

ロガーの名前にドット (.) が含まれる場合、 . が親子関係の区切りを表すことになる。

例えば、 foo.bar.Hoge という名前のロガーは、 foo.bar というロガーの子供ということになる。
また、 foo.bar ロガーは、 foo というロガーの子供になる。
そして、 foo ロガーはルートロガーの子供になる。

logback.jpg

子供のロガーは、親のロガーに設定されているレベルやアペンダーを継承するようになっている。
つまり、子供のロガーで設定を記述しない場合は、デフォルトで親のロガーと同じ設定が適用されることになる。

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <logger name="foo" level="trace" />
  <logger name="foo.bar" level="info" />

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        log("foo");
        log("foo.Fuga");
        log("foo.bar");
        log("foo.bar.Hoge");
    }

    private static void log(String loggerName) {
        Logger logger = LoggerFactory.getLogger(loggerName);

        System.out.println("[" + loggerName + "]");
        logger.trace("trace");
        logger.debug("debug");
        logger.info("info");
        System.out.println();
    }
}
実行結果
[foo]
trace
debug
info

[foo.Fuga]
trace
debug
info

[foo.bar]
info

[foo.bar.Hoge]
info

logback.jpg

  • ルートロガーは、デフォルトでレベルが debug になっている。
  • それを、 foo ロガーで trace に上書きしている。
  • さらに、その設定を foo.bar ロガーでは info に上書きしている。
  • foo ロガーの子供である foo.Fuga ロガーは、 foo ロガーの設定を継承して trace レベルまでログが出力されている。
  • 一方で、 foo.bar.Hoge ロガーは foo.bar ロガーの設定を継承して info レベルのログしか出力されていない。

ロガーの名前

一般的に、ロガーの名前にはそのロガーを使用するクラスの FQCN を使用するのが良いとされている。

そうすることで、パッケージ名がそのロガーの親ロガーということになり、パッケージ単位でロガーの設定を変更する、といった調整が可能になる。

ロガーの名前を FQCN にする場合、文字列で指定するのではなく Class オブジェクトを渡す方が良い。
そうしておけば、クラス名の変更やパッケージの移動が必要になったときでも IDE のリファクタリング機能を使うことで自動でロガー名を変更できるようになる。

ただし、クラス名にしなければならない、というわけではなく、用途に合わせた名称でロガーを宣言しても問題はない。

アペンダーを設定する

アペンダーとは、実際にログを出力するコンポーネントで、ログの出力先(コンソール、ファイル、データベース)やフォーマットなどを指定することができる。

ロガーにアペンダーを設定することで、そのロガーを使ったときのログ出力方法が決定される。

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>STDOUT1 : %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT2" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>STDOUT2 : %msg%n</pattern>
    </encoder>
  </appender>

  <logger name="foo.bar.Hoge">
    <appender-ref ref="STDOUT2" />
  </logger>

  <root>
    <appender-ref ref="STDOUT1" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger("foo.bar.Hoge");

        logger.info("hello appender");
    }
}
実行結果
STDOUT2 : hello appender
STDOUT1 : hello appender
  • <appender> タグを使って、アペンダーを定義できる。
  • <appender> タグには、 nameclass という必須の属性が2つある。
    • name は、そのアペンダーの名前を任意に指定する。
    • class は、アペンダーの具体的な実装クラスを FQCN で指定する。
      • ch.qos.logback.core.ConsoleAppender は Logback が提供しているアペンダーで、コンソールにログを出力するアペンダーになる。
  • ロガーにアペンダーを設定するには、子供要素に <appender-ref> タグを追加する。
    • ref 属性に、設定するアペンダーの name を指定する。

アペンダーの設定は積み重ねられる

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <logger name="foo.bar.Hoge">
    <appender-ref ref="STDOUT" />
  </logger>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

ルートロガーと foo.bar.Hoge ロガーに、それぞれ STDOUT アペンダーを設定している。

この場合、アペンダーの名前が一緒だからルートロガーの STDOUTfoo.bar.HogeSTDOUT で上書きされて結果的に1つのアペンダーが設定されるのかという、そうではない。

Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger("foo.bar.Hoge");

        logger.info("hello appender");
    }
}
実行結果
hello appender
hello appender

アペンダーの設定は積み重ねられるので、 foo.bar.Hoge ロガーはルートロガーで設定された STDOUT と自身に設定された STDOUT に2回ログ出力を指示することになる。
結果、ログは重複して出力される。

アペンダーの積み重ねを止める

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>STDOUT1 : %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT2" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>STDOUT2 : %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT3" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>STDOUT3 : %msg%n</pattern>
    </encoder>
  </appender>

  <!-- ★ additivity に false を設定 -->
  <logger name="foo.bar" additivity="false">
    <appender-ref ref="STDOUT2" />
  </logger>

  <logger name="foo.bar.Hoge">
    <appender-ref ref="STDOUT3" />
  </logger>

  <root>
    <appender-ref ref="STDOUT1" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        log("foo.bar");
        log("foo.bar.Hoge");
    }

    private static void log(String loggerName) {
        Logger logger = LoggerFactory.getLogger(loggerName);

        System.out.println("[" + loggerName + "]");
        logger.info("hello appender");
        System.out.println();
    }
}
実行結果
[foo.bar]
STDOUT2 : hello appender

[foo.bar.Hoge]
STDOUT3 : hello appender
STDOUT2 : hello appender
  • <logger> タグの additivity 属性に false を設定すると、親のロガーに設定されていたアペンダーを継承しなくなる。
  • additivity="false" を設定したロガーの子供は、再び親のアペンダーを継承するようになる。

ファイル出力

基本

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>logback-sample.log</file>
    <encoder>
      <charset>UTF-8</charset>
      <pattern>%m%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="FILE" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Main.class);
        logger.info("hello world");
    }
}
logback-sample.log
hello world

  • ch.qos.logback.core.FileAppender でアペンダーを定義すると、ファイル出力が可能になる。
  • <file> タグで出力ファイルを指定する。
  • ファイルがなければ作成する。
  • ファイルまでのフォルダがなければ、勝手に作成してくれる。
  • 文字コードは <encoder> タグの下に <charset> タグを入れて設定する。

ファイル名にタイムスタンプを入れる

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>

  <timestamp key="time" datePattern="yyyyMMdd_HHmmss" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>logback-sample_${time}.log</file>
    <encoder>
      <pattern>%m%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="FILE" />
  </root>
</configuration>
実行後のフォルダ構成
|-logback-sample_20151024_230826.log
`-src/
logback-sample_20151024_230826.log
hello world

  • <timestamp> タグで実行日時を記録した変数を定義できる。
  • key 属性に他から参照のための名前を。
  • datePattern 属性に日付書式を指定する。

ローテーションさせる

ログファイルをローテーションさせる場合は、アペンダーのクラスに ch.qos.logback.core.rolling.RollingFileAppender を指定する。

時間基準でローテーションさせる

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>

  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logback-sample.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>logback-sample-%d{yyyyMMdd_HHmmss}.log</fileNamePattern>
    </rollingPolicy>

    <encoder>
      <pattern>%m%n</pattern>
    </encoder>
  </appender> 

  <root>
    <appender-ref ref="FILE" />
  </root>
</configuration>

何度かログ出力を実行する。

実行後のフォルダ構成
|-logback-sample.log
|-logback-sample-20151024_232440.log
|-logback-sample-20151024_232459.log
|-logback-sample-20151024_232501.log
`-src/
  • <rollingPolicy> タグに ch.qos.logback.core.rolling.TimeBasedRollingPolicy を指定する。
  • <fileNamePattern> タグで、ローテーション後のファイル名を指定する。
  • 日付部分の書式には、 %d を使用する。
    • 具体的なフォーマットの指定は %d{yyyyMMdd} のように、変換指定子の場合と同じ要領で記述する。
    • オプションを指定しない場合、デフォルトで yyyy-MM-dd という日付書式が使用される。
  • ローテーションは、日付の書式から自動的に推測されて実行される。
    • %d{yyyyMMdd_HHmmss} の場合は秒まで書式が指定されているので、秒が切り替わればローテーションが実行される。
    • %d{yyyy-MM-dd} なら日付が切り替わればローテーションされる。

古いログファイルを自動で削除する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>

  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logback-sample.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>logback-sample-%d{yyyyMMdd_HH}.log</fileNamePattern>
      <maxHistory>3</maxHistory> <!-- ★最大保持件数を設定 -->
    </rollingPolicy>

    <encoder>
      <pattern>%m%n</pattern>
    </encoder>
  </appender> 

  <root>
    <appender-ref ref="FILE" />
  </root>
</configuration>
ログファイル(ログ出力実行前)
2015/10/24  18:00                52 logback-sample-20151024_18.log
2015/10/24  19:00                52 logback-sample-20151024_19.log
2015/10/24  20:00                52 logback-sample-20151024_20.log
2015/10/24  21:00                52 logback-sample-20151024_21.log
2015/10/24  22:00                37 logback-sample.log
ログファイル(ログ出力実行後)
2015/10/24  20:00                52 logback-sample-20151024_20.log
2015/10/24  21:00                52 logback-sample-20151024_21.log
2015/10/24  22:00                37 logback-sample-20151024_22.log
2015/10/24  23:58                37 logback-sample.log
  • <maxHistory> タグで、いくつ前までのログファイルを保持するかを設定できる。
  • 日付書式が %d{yyyyMMdd_HH} で、 maxHistory3 なので、「3時間より前のファイル」は削除されることになる。
    • ログ出力が23時なので、それより3時間前(20時)より前(19時以前)のファイルは全て削除される。

毎日ローテーションさせつつ過去ログは月ごとのフォルダに格納する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>

  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logback-sample.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>%d{yyyyMM,aux}/logback-sample-%d{yyyyMMdd}.log</fileNamePattern>
    </rollingPolicy>

    <encoder>
      <pattern>%m%n</pattern>
    </encoder>
  </appender> 

  <root>
    <appender-ref ref="FILE" />
  </root>
</configuration>
  • 月ごとのフォルダを表す部分に %d{yyyyMM,aux} というふうに aux オプションを指定する。
    • auxauxiliary (補助)の略で、これが設定された %d はファイルローテーションのタイミングとしては識別されなくなる。
    • この場合、 aux が指定されていない %d{yyyyMMdd} の方がファイルローテーションのタイミングとして認識される。

過去ログを圧縮する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>

  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logback-sample.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>logback-sample_%d{yyyyMMdd_HHmmss}.zip</fileNamePattern>
    </rollingPolicy>

    <encoder>
      <pattern>%m%n</pattern>
    </encoder>
  </appender> 

  <root>
    <appender-ref ref="FILE" />
  </root>
</configuration>
  • <fileNamePattern> に指定するファイル名の拡張子を zipgz にすれば、自動的に圧縮してくれる。

メールで送信する

SMTPAppender を使うと、 error レベルのログを出力したタイミングでメールを送信することができる。

試しに GMail を使ってメールを送信する。

build.gradle
dependencies {
    compile 'ch.qos.logback:logback-classic:1.1.3'
    compile 'javax.mail:mail:1.4.7' // ★ Java Mail を追加
}
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <smtpHost>smtp.gmail.com</smtpHost>
    <smtpPort>465</smtpPort>
    <SSL>true</SSL>
    <username>xxxxxxxxxxxxxxxx@gmail.com</username>
    <password>xxxxxxxxxxxxxxxxxxxxx</password>

    <to>yyyyyyyyyyyy@gmail.com</to>
    <from>xxxxxxxxxxxxxxxx@gmail.com</from>
    <subject>Logback SMTPAppender Sample</subject>

    <layout class="ch.qos.logback.classic.PatternLayout">
      <pattern>%m%n</pattern>
    </layout>
  </appender>

  <root>
    <appender-ref ref="EMAIL" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) throws Exception {
        Logger logger = LoggerFactory.getLogger(Main.class);

        for (int i=0; i<256; i++) {
            logger.info("i=" + i);
        }
        logger.error("error!!");

        // ★メールの送信が完了するまで少し待機
        Thread.sleep(5000);
    }
}

実行結果

logback.jpg

  • メール送信を使うには ch.qos.logback.classic.net.SMTPAppender をアペンダーとして指定する。
  • 各設定は以下のような感じ。
設定 説明
<smtpHost> SMTP サーバーのホスト名
<smtpPort> SMTP サーバーのポート番号。デフォルトは 25
<SSL> true を指定すると、 SMTP サーバーに SSL で接続する。
<username> SMTP サーバーの接続に認証が必要な場合のユーザー名。
<password> 同接続用のパスワード。
<to> 送信先のメールアドレス。<to> を複数宣言するか、カンマ , 区切りで複数の宛先を指定可能。
<from> 送信元のメールアドレス。
<subject> メールの件名。 %logger などの変換指定子も指定可能。
  • SMTPAppender に出力されたログは、デフォルトで最大 256 個までキャッシュされる。
  • error レベルでログを出力すると、このキャッシュされたログと error レベルで出力したログの内容がメールで送信される。
  • メールの送信処理は、デフォルトでは非同期で行われる。
    • サンプルでは Thread.sleep() を入れてメールの送信が完了するのを待機している。
    • こうしないと、非同期で行われているメールの送信が完了する前に JVM が終了してしまい、動作の確認ができなかった。

Gmail で送信するときのパスワードについて

二段階認証を有効にしている場合、アプリパスワードを発行する必要がある。

キャッシュするログの量を変更する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <smtpHost>smtp.gmail.com</smtpHost>
    <smtpPort>465</smtpPort>
    <SSL>true</SSL>
    <username>xxxxxxxxxxxxxxxx@gmail.com</username>
    <password>xxxxxxxxxxxxxxxxxxxxx</password>

    <to>yyyyyyyyyyyy@gmail.com</to>
    <from>xxxxxxxxxxxxxxxx@gmail.com</from>
    <subject>Logback SMTPAppender Sample</subject>

    <!-- ★キャッシュサイズを変更 -->
    <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
      <bufferSize>10</bufferSize>
    </cyclicBufferTracker>

    <layout class="ch.qos.logback.classic.PatternLayout">
      <pattern>%m%n</pattern>
    </layout>
  </appender>

  <root>
    <appender-ref ref="EMAIL" />
  </root>
</configuration>

実行結果

logback.jpg

  • <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker"> を追加して、 <bufferSize> タグでキャッシュするログの量を指定できる。

メールの送信を同期処理にする

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <smtpHost>smtp.gmail.com</smtpHost>
    <smtpPort>465</smtpPort>
    <SSL>true</SSL>
    <username>xxxxxxxxxxxxxxxx@gmail.com</username>
    <password>xxxxxxxxxxxxxxxxxxxxx</password>

    <to>yyyyyyyyyyyy@gmail.com</to>
    <from>xxxxxxxxxxxxxxxx@gmail.com</from>
    <subject>Logback SMTPAppender Sample</subject>

    <!-- ★同期処理 -->
    <asynchronousSending>false</asynchronousSending>

    <layout class="ch.qos.logback.classic.PatternLayout">
      <pattern>%m%n</pattern>
    </layout>
  </appender>

  <root>
    <appender-ref ref="EMAIL" />
  </root>
</configuration>
  • <asynchronousSending> タグを追加して false を指定すると、メールの送信が同期処理になる。
  • エラーが発生すると、その直後に JVM を終了させてしまうようなアプリの場合は、メールの送信を同期にしておく必要がある。

フィルター

アペンダーにフィルターを設定することで、特定の条件に一致したログだけを出力できるようになる。

特定のログレベルだけを出力させる(させない)

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="DENY_INFO" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>INFO</level>
      <onMatch>DENY</onMatch>
    </filter>
    <encoder>
      <pattern>%level %n</pattern>
    </encoder>
  </appender>

  <appender name="ACCEPT_DEBUG" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>DEBUG</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
    <encoder>
      <pattern>%level %n</pattern>
    </encoder>
  </appender>

  <logger name="accept.debug">
    <appender-ref ref="ACCEPT_DEBUG" />
  </logger>

  <logger name="deny.info">
    <appender-ref ref="DENY_INFO" />
  </logger>

  <root level="trace">
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) throws Exception {
        log("accept.debug");
        log("deny.info");
    }

    private static void log(String loggerName) {
        Logger logger = LoggerFactory.getLogger(loggerName);

        System.out.println("[" + loggerName + "]");
        logger.trace("");
        logger.debug("");
        logger.info("");
        logger.warn("");
        logger.error("");
        System.out.println();
    }
}
実行結果
[accept.debug]
DEBUG 

[deny.info]
TRACE 
DEBUG 
WARN 
ERROR
  • <filter> タグを追加し、 classch.qos.logback.classic.filter.LevelFilter を設定する。
  • <level> タグに、対象のログレベルを指定する。
  • <onMatch> および <onMismatch> タグに、ログレベルがマッチした場合にどうするかを指定する。
    • DENY を指定すると、出力は完全に中断される(他のフィルタの処理はスキップされる)。
    • ACCEPT を指定すると、出力が許可される(他のフィルタの処理はスキップされる)。
    • NEUTRAL を指定すると、現在のフィルタはスキップされ次のフィルタに処理が送られる。

あるログレベルより低いログレベルを出力させないようにする

loglevel.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>WARN</level>
    </filter>
    <encoder>
      <pattern>%level %n</pattern>
    </encoder>
  </appender>

  <root level="trace">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) throws Exception {
        Logger logger = LoggerFactory.getLogger(Main.class);

        logger.trace("");
        logger.debug("");
        logger.info("");
        logger.warn("");
        logger.error("");
    }
}
実行結果
WARN 
ERROR 
  • ch.qos.logback.classic.filter.ThresholdFilter をフィルターに指定することで、 <level> で指定したログより低いレベルのログ出力を抑制できる。

特定の文字列が含まれるログだけを出力する

build.gradle
dependencies {
    compile 'ch.qos.logback:logback-classic:1.1.3'
    compile 'janino:janino:2.5.10' // ★追加
}
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
      <evaluator>
        <matcher>
          <name>hogeMatcher</name>
          <regex>hoge</regex>
        </matcher>

        <expression>hogeMatcher.matches(formattedMessage)</expression>
      </evaluator>

      <OnMismatch>DENY</OnMismatch>
    </filter>

    <encoder>
      <pattern>%m%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) throws Exception {
        Logger logger = LoggerFactory.getLogger(Main.class);

        logger.info("hoge");
        logger.info("fuga");
        logger.info("piyo");
        logger.info("hoge fuga");
        logger.info("hoge piyo");
    }
}
実行結果
hoge
hoge fuga
hoge piyo
  • 依存関係に janino:janino:2.5.10 を追加する。
  • <filter>ch.qos.logback.core.filter.EvaluatorFilter を設定する。
  • <evaluator> タグを追加し、 <matcher> タグで文字列を検証するための Matcher を定義する。
    • <name> 属性でその Matcher の名前を、 <regex> タグでマッチの条件となる正規表現を定義する。
    • <expression> タグで、 Matcher を使った値の検証ロジックを記述する。
      • Matcher を使わなくても、評価結果が boolean になるのであれば、任意の Java コードを記述することができる。
    • formattedMessage<expression> タグ中で参照可能な暗黙の変数で、最終的に出力されようとしている文字列が格納されている。
  • hoge という文字列が含まれているメッセージのみがログ出力されている。

<expression> タグ中で参照できる暗黙の変数(一部)

変数名 説明
message String ロガーに渡されたメッセージ。パラメータ({})もそのままの形で渡される。
formattedMessage String 最終的に出力されようとしている文字列。
logger String ロガーの名前。
level int ログレベルを表す整数値。
DEBUG int debug のログレベルを表す整数値。
INFO int info のログレベルを表す整数値。
WARN int warn のログレベルを表す整数値。
ERROR int error のログレベルを表す整数値。
marker Marker ログ出力のときに指定されたマーカーオブジェクト。
throwable Throwable ログ出力のときに渡された例外オブジェクト。

より詳細な情報は JaninoEventEvaluator | 第7章フィルター を参照のこと。

フィルターを自作する

MyFilter.java
package sample.logback;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class MyFilter extends Filter<ILoggingEvent> {

    private String value;

    @Override
    public FilterReply decide(ILoggingEvent event) {
        if (event.getMessage().contains(this.value)) {
            return FilterReply.ACCEPT;
        } else {
            return FilterReply.DENY;
        }
    }

    public void setValue(String value) {
        this.value = value;
    }
}
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="sample.logback.MyFilter">
      <value>hoge</value>
    </filter>

    <encoder>
      <pattern>%m%n</pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>
Main.java
package sample.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

    public static void main(String[] args) throws Exception {
        Logger logger = LoggerFactory.getLogger(Main.class);

        logger.info("a hoge");
        logger.info("Hoge");
        logger.info("hoge b");
        logger.info("hoGe");
    }
}
実行結果
a hoge
hoge b
  • Filter クラスを継承することで、任意のフィルターを自作することができる。
  • decide() メソッドをオーバーライドして、フィルタリングの定義を実装する。
    • FilterReply.ACCEPT を返せば、後続のフィルターを飛ばして出力を許可する。
    • FilterReply.DENY を返せば、後続のフィルターを飛ばして出力を拒否する。
    • FilterReply.NEUTRAL を返せば、後続のフィルターに処理を続けさせる。
  • setter を定義することで、任意のオプションを <filter> タグの子要素として指定できるようになる。

設定例

info 以上のログをコンソールとファイルに出力する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <property name="format" value="[%-5level] %date %-15logger{15} - %m%n" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>sample.log</file>
    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <root level="info">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="FILE" />
  </root>
</configuration>

ファイル出力は特定のパッケージ以下だけ

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <property name="format" value="[%-5level] %date %-15logger{15} - %m%n" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>sample.log</file>
    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <logger name="sample">
    <appender-ref ref="FILE" />
  </logger>

  <root level="info">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>

ログファイルのローテーションを設定

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <property name="format" value="[%-5level] %date %-15logger{15} - %m%n" />

  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>log/sample.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>log/%d{yyyyMM,aux}/sample-%d{yyyyMMdd}.log</fileNamePattern>
      <maxHistory>90</maxHistory>
    </rollingPolicy>

    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <logger name="sample">
    <appender-ref ref="FILE" />
  </logger>

  <root level="info">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>
  • log フォルダの下に月ごとのフォルダを作り、その下に過去ログを格納。
  • 最大3ヶ月(90日)分のログを保持しておく。

環境変数 LOG_LEVEL に合わせて出力のログレベルを切り替える

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <property name="format" value="[%-5level] %date %-15logger{15} - %m%n" />

  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>log/sample.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>log/%d{yyyyMM,aux}/sample-%d{yyyyMMdd}.log</fileNamePattern>
      <maxHistory>90</maxHistory>
    </rollingPolicy>

    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <logger name="sample">
    <appender-ref ref="FILE" />
  </logger>

  <root level="${LOG_LEVEL:-info}">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>
  • 未指定の場合は info レベルで出力。

ERROR レベルの出力があったらメールを送信する

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
  <property name="format" value="[%-5level] %date %-15logger{15} - %m%n" />

  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <smtpHost>smtp.gmail.com</smtpHost>
    <smtpPort>465</smtpPort>
    <SSL>true</SSL>
    <username>xxxxx@gmail.com</username>
    <password>xxxxx</password>

    <to>xxxxx@gmail.com</to>
    <from>xxxxx@gmail.com</from>
    <subject>[System Error] %date{yyyy-MM-dd HH:mm:ss} - %m</subject>

    <asynchronousSending>false</asynchronousSending>

    <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
      <bufferSize>50</bufferSize>
    </cyclicBufferTracker>

    <layout class="ch.qos.logback.classic.PatternLayout">
      <pattern>${format}</pattern>
    </layout>
  </appender>

  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>log/sample.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>log/%d{yyyyMM,aux}/sample-%d{yyyyMMdd}.log</fileNamePattern>
      <maxHistory>90</maxHistory>
    </rollingPolicy>

    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${format}</pattern>
    </encoder>
  </appender>

  <logger name="sample">
    <appender-ref ref="FILE" />
  </logger>

  <root level="${LOG_LEVEL:-info}">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="EMAIL" />
  </root>
</configuration>
  • メール送信は、念のため同期処理で実行。

eclipse での logback.xml の警告表示を無くす

eclipse でスキーマ定義のない xml ファイルを作ると、黄色く警告アイコンが表示されて鬱陶しい。

これを回避するには、先頭に <!DOCTYPE logback> と入れてあげるといいらしい。

参考: logbackへ移行するの巻 - R42日記

logback.xml
  <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE logback>
  <configuration>
    ...
  </configuration>

参考