Spring BootでIPアドレスのログ出力


ユーザの操作手順を追跡するために、IPアドレスをログ出力したいなんて話があると思います。
そんな要件のSpring Bootでの実装手順です。
#バージョン
Spring Boot:1.3.6

#参考
[Spring Bootのログ設定を変更する](http://qiita.com/tag1216/items/b898b8fb58920bf335b2)
デフォルト設定の変更方法などが簡潔にまとめられています。

[Logback 使い方メモ](http://qiita.com/opengl-8080/items/49719f2d35171f017aa9)
ローテーションとか、欲しい情報がまとまっていてありがたいです。

[logback マニュアル-第8章 診断コンテキスト](http://logback.qos.ch/manual/mdc_ja.html)
lobbackは和訳があるのですね。素晴らしい。。
http://logback.qos.ch/manual/index_ja.html

#フォルダ構成
 LogSettingFilter.javaでIPアドレスの取得、logback.xmlで出力設定しています。

```フォルダ構成
└── src
     └── main
        ├── java
        │   └── com
        │       └── example
        │           ├── AppConfig.java
        │           ├── LogSettingFilter.java
        │           ├── SampleController.java
        │           └── SpringbootLogApplication.java
        └── resources
            └── logback.xml

```

#実装
logback.xmlを作成します。
spring-boot.jar配下のdefaults.xmlを読み込んでいます。
パターンの内容は[Logback 使い方メモ-メッセージのパターンを指定する](http://qiita.com/opengl-8080/items/49719f2d35171f017aa9#%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%81%AE%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B)にあります。
%X{client} は後述の診断コンテキストで設定しているパラメータでIPアドレスの設定箇所になります。
ここではコンソール出力のみしています。

```xml:lobback.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d %p %t %c %X{client} - %m%n</Pattern>
        </layout>
    </appender>
</configuration>
```

JavaEEのFilterを実装したクラスを作成し、MDC(診断コンテキスト)にIPアドレスを設定します。
MDCにはスレッドローカルで保存されます。

```java:LogSettingFiler.java
package com.example;

import org.slf4j.MDC;

import javax.servlet.*;
import java.io.IOException;

/**
 * ログ出力用の診断コンテキストを設定するFilterクラス.
 */
public class LogSettingFilter implements Filter {

    String CLIENT = "client";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    /**
     * 診断コンテキストを設定します.
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        try {
            MDC.put(CLIENT, servletRequest.getRemoteAddr());
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            MDC.remove(CLIENT);
        }
    }

    @Override
    public void destroy() {

    }
}
```

上記で作成したFilterクラスを設定します。

```java:AppConfig.java
package com.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class AppConfig {

    @Bean
    LogSettingFilter logSettingFilterFilter() {

        LogSettingFilter filter = new LogSettingFilter();
        return filter;
    }

}
```

適当なコントローラを作成してログ出力してみます。

```java:SampleController
package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/web/sample")
public class SampleController {

    private static Logger logger = LoggerFactory.getLogger(SampleController.class);

    @RequestMapping(method = RequestMethod.GET)
    public int logSample() {

        logger.info("IPアドレス出力");
        return 1;
    }

}
```

こんな感じで出力されます。

```:実行結果
2016-07-18 16:39:04,522 INFO http-nio-8080-exec-1 com.example.SampleController 0:0:0:0:0:0:0:1 - IPアドレス出力

```