logback機能,設定まとめ

# 概要

logbackの特徴や機能のまとめ記事です。
前半はサンプルアプリケーションを使ったコードや設定方法の説明になります。
後半は参考にさせて頂いたサイトの要点をまとめたリファレンス的な内容になります。

**環境**

下記の環境でサンプルアプリケーションの動作を確認しました。

* Java 1.8.0_45
* logback 1.1.3
* slf4j 1.7.7


## サンプルアプリケーション

mavenで雛形を作成しました。

```bat
> mvn archetype:generate -DgroupId=com.example.lbsample -DartifactId=lbsample -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
```

**編集後のpom.xml**

```xml:pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example.lbsample</groupId>
  <artifactId>lbsample</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>lbsample</name>
  <url>http://maven.apache.org</url>

  <properties>
    <java.version>1.8</java.version>
    <logback.version>1.1.3</logback.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>${logback.version}</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <verbose>true</verbose>
          <source>${java.version}</source>
          <target>${java.version}</target>
          <encoding>${project.build.sourceEncoding}</encoding>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
```

**作成したlogback.xml**

```xml.logback.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="true">

  <!--
    変数の定義を行います。
    2行目は外部のプロパティファイルの内容から定義します。
  -->
  <property name="LOG_DIR" value="D:/logs" />
  <property file="src/main/resources/variables1.properties" />

  <turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
    <Marker>com.example.sample.animal.Cat</Marker>
    <OnMatch>ACCEPT</OnMatch>
  </turboFilter>

  <!--
     標準出力に出力する設定です。
  -->
  <appender name="STDOUT_A" class="ch.qos.logback.core.ConsoleAppender">
    <target>System.out</target>
    <encoder>
      <pattern>A: %-5r %d{yyyy-MM-dd HH:mm:ss} [%t] %highlight(%-5le) %cyan(%-40.40lo{36}) - %green(%msg) %n</pattern>
    </encoder>
    <withJasi>true</withJasi>
  </appender>

  <!--
     標準出力に出力する設定です。
  -->
  <appender name="STDOUT_B" class="ch.qos.logback.core.ConsoleAppender">
    <target>System.out</target>
    <encoder>
      <pattern>B: %-5r %d{yyyy-MM-dd HH:mm:ss} [%t] %highlight(%-5le) %yellow(%-40.40lo{36}) - %green(%msg) %n</pattern>
    </encoder>
    <withJasi>true</withJasi>
  </appender>

  <!--
    標準エラーに出力する設定です。
  -->
  <appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
    <target>System.err</target>
    <encoder>
      <pattern>E: %-5r %d{yyyy-MM-dd HH:mm:ss} [%t] %highlight(%-5le) %red(%-40.40lo{36}) - %red(%msg) %n</pattern>
    </encoder>
    <withJasi>true</withJasi>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>ERROR</level>
    </filter>
  </appender>

  <!--
    ログファイルを出力するシンプルな設定です。
  -->
  <appender name="FILE_A" class="ch.qos.logback.core.FileAppender">
    <file>${LOG_DIR}/lbsample_a.log</file>
    <encoder>
      <pattern>%-5r %d{yyyyMMdd HH:mm:ss.SSS} [%t] %-5le %lo{36} [%file:%line] - %msg %n</pattern>
    </encoder>
  </appender>

  <!--
    ログファイルを出力するシンプルな設定です。
    ファイル名やパターンの設定をプロパティファイルから取得した変数で行います。
  -->
  <appender name="FILE_B" class="ch.qos.logback.core.FileAppender">
    <file>${file_b.log_dir:-D:/logs}${file_b.log_file}</file>
    <encoder>
      <pattern>${file_b.pattern}</pattern>
    </encoder>
  </appender>

  <!--
    ログファイルをアーカイブする設定です。
    アーカイブは1分毎に行います。（テストのため）
  -->
  <appender name="ROLLING_A" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_DIR}/roll_a_lbsample.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${LOG_DIR}/rolling_lbsample_%d{yyyy-MM-dd_HH-mm}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>
    <encoder>
      <pattern>%-5r %d{yyyyMMdd HH:mm:ss.SSS} [%t] %-5le %lo{35} - %msg %n</pattern>
    </encoder>
  </appender>

  <!--
     ログファイルをアーカイブする設定です。
     アーカイブファイルは月別のディレクトリに作成します。
  -->
  <appender name="ROLLING_B" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_DIR}/roll_b_lbsample.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${LOG_DIR}/%d{yyyy-MM-dd,aux}/rolling2_lbsample_%d{yyyy-MM-dd_HH-mm}.log</fileNamePattern>
    </rollingPolicy>
    <encoder>
      <pattern>%-5r %d{yyyyMMdd HH:mm:ss.SSS} [%t] %-5le %lo{35} - %msg %n</pattern>
    </encoder>
  </appender>

  <!--
    ログファイルをアーカイブする設定です。
    ファイルサイズが5KB(テストのため）に達するとアーカイブします。
  -->
  <appender name="ROLLING_C" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_DIR}/roll_c_${${DEP}.${PRI}}.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>roll_c_${LOG_DIR}/${${DEP}.${PRI}}_%i.log</fileNamePattern>
        <minIndex>15</minIndex>
        <maxIndex>19</maxIndex>
    </rollingPolicy>
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5KB</maxFileSize>
    </triggeringPolicy>
    <encoder>
      <pattern>%-5r %d{yyyyMMdd HH:mm:ss.SSS} [%t] %-5le %lo{36} - %msg %n</pattern>
    </encoder>
  </appender>

  <!--
    ログファイルをアーカイブする設定です。
    時間とファイルサイズでアーカイブします。
  -->
  <appender name="ROLLING_D" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_DIR}/roll_d_lbsample.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${LOG_DIR}/roll_d_%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
      <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>5KB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
      <pattern>%-5r %d{yyyyMMdd HH:mm:ss.SSS} [%t] %-5le %lo{36} - %msg %n</pattern>
    </encoder>
  </appender>

  <logger name="com.example.sample.animal.dog" level="DEBUG" additivity="false">
    <appender-ref ref="STDOUT_B"/>
  </logger>

  <logger name="com.example.sample.animal" level="WARN">
    <appender-ref ref="STDERR"/>
  </logger>

  <logger name="com.example.sample.fruits" level="INFO">
    <appender-ref ref="STDERR"/>
  </logger>

  <!--
    上記のロガーの祖先ロガーです。
  -->
  <logger name="com.example.sample" level="DEBUG">
    <appender-ref ref="STDOUT_A"/>
  </logger>

  <root level="DEBUG">
    <appender-ref ref="FILE_A" />
    <appender-ref ref="FILE_B" />
    <appender-ref ref="ROLLING_A"/>
    <appender-ref ref="ROLLING_B"/>
    <appender-ref ref="ROLLING_C"/>
    <appender-ref ref="ROLLING_D"/>
  </root>

</configuration>
```

**作成したプロパティファイル**

```properties:variables1.prpperties
# FILE_B
file_b.log_dir = D:/logs
file_b.log_file = /lbsample_b.log
file_b.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5le %lo{36} [%file:%line] - %msg%n

DEP = CUSTOMER
PRI = REGULAR

CUSTOMER.REGULAR = cust_r
CUSTOMER.IRREGULAR = cust_i
CUSTOMER.EMERGENCY = cust_e
SALES.REGULAR = sale_r
SALES.IRREGULAR = sale_i
SALES.EMERGENCY = sale_e
PERSONNEL.REGULAR = pers_r
PERSONNEL.IRREGULAR = pers_i
PERSONNEL.EMERGENCY = pers_e
```

**アプリケーションのディレクトリツリー**

```text
lbsample
 ├─src
 │  ├─main
 │  │  ├─java
 │  │  │  └─com
 │  │  │      └─example
 │  │  │          ├─lbsample
 │  │  │          │   └─App.java
 │  │  │          └─sample
 │  │  │              ├─Main.java
 │  │  │              ├─animal
 │  │  │              │  ├─cat
 │  │  │              │  │  └─Mike.java
 │  │  │              │  └─dog
 │  │  │              │     └─Shiba.java
 │  │  │              └─fruits
 │  │  │                  ├─Budou.java
 │  │  │                  └─budou
 │  │  │                     └─Kyohou.java
 │  │  └─resources
 │  └─test
```

### サンプルコードとログの出力結果

サンプルコードのimport文は省略しています。

**ロガー：com.example.sample**

このロガーは他のロガー(root以外)の祖先ロガーになります。

```xml
<logger name="com.example.sample" level="DEBUG">
  <appender-ref ref="STDOUT_A"/>
</logger>
```

```java:Main.java
package com.example.sample;

public class Main {
  private static final Logger logger = LoggerFactory.getLogger(Main.class);
  public void doExec() {
    logger.debug("Main debug");
    logger.info("Main info current:{}", new Date());
    logger.warn("Main warn");
    logger.error("Main error");
    Budou.doExec();
    Cat.doExec();
    Dog.doExec();
  }
}
```

|logger name                      |level   |STDOUT_A |STDOUT_B |STRERR   |
|:--------------------------------|:------:|:-------:|:-------:|:-------:|
|com.example.sample               |DEBUG   |    ○    |         |         |
|                                 |INFO    |    ○    |         |         |
|                                 |WARN    |    ○    |         |         |
|                                 |ERROR   |    ○    |         |         |


**ロガー：com.example.sample.fruits**

このロガーのアペンダーは`STDERR`ですが、祖先のロガーのアペンダーも引き継いでいるので`STDOUT_A`へも出力します。

```xml
<logger name="com.example.sample.fruits" level="INFO">
  <appender-ref ref="STDERR"/>
</logger>
```

```java:Budou.java
package com.example.sample.fruits;

public class Budou {
  private static final Logger logger = LoggerFactory.getLogger(Budou.class);
  public static void doExec() {
    logger.debug("Budou debug");
    logger.info("Budou info current:{}", new Date());
    logger.warn("Budou warn");
    logger.error("Budou error");
    Kyohou.doExec();
  }
}
```

```java:Kyohou.java
package com.example.sample.fruits.budou;

public class Kyohou {
  private static final Logger logger = LoggerFactory.getLogger(Kyohou.class);
  public static void doExec() {
    logger.debug("Budou.Kyohou debug");
    logger.info("Budou.Kyohou info current:{}", new Date());
    logger.warn("Budou.Kyohou warn");
    logger.error("Budou.Kyohou error");
  }
}
```

|logger name                      |level   |STDOUT_A |STDOUT_B |STRERR   |
|:--------------------------------|:------:|:-------:|:-------:|:-------:|
|com.example.sample.fruits        |DEBUG   |         |         |         |
|                                 |INFO    |    ○    |         |         |
|                                 |WARN    |    ○    |         |         |
|                                 |ERROR   |    ○    |         |    ○    |
|com.example.sample.fruits.budou  |DEBUG   |         |         |         |
|                                 |INFO    |    ○    |         |         |
|                                 |WARN    |    ○    |         |         |
|                                 |ERROR   |    ○    |         |    ○    |


**ロガー：com.example.sample.animal**

このロガーのアペンダーは`STDERR`ですが、祖先のロガーのアペンダーも引き継いでいるので`STDOUT_A`へも出力します。

```xml
<logger name="com.example.sample.animal" level="WARN">
  <appender-ref ref="STDERR"/>
</logger>
```

また、ログレベルが`WARN`に設定されていますが、下記のMarkerFilterにマッチするログはログレベルに関係なく出力されます。

```xml
<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
  <Marker>com.example.sample.animal.Cat</Marker>
  <OnMatch>ACCEPT</OnMatch>
</turboFilter>
```

```java:Cat.java
package com.example.sample.animal;

public class Cat {
  private static final Logger logger = LoggerFactory.getLogger(Cat.class);
  private static final Marker marker = MarkerFactory.getMarker(Cat.class.getCanonicalName());
  public static void doExec() {
    logger.debug("Cat debug");
    logger.info("Cat info current:{}", new Date());
    logger.warn("Cat warn");
    logger.error("Cat error");
    logger.info(marker, "marker:{}", marker.getName());
    Mike.doExec();
  }
}
```

```java:Dog.java
package com.example.sample.animal;

public class Dog {
  private static final Logger logger = LoggerFactory.getLogger(Dog.class);
  private static final Marker marker = MarkerFactory.getMarker(Dog.class.getCanonicalName());
  public static void doExec() {
    logger.debug("Dog debug");
    logger.info("Dog info current:{}", new Date());
    logger.warn("Dog warn");
    logger.error("Dog error");
    logger.info(marker, "marker:{}", marker.getName());
    Shiba.doExec();
  }
}
```

```java:Mike.java
package com.example.sample.animal.cat;

public class Mike {
  private static final Logger logger = LoggerFactory.getLogger(Mike.class);
  public static void doExec() {
    logger.debug("Cat.Mike debug");
    logger.info("Cat.Mike info current:{}", new Date());
    logger.warn("Cat.Mike warn");
    logger.error("Cat.Mike error");
  }
}
```

|logger name                      |level   |STDOUT_A |STDOUT_B |STRERR   |
|:--------------------------------|:------:|:-------:|:-------:|:-------:|
|com.example.sample.animal        |DEBUG   |         |         |         |
|                                 |INFO    |    △   |         |         |
|                                 |WARN    |    ○    |         |         |
|                                 |ERROR   |    ○    |         |    ○    |
|com.example.sample.animal.cat    |DEBUG   |         |         |         |
|                                 |INFO    |         |         |         |
|                                 |WARN    |    ○    |         |         |
|                                 |ERROR   |    ○    |         |    ○    |


**ロガー：com.example.sample.animal.dog**

このロガーのアペンダー`STDOUT_B`に出力されますが、`additivity=false`を指定しているので祖先のロガー(STDOUT_A)には出力されません。
この指定を外すと祖先のロガーにも出力されるようになります。

```xml
<logger name="com.example.sample.animal.dog" level="DEBUG" additivity="false">
  <appender-ref ref="STDOUT_B"/>
</logger>
```

```java:Shiba.java
package com.example.sample.animal.dog;

public class Shiba {
  private static final Logger logger = LoggerFactory.getLogger(Shiba.class);
  public static void doExec() {
    logger.debug("Dog.Shiba debug");
    logger.info("Dog.Shiba info current:{}", new Date());
    logger.warn("Dog.Shiba warn");
    logger.error("Dog.Shiba error");
  }
}
```

|logger name                      |level   |STDOUT_A |STDOUT_B |STRERR   |
|:--------------------------------|:------:|:-------:|:-------:|:-------:|
|com.example.sample.animal.dog    |DEBUG   |         |    ○    |         |
|                                 |INFO    |         |    ○    |         |
|                                 |WARN    |         |    ○    |         |
|                                 |ERROR   |         |    ○    |         |


## logback仕様まとめ

**参考**

下記のサイトの内容を参考にさせて頂きました。

LOGBack

* [LOGBack] (http://logback.qos.ch/)
* [Logback マニュアル] (http://logback.qos.ch/manual/index_ja.html)

Qiita

* [Logbackでファイルにログを吐く時の基本設定] (http://qiita.com/joe_hrmn/items/356f1e2b05cb90241414)
* [SLF4J/LogbackでJSON形式のログ出力] (http://qiita.com/ephemeralsnow/items/10d362286aaa55120822)

### appender

* name属性(必須)。アペンダーの名前を指定します。
* class属性(必須)。アペンダークラスの完全名を指定します。
* appenderには任意の数のlayout、encoder、filterを含めることができます。

**appenderは次のようなものがあります**

* ConsoleAppender
* FileAppender
* RollingFileAppender

#### ConsoleAppender

FQCN:`ch.qos.logback.core.ConsoleAppender`
API: [Class ConsoleAppender<E>] (http://logback.qos.ch/apidocs/ch/qos/logback/core/ConsoleAppender.html)

ログをコンソール(System.outかSystem.err)に出力します。

|property name       |type             |Description                                       |
|:-------------------|:----------------|:-------------------------------------------------|
|`encoder`           |Encoder          |default `PatternLayoutEncoder`.                   |
|`target`            |String           |default `System.out`. `System.out` or `System.err`|
|`withJasi`          |boolean          |default `false`.                                  |

```xml:ConsoleAppender
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{35} - %msg %n</pattern>
  </encoder>
  <target>System.out</target>
  <withJasi>false</withJasi>
</appender>
```

#### FileAppender

FQCN:`ch.qos.logback.core.FileAppender`
API: [Class FileAppender<E>] (http://logback.qos.ch/apidocs/ch/qos/logback/core/FileAppender.html)

ログをファイルに出力します。

|property name       |type             |Description                                       |
|:-------------------|:----------------|:-------------------------------------------------|
|`file`              |String           |出力先のファイル名.                                 |
|`append`            |boolean          |default `true`.trueは既存ファイルに追記します.      |
|`encoder`           |Encoder          |default `PatternLayoutEncoder`.                   |
|`prudent`           |boolean          |default `false`.                                  |

```xml:FileAppender
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
  <file>app.log</file>
  <append>true</append>
  <encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5le [%t] %lo{36} - %msg %n</pattern>
  </encoder>
  <prudent>false</prudent>
</appender>
```

#### RollingFileAppender

FQCN:`ch.qos.logback.core.rolling.RollingFileAppender`
API: [Class RollingFileAppender<E>] (http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/RollingFileAppender.html)

ログをファイルに出力します。指定した条件でファイルをアーカイブできます。
アーカイブの条件を`rollingPolicy`と`triggeringPolicy`で指定します。

|property name       |type             |Description                                       |
|:-------------------|:----------------|:-------------------------------------------------|
|`file`              |String           |出力先のファイル名.                                 |
|`append`            |boolean          |default `true`. trueは既存ファイルに追記します.      |
|`encoder`           |Encoder          |default `PatternLayoutEncoder`.                    |
|`rollingPolicy`     |RollingPolicy    |RollingPolicyインターフェースを実装したクラス.        |
|`triggeringPolicy`  |TriggeringPolicy |TriggeringPolicyインターフェースを実装したクラス.     |
|`prudent`           |boolean          |default `false`.                                   |

##### RollingPolicy

**RollingPolicyは次のようなものがあります**

* TimeBasedRollingPolicy
* FixedWindowRollingPolicy

###### TimeBasedRollingPolicy

FQCN:`ch.qos.logback.core.rolling.TimeBasedRollingPolicy`
API: [Class TimeBasedRollingPolicy<E>] (http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/TimeBasedRollingPolicy.html)

* 時間ベースでアーカイブを行います。アーカイブするタイミングは%dで指定します。
* RollingPolicyとTriggeringPolicyを実装しています。
* パターンに%dを含める必要があります。

|property name        |type             |Description                                       |
|:--------------------|:----------------|:-------------------------------------------------|
|`fileNamePattern`    |String           |アーカイブファイル名. %dを含める必要があります.       |
|`maxHistory`         |int              |オプションです.保存するアーカイブファイルの数を指定します. この数値を超えるファイルは削除します.|
|`cleanHistoryOnStart`|boolean          |default `false`.    |

アーカイブするタイミングは%dで指定します。

|pattern                             |Description                                 |
|:-----------------------------------|:-------------------------------------------|
|`%d`                                |default pattern of yyyy-MM-dd.              |
|`%d{yyyy-MM}`                       |月初めにアーカイブします.                     |
|`%d{yyyy-ww}`                       |週初めにアーカイブします. 週初めが日曜の場合は日曜日にアーカイブします. |
|`%d{yyyy-MM-dd_HH-mm}`              |1分ごとにアーカイブします.                    |
|`%d{yyyy-MM-dd_HH-mm, Asia/Tokyo}`  |同上です. 引数にタイムゾーンを指定できます.     |
|`%d{yyyy-MM,aux}/%d`                |年月ディレクトリ(yyyy-MM)へ日ごとにアーカイブします.|

```xml:TimeBasedRollingPolicy
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>app.log</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>app.%d{yyyy-MM-dd}.log</fileNamePattern>
    <maxHistory>30</maxHistory>
  </rollingPolicy>
  <encoder>
    <pattern>%-5r %d [%t] %-5le %lo{36} - %msg %n</pattern>
  </encoder>
</appender>
```

**aux**

1つ目の%dの引数にauxを指定するとそのパターンでアーカイブ先のディレクトを作成します。アーカイブするタイミングは2つ目の%dで指定します。

```xml:aux
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  <fileNamePattern>/var/logs/%d{yyyy-MM-dd,aux}/app_access_%d{yyyy-MM-dd_HH}.log</fileNamePattern>
</rollingPolicy>
```

この例では、/var/logs以下に`yyyy-MM-dd`パターンでディレクトリを作成し、そのディレクトリへ1時間ごとにログファイルをアーカイブします。

```text:image
/var/logs
      |
      +--- /2015-06-20
      |          |
      |          +--- app_access_2015-06-20_00.log
      |          +--- app_access_2015-06-20_01.log
      |          |
      |          +--- app_access_2015-06-20_23.log
      |
      +--- /2015/06/21
      |          |
      |          +--- app_access_2015-06-21_00.log
      |          +--- app_access_2015-06-21_01.log
```

###### SizeAndTimeBasedFNATP

FQCN:`ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP`
API: [Class SizeAndTimeBasedFNATP<E>] (http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/SizeAndTimeBasedFNATP.html)

時間とサイズでアーカイブを行います。
アーカイブする時間が来る前に指定サイズに達した場合は連番を付けてアーカイブを行います。

* TimeBasedRollingPolicyのサブコンポーネントです。
* パターンに%dと%iを含める必要があります。
* %iは0から始まります。

|property name       |type             |Description                                       |
|:-------------------|:----------------|:-------------------------------------------------|
|maxFileSize         |String           |ファイルサイズの上限を指定します.                    |

```xml:SizeAndTimeBasedFNATP
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>app.log</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>app-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      <maxFileSize>100MB</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
  </rollingPolicy>
  <encoder>
    <pattern>%-5r %d [%t] %-5le %lo{36} - %msg %n</pattern>
  </encoder>
</appender>
```

###### FixedWindowRollingPolicy

FQCN:`ch.qos.logback.core.rolling.FixedWindowRollingPolicy`
API: [Class FixedWindowRollingPolicy] (http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/FixedWindowRollingPolicy.html)

ファイルにインデックスを付けてアーカイブします。
インデックスの範囲でローテーションを行います。

* RollingPolicyを実装しています。
* TriggeringPolicyと併用します。
* パターンに%iを含める必要があります。
* %iの出力結果はminIdexからmaxIndexの範囲になります。

|property name       |type             |Description                                       |
|:-------------------|:----------------|:-------------------------------------------------|
|`minIndex`          |int              |インデックスの最小値を指定します.                    |
|`maxIndex`          |int              |インデックスの最大値を指定します.                    |
|`fileNamePattern`   |String           |アーカイブファイル名. %iを含める必要があります.       |

```xml:FixedWindowRollingPolicy
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>app.log</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
    <fileNamePattern>app.%i.log</fileNamePattern>
    <minIndex>1</minIndex>
    <maxIndex>3</maxIndex>
  </rollingPolicy>
  <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
    <maxFileSize>5MB</maxFileSize>
  </triggeringPolicy>
  <encoder>
    <pattern>%-5r %d [%t] %-5le %lo{36} - %msg %n</pattern>
  </encoder>
</appender>
```

この例ではアーカイブは下記の3ファイルをローテーションします。

* app.1.log
* app.2.log
* app.3.log

##### TriggeringPolicy

**TriggeringPolicyは次のようなものがあります**

* TimeBasedRollingPolicy
* SizeBasedTriggeringPolicy

###### TimeBasedRollingPolicy

時間ベースでアーカイブするタイミングを通知します。
(RollingFileAppenderで説明済みです。)

###### SizeBasedTriggeringPolicy

FQCN:`ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy`
API: [Class SizeBasedTriggeringPolicy<E>] (http://logback.qos.ch/apidocs/ch/qos/logback/core/rolling/SizeBasedTriggeringPolicy.html)

ファイルサイズベースでアーカイブするタイミングを通知します。
(FixedWindowRollingPolicyで説明済みです。)

|property name       |type             |Description                                       |
|:-------------------|:----------------|:-------------------------------------------------|
|`maxFileSize`       |String           |ファイルサイズの上限を指定します.                    |

### layout

通常はlayoutを直接使用することはありません。layoutの機能はencoderが代わりに行います。
patternに、変換パターン文字列と呼ぶメッセージフォーマットを指定します。変換パターン文字列は文字列リテラル、変換指定子、書式修飾子などで構成されます。

#### PatternLayout

FQCN:`ch.qos.logback.classic.PatternLayout`
API: [Class PatternLayout] (http://logback.qos.ch/apidocs/ch/qos/logback/classic/PatternLayout.html)

これは古いバージョンでの記述方法です。

```xml:PatternLayout
<layout>
  <pattern>%-5r %d{yyyyMMdd HH:mm:ss.SSS} [%t] %-5le %lo{36} [%file:%line] - %msg %n</pattern>
</layout>
```

現在のバージョンではencoderを使用します。
encoderはデフォルトで`PatternLayoutEncoder`を使用します。

```xml:encoder
<encoder>
  <pattern>%-5r %d{yyyyMMdd HH:mm:ss.SSS} [%t] %-5le %lo{36} [%file:%line] - %msg %n</pattern>
</encoder>
```

##### 変換指定子

|変換指定子       |短縮名     |オプション|出力                        |速度|
|:---------------|:----------|:--------|:---------------------------|:--|
|`logger`        |`lo`, `c`  |`length` |ロガーの名前                 |   |
|`level`         |`le`, `p`  |         |ログレベル                  |   |
|`thread`        |`t`        |         |スレッド                    |   |
|`date`          |`d         |`pattern`|ログの出力日時               |   |
|`message`       |`msg`, `m` |         |ログメッセージ               |   |
|`n`             |           |         |改行コード                   |   |
|                |           |         |                            |   |
|`contextName`   |`cn`       |         |ロギングコンテキスト名        |   |
|`marker`        |           |         |マーカーの名前               |   |
|                |           |         |                            |   |
|`relative`      |`r`        |         |経過時間(ミリ秒)             |   |
|`property`      |           |`key`    |プロパティ                   |   |
|`replace(p)`    |           |`r`, `t` |置換後の文字列               |   |
|                |           |         |                            |   |
|`caller`        |           |`depth`  |位置情報                     |   |
|`file`          |`F`        |         |クラスのソースコードファイル名 |低速|
|`line`          |`L`        |         |ソースコードファイル中の行番号 |低速|
|`class`         |`C`        |`length `|クラスの完全名               |低速|
|`method`        |`M`        |         |メソッド名                   |低速|
|                |           |         |                            |   |
|`exception`     |`ex`       |`depth`  |例外                         |   |
|`rootException` |`rEx`      |`depth`  |例外                         |   |
|`xException`    |`xEx`      |`depth`  |例外                         |   |
|`nopexception`  |`nopex`    |         |例外を出力しない              |   |

##### 書式修飾子

書式修飾子を使うと出力するデータの幅や文字揃えを指定できます。
書式修飾子は%記号と変換指定子の間に記述します。

この例では最小幅20、最大幅30の範囲でロガーの名前を出力します。
ロガーが20文字未満の場合は半角スペースを右側にパディングして20文字に調整します。(左揃え)

```xml:書式修飾子
%-20.30logger
```

|option |description                |
|:------|:--------------------------|
|`-`    |左揃えにします.             |
|`10`   |最小幅10文字で足りない分は先頭に半角スペースを付加します(右揃えに).|
|`-10`  |最小幅10文字で足りない分は末尾に半角スペースを付加します(左揃えに).|
|`.20`  |最大幅20文字で超えた分は先頭から削除します.|
|`.-20` |最大幅20文字で超えた分は末尾から削除します.|

**date**

%dateまたは%d変換指定子で日付を出力することができます。
引数にfomartとタイムゾーンを指定できます。

|pattern                                      |output                    |
|:--------------------------------------------|:-------------------------|
|`%date`                                      |2015-06-22 12:34:56,789   |
|`%date{yyyy-MM-dd}`                          |2015-06-22                |
|`%date{yyyy-MM-dd HH:mm:ss.SSS}`             |2015-06-22 12:34:56.789   |
|`%date{yyyy-MM-dd HH:mm:ss.SSS, Asia/Tokyo}` |同上, タイムゾーン指定あり. |

[Java8 - SimpleDateFormat] (http://docs.oracle.com/javase/jp/8/api/java/text/SimpleDateFormat.html)

**replace(p)**

文字列の置換を行います。

この例は、メッセージの半角スペースを削除します。

```xml:replace
%repalce(%msg){'\s',''}
```

この例は、ロガーとメッセージの`.`を`/`に置換します。

```xml:replace
%replace(%logger %msg){'\.','/'}
```

**exception**

例外を出力するのに特別な設定は不要です。
ロガーの引数に例外オブジェクトを渡すだけで例外のスタックトレースが出力されます。

```java:exception(抜粋)
public class Ringo {
  private static final Logger logger = LoggerFactory.getLogger(Ringo.class);

  public static void doExec() {

    ...省略...

    Exception error = new Exception("例外メッセージ");
    logger.error("りんごの例外テスト",error);
  }
}
```

変換パターン文字列にも例外用の変換指定子を含めなくてもスタックトレースが出力されます。

```xml:pattern
<encoder>
   <pattern>%-5r %date [%t] %-5le %-30.30lo{20} - %msg %n</pattern>
</encoder>
```

```text:output
291   2015-06-22 10:40:43,763 [main] ERROR c.e.s.fruits.Ringo             - りんごの例外テスト 
java.lang.Exception: 例外メッセージ
	at com.example.sample.fruits.Ringo.doExec(Ringo.java:26) ~[classes/:na]
	at com.example.sample.Main.Sample1(Main.java:21) [classes/:na]
	at com.example.lbsample.App.main(App.java:21) [classes/:na]
```

スタックトレースの出力を制御したい場合は`%ex`,`%xEx`,`%rEx`などの変換指定子を使用します。

**coloring**

色付け用の変換指定子を使ってメッセージを色づけすることができます。

`%highlight`の他に下表の色が指定できます。

|regular  |bold         |
|:--------|:------------|
|%black   |             |
|%red     |%boldRed     |
|%green   |%boldGreen   |
|%yellow  |%boldYellow  |
|%blue    |%boldBlue    |
|%magenta |%boldMagenta |
|%cyan    |%boldCyan    |
|%white   |%boldWhite   |
|%gray    |             |

```xml:coloring
<pattern>%d{yyyy-MM-dd HH:mm:ss} - [%t] - %highlight(%-5le) - %green(%-30lo{20}) - %msg %n</pattern>
```

### encoder

**encoderは次のようなものがあります**

* LayoutWrappingEncoder
* PatternLayoutEncoder

#### LayoutWrappingEncoder

FQCN:`ch.qos.logback.core.encoder.LayoutWrappingEncoder`
API: [Class LayoutWrappingEncoder<E>] (http://logback.qos.ch/apidocs/ch/qos/logback/core/encoder/LayoutWrappingEncoder.html)

自作のレイアウトを使用する場合などに使用します。

|property name       |type             |Description                                       |
|:-------------------|:----------------|:-------------------------------------------------|
|`pattern`           |String           |変換パターン文字列を指定します.  |
|`layout`            |Layout           |default `PatternLayout`.      |
|`immediateFlush`    |boolean          |default `true`. falseを指定するとファイルへの書き込みをバッファリングします. |
|`charset`           |Charset          |文字コードを指定します.         |

```xml:LayoutWrappingEncoder
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
  <layout class="chapters.layouts.MySampleLayout" />
</encoder>
```

#### PatternLayoutEncoder

FQCN:`ch.qos.logback.core.encoder.PatternLayoutEncoder`
API: [Class PatternLayoutEncoder] (http://logback.qos.ch/apidocs/ch/qos/logback/classic/encoder/PatternLayoutEncoder.html)

`PatternLayoutEncoder`はデフォルトのエンコーダーなのでclassに指定しなくてもかまいません。

|property name       |type             |Description                                       |
|:-------------------|:----------------|:-------------------------------------------------|
|`pattern`           |String           |変換パターン文字列を指定します.  |
|`layout`            |Layout           |default `PatternLayout`.       |
|`immediateFlush`    |boolean          |default `true`.  falseを指定するとファイルへの書き込みをバッファリングします.   |
|`charset`           |Charset          |文字コードを指定します.          |

```xml:default
<encoder>
  <pattern>%-5r %d{yyyyMMdd HH:mm:ss.SSS} [%t] %-5le %lo{36} [%file:%line] - %msg %n</pattern>
  <immediateFlush>true</immediateFlush>
</encoder>
```

これは上記の例と同じ意味になります。

```xml:PatternLayoutEncoder
<encoder class="ch.qos.logback.core.encoder.PatternLayoutEncoder">
  <pattern>%-5r %d{yyyyMMdd HH:mm:ss.SSS} [%t] %-5le %lo{36} [%file:%line] - %msg %n</pattern>
</encoder>
```

### filter

**filterは次のようなものがあります**

* LevelFilter
* ThresholdFilter
* EvaluatorFilter

#### LevelFilter

FQCN:`ch.qos.logback.classic.filter.LevelFilter`
API: [Class LevelFilter] (http://logback.qos.ch/apidocs/ch/qos/logback/classic/filter/LevelFilter.html)

ログレベルでフィルタリングします。指定したレベルのログは`onMatch`で、それ以外のレベルのログは`onMismatch`で出力するか決定します。

[Enum FilterReply] (http://logback.qos.ch/apidocs/ch/qos/logback/core/spi/FilterReply.html)

```xml:LevelFilter
<filter class="ch.qos.logback.classic.filter.LevelFilter">
  <level>INFO</level>
  <onMatch>ACCEPT</onMatch>
  <onMismatch>DENY</onMismatch>
</filter>
```

#### ThresholdFilter

FQCN:`ch.qos.logback.classic.filter.ThresholdFilter`
API: [Class ThresholdFilter] (http://logback.qos.ch/apidocs/ch/qos/logback/classic/filter/ThresholdFilter.html)

ログレベルでフィルタリングします。指定したレベル以上のログが出力されます。

```xml:ThresholdFilter
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
  <level>ERROR</level>
</filter>
```

#### EvaluatorFilter

FQCN:`ch.qos.logback.core.filter.EvaluatorFilter`
API: [Class EvaluatorFilter<E>] (http://logback.qos.ch/apidocs/ch/qos/logback/core/filter/EvaluatorFilter.html)

フィルタリングはEventEvaluatorインターフェースを実装したクラスで評価した結果で行います。

### TurboFilters

**TurboFiltersは次のようなものがあります**

* MDCFilter
* MarkerFilter
* DuplicateMessageFilter

##### MDCFilter

FQCN:`ch.qos.logback.classic.turbo.MDCFilter`
API: [Class MDC] (http://logback.qos.ch/apidocs/ch/qos/logback/classic/MDC.html)

[Chapter 8: Mapped Diagnostic Context] (http://logback.qos.ch/manual/mdc.html)

##### MarkerFilter

FQCN:`ch.qos.logback.classic.turbo.MarkerFilter`
API: [Class MarkerFilter] (http://logback.qos.ch/apidocs/ch/qos/logback/classic/turbo/MarkerFilter.html)

マーカーが関連付けられたログをフィルタリングします。

この例では`com.example.sample.animal`パッケージのログはWARNレベル以上しか出力されない設定になっていますが`MarkerFilter`によって`com.example.sample.animal.Cat`のログはレベルにかかわらず出力されます。

```java:marker(抜粋)
package com.example.sample.animal;

public class Cat {
  private static final Marker marker = MarkerFactory.getMarker(Cat.class.getCanonicalName());

  public static void doExec() {
    ...省略...
    logger.debug(marker, "marker:{}", marker.getName());
  }
}
```

```xml:MarkerFilter
<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
  <Marker>com.example.sample.animal.Cat</Marker>
  <OnMatch>ACCEPT</OnMatch>
</turboFilter>

<!-- WARN以上 -->
<logger name="com.example.sample.animal" level="WARN">
  <appender-ref ref="STDOUT"/>
</logger>
```

##### DuplicateMessageFilter

FQCN:`ch.qos.logback.classic.turbo.DuplicateMessageFilter`
API: [Class DuplicateMessageFilter] (http://logback.qos.ch/apidocs/ch/qos/logback/classic/turbo/DuplicateMessageFilter.html)

重複するメッセージをフィルタリングします。

|property name       |type             |Description                                       |
|:-------------------|:----------------|:-------------------------------------------------|
|`allowedRepetitions`|int              |繰り返しを許容する回数を指定します. デフォルトは5です.|
|`cacheSize`         |int              |デフォルトは100です.|

```xml:DuplicateMessageFilter
<turboFilter class="ch.qos.logback.classic.turbo.DuplicateMessageFilter">
  <allowedRepetitions>10</allowedRepetitions>
  <cacheSize>200</cacheSize>
</turboFilter>
```

### logger

ロガーはlogger要素で設定します。

* level属性はTRACE、DEBUG、INFO、WARN、ERROR、ALL、OFFのいずれかを指定できます。
* additivityは任意です。デフォルトはtrueです。
* appender-refでアペンダーを指定します。

```xml:logger
<logger name="com.example.sample.fruits" level="INFO">
  <appender-ref ref="STDOUT"/>
  <appender-ref ref="FILE"/>
</logger>
```

#### root logger

ルートロガーはroot要素で設定します。
ルートロガーは全てのロガーの祖先ロガーです。

* level属性(必須)。デフォルトはDEBUGです。
* name属性は指定できません。(名前は"ROOT"で固定されているため)
* appender-refでアペンダーを指定します。

```xml:root
<root level="DEBUG">
  <appender-ref ref="CONSOLE" />
  <appender-ref ref="FILE" />
</root>
```

### Variable

変数を定義して使用することができます。
暗黙的に`HOSTNAME`変数と`CONTEXT_NAME`変数が定義されています。

#### property

**変数の定義**

設定ファイル内で変数を定義します。

```xml:property
<property name="LOG_DIR" value="D:/logs" />
```

外部のプロパティファイルを読み込んで変数を定義します。

```xml:property
<property file="src/main/resources/variables1.properties" />
```

**定義した変数の使用**

変数を使用するには定義した変数名を`${`と`}`で囲みます。

```xml:variable
<file>${LOG_DIR}/app.log</file>
```

パターン内で変数を使用するにはproperty変換指定子を使用します。

```xml:property
<encoder>
  <pattern>%property{HOSTNAME} %d [%t] - %msg%n</pattern>
</encoder>
```

**変数のデフォルト値**

デフォルト値は`:-`の後に続けて指定します。

```xml:default
<file>${LOG_DIR:-/var/logs}/app.log</file>
```

**変数のネスト**

変数の値を別の変数名の一部として使用することができます。

この例では、file要素は`D:/logs/cust_r.log`になります。

```properties:variables1.properties
DEP = CUSTOMER
PRI = REGULAR

CUSTOMER.REGULAR = cust_r
CUSTOMER.IRREGULAR = cust_i
CUSTOMER.EMERGENCY = cust_e
SALES.REGULAR = sale_r
SALES.IRREGULAR = sale_i
SALES.EMERGENCY = sale_e
PERSONNEL.REGULAR = pers_r
PERSONNEL.IRREGULAR = pers_i
PERSONNEL.EMERGENCY = pers_e
```

```xml:logback.xml
<property name="LOG_DIR" value="D:/logs" />
<property file="src/main/resources/variables1.properties" />

<file>${LOG_DIR}/${${DEP}.${PRI}}.log</file>
```

#### timestamp

**変数にタイムスタンプを使用**

```xml:timestamp
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
```

```xml:timestamp
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss" timeReference="contextBirth"/>
```

## 付録

### Eclipseのコンソールをカラーコードに対応させる

**インストール**

http://mihai-nita.net/java/ を参照しEclipseのPluginをインストールします。

**設定**

Window -> Preferences -> Ansi Consoleから下図のように設定を行います。

* Enabledにチェックを入れます。
* Show the escape sequencesのチェックを外します。

![AnsiConsole.png](https://qiita-image-store.s3.amazonaws.com/0/22772/cb0550c6-b3b8-fee0-9b87-bcc357b361bb.png)

**コンソール**

カラーコード付きのメッセージを出力します。

![eclipse_console.png](https://qiita-image-store.s3.amazonaws.com/0/22772/c5e1136e-f296-66ac-8510-aea6f70040f1.png)