log4j2の設定ファイル(XML)


## 目的
自分が使いそうな設定のまとめ。

## jar ファイル
最低限、以下のファイルが必要。

log4j-api-2.3.jar
log4j-core-2.3.jar
(2.3 はこれを書いている時点の最新バージョン)

## 全体
こんな感じで。
ファイル名はlog4j2.xmlとして、クラスパス上に配置。

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

    <!-- AppenterやLoggerで使用するプロパティを定義する -->
    <Properties>
        <Property name="...">hoge</Property>
        <Property name="..." value="..." />
    </Properties>

    <!-- ログの出力先と出力フォーマットを設定する -->
    <Appenders>
    </Appenders>

    <!-- パッケージごとにAppenderとログレベルを組み合わせる -->
    <Loggers>
        <Logger ...>
        <Logger ...>
    </Loggers>
</Configuration>
```

## Configuration
`<Configuration>` に設定する属性。

log4j2自身のログを出力したいときは、statusにログレベルを設定する。
`<Configuration status="debug">` とか。

通常はオフで。
`<Configuration status="off">`

`monitorInterval` を指定する(単位は秒)と、アプリケーションを終了させずに、指定した間隔で設定の変更を読み込んでくれそうな気がするんだが、違うのかな...
下記の例は60秒。[公式マニュアル](http://logging.apache.org/log4j/2.x/manual/configuration.html#AutomaticReconfiguration)によると、最小は5秒。
`<Configuration monitorInterval="60">`

他の属性は公式マニュアルで。
[Configraton Syntax](http://logging.apache.org/log4j/2.x/manual/configuration.html#ConfigurationSyntax)

## Properties
設定ファイル内で使用するプロパティを定義できる。何度も使うログ出力パターンやログファイルパスなどを、変数として外出しにするような場合に使う。

こんな感じで。

```
<Properties>
    <Property name="prop1">prop1に設定する値</Property>
    <Property name="prop2">prop2に設定する値</Property>
</Properties>
```

設定したプロパティを使う場合は、`${prop1}` のように書く。

システムのプロパティを使いたいときは、`${sys:propertyname}` のように、プロパティ名の前にコロンで区切ったプレフィックスを付ける。
例えば、Tomcatのインストールディレクトリパスをプロパティとして使いたい場合は、
`${sys:catalina.base}` のように指定する。

Javaのシステムプロパティは`${sys:propertyname}` で指定する。
OSの環境変数は`${env:propertyname}` で指定する。

### プロパティを外部ファイルで指定したい場合
`${bundle:BundleName:BundleKey}`を使う。
java.util.ResourceBundle なので、BundleName にはリソースバンドルの基底名、BundleKey にはリソースバンドルのキー名を記述する。
例えば、`${bundle:hoge.fuga:key1}` と指定した場合は、クラスパス上のhoge/fuga.properties ファイルに記述してあるkey1の値を取得する。
(リソースバンドルなので、ファイルを hoge/fuga_ja.properties のようにロケール別にもできるけど使い道が思いつかない)

詳細や他のプレフィックスは公式マニュアルで。
[Property Substitution](http://logging.apache.org/log4j/2.x/manual/configuration.html#PropertySubstitution)

## PatternLayout
Property でログの出力形式を定義する方式にする。ここに書いてないパターンは公式マニュアルの[PatternLayout](http://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout)を参照。PatternLayout以外のlayoutもある。
書き方は以下の様な感じ。

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

どうせログをコピペしてExcelに貼り付けたがると思うので、カンマ区切りにしている。
`[%d{yyyy-MM-dd HH:mm:ss.SSS}]` : %dは日時。%dateでも可。{}の中に日時の形式を指定する。この例だと[2015-01-01 12:34:56.789]のように出力される。
`%-5p` : %pはログレベル。%levelでも可。-5は書式指定で、この場合ログレベルが左詰めで5文字分出力される。例えば、ログレベルがinfoの場合は、INFO＋空白1文字が出力される。
`%t` : %tはスレッド名。%threadでも可。
`%c` : %c(小文字)はロガー名。%loggerでも可。ロガー名は、自分の場合は完全修飾クラス名にすると思うので、ログを出力したクラスのパッケージとクラス名が出力される(ロガー名を完全修飾クラス名にしない場合ってどういうときだろう)。
`%m` : %m はログメッセージ。%msg か %messageでも可。
`%n` : 改行。

以下はパフォーマンスに影響あるかもしれないので注意して使ってください系。
`%C` : %C(大文字)は完全修飾クラス名。%classでも可。
`%M` : %Mはメソッド名。%methodでも可。
`%F` : %Fはソースファイル名。%fileでも可。
`%L` : %Lはソースの行数。%lineでも可。
`%l` : %lは`%C.%M(%F:%L)`と同じ。%locationでも可。


## Appenders
真っ先に使いそうな ConsoleAppender と RollingFileAppender に絞って書く。
他の Appender は公式マニュアルで。
[Appenders](http://logging.apache.org/log4j/2.x/manual/appenders.html)

### ConsoleAppender
コンソールにログを出力する。
[ConsoleAppender](http://logging.apache.org/log4j/2.x/manual/appenders.html#ConsoleAppender)の属性は name と target を指定する(これ以外の属性もある)。
ログ出力形式は `<Property>` で定義しておいて、`<PatternLayout>`でセットする方式で記述している。
以下の様な感じ。

```
<Appenders>
    <Console name="stdout" target="SYSTEM_OUT">
        <PatternLayout pattern="${loglayout}"/>
    </Console>
</Appenders>
```

#### name
この ConsoleAppender の名前を付ける。このあと出てくる Loggers で使う。

#### target
"SYSTEM_OUT" か "SYSTEM_ERR" を指定する。SYSTEM_OUT は System.out にログを出力。SYSTEM_ERR は System.err に出力する。デフォルトは"SYSEM_ERR"。

### RollingFileAppender
ログをファイルに出力する。設定した条件が満たされると、ログの出力先が別のファイルに切り替わる。
[RollingFileAppender](http://logging.apache.org/log4j/2.x/manual/appenders.html#RollingFileAppender)の属性は name, fileName, filePattern を指定する(これ以外の属性もある)。さらにサブノードで TriggingPolicy, RolloverStrategyを指定する。
以下の様な感じ。

```
<Appenders>
    <RollingFile name="rolling" fileName="ログファイルのパスとファイル名" filePattern="アーカイブされるログファイルのパスとファイル名">
        <PatternLayout pattern="${loglayout}"/>
        <Policies>
            <OnStartupTriggeringPolicy />
            <SizeBasedTriggeringPolicy size="20 MB" />
            <TimeBasedTriggeringPolicy />
        </Policies>
        <DefaultRolloverStrategy max="10"/>
    </RollingFile>
</Appenders>
```

- name : この RollingFileAppender の名前を付ける。このあと出てくる Loggers で使う。
- fileName : ログを出力するファイルパスを記述する。<br/>`fileName="C:/log/app.log"` みたいに書く。パスやファイルが存在しない場合は自動的に作成される。
- filePattern : 過去のログファイルのアーカイブ時のファイルパスを記述する。<br/>`filePattern="C:/log/app-%d{yyyy-MM-dd}-%i.zip"` みたいに書く。%d{}は日付。時刻も書式指定可能。%iはファイルの枝番。枝番の数字の付け方は DefaultRolloverStrategy で指定。拡張子は".gz"か".zip"を指定すると圧縮する。

#### Policies
ログファイルが切り替わる方針を設定する。以下の3つから、1つ以上を組み合わせて使う。

- `<OnStartupTriggeringPolicy />` : ログファイルが現在のJVMの開始時刻より古い場合、ロールオーバーする。つまりJVM開始時にロールオーバーするということ。
- `<SizeBasedTriggeringPolicy size="20 MB" />` : ログファイルが指定したサイズに達した時にロールオーバーする。指定できる単位は、KB, MB, GB。
- `<TimeBasedTriggeringPolicy />` : これで日付が変わった時にロールオーバーする。こいつの属性である interval と modulate はあとで調べる。

#### DefaultRolloverStrategy
ロールオーバーファイルの番号付けや圧縮率を指定する。以下の様な感じ。

```
<DefaultRolloverStrategy fileIndex="max" min="1" max="10"/>
```

- fileIndex : `max`か`min`を指定する。`max`がデフォルト。数値が大きいほど新しいロールオーバーファイル(*-1.zip, *-2.zip...というふうに枝番が付く)。`min`を指定すると番号付けが逆になる。つまり、数値が大きいほど古いロールオーバーファイル。
- min : 枝番の最小の数値。デフォルトは1。
- max : 枝番の最大の数値。ロールオーバーファイルの数がこの数値を超えると、古いロールオーバーファイルは削除される。
- compressionLevel : ロールオーバーファイルの拡張子がzipの場合に有効。0-9を指定可能。0は圧縮なし。数値が大きいほど高圧縮率。

## Loggers
マニュアルに Loggers に関する説明が無いような気がするんだが。
ログを出力するJavaパッケージ、ログレベル、ログの出力先を指定する。以下の様な感じ。

```
<Loggers>
    <Logger name="hoge.fuga.sample" level="info" additivity="false">
        <AppenderRef ref="appender1"/>
        <AppenderRef ref="appender2"/>
    </Logger>
</Loggers>
```

- name : ログを出力したいJavaパッケージ名を指定する。<br/>上の例のように書くと、hoge.fuga.sampleパッケージとそのサブパッケージのログを出力する。パッケージ名を指定する以外のやり方は知らない(どこに書いてあるのか?)。
- level : 出力するログレベル。上の例のように書くと、info以上のレベルのログを出力する。<br/>つまり、debug, traceのログは出力しない。
- additivity : 上位のロガーにもログを出力するかどうか。デフォルトはtrue。なんだか同じログが複数回出力されているなあ(つまり指定したロガーとその上位のロガーで同じログを出力している)、と思ったらfalseに設定する。

#### AppenderRef
ConsoleAppender や RollingFileAppender の`name`を指定する。複数の Appender にログを出力したい場合は、`<AppenferRef>` タグを必要な分だけ記述する。

## log4j2 のシステムプロパティ
下記を参照。`log4j.configurationFile` くらいは使うかもしれない。
[System Properties](http://logging.apache.org/log4j/2.x/manual/configuration.html#SystemProperties)

## 使い方
以下の様な感じ。

```
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class SampleClass {
    // static変数にするかどうかは、方針を決めること
    // getLogger()の引数にはクラス名.classを指定する(省略可能)
    private final Logger logger = LogManager.getLogger(SampleClass.class);
    
    public void sampleMethod() {
        // ログメッセージのみ
        logger.info("This is info level log.");
        
        // 変数を{}に埋め込む
        int val1 = 1;
        int val2 = 2;
        logger.info("val1={}, val2={}", val1, val2);
        
        // フォーマットを指定する
        int val3 = 3;
        logger.printf(Level.INFO, "val3=%d", val3);
    }
}
```

## 参照したURL

- http://logging.apache.org/log4j/2.x/manual/configuration.html
- http://logging.apache.org/log4j/2.x/manual/appenders.html
- http://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout