0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

spring boot 2 + logback

Posted at

今の状況

これまで Spring Boot 2 + log4j1 の構成でログを管理してきたが、
流石にlog4j1は古過ぎて(メンテナンスも終わっている)、移行することにした。
しかし、log4j1からlog4j2はリリース20年の差が大き過ぎて
単純バージョンアップではなかった。

どうせlog4j2は変更点も多いし、spring bootらしい開発にするため、
内蔵ライブラリのlogbackに移行する事になった。

要求事項

① コンソール出力(infoレベル)、ファイル出力(ALLレベル)、両方したい。
② ファイル出力は毎日ローテート。
③ カスタムパターン(レイアウト)使いたい。

少しみてみると、あ〜appenderとloggerは二つ必要だね〜
カスタムパターンはクラス作成が必要だね〜とかが予想できる。

変更点4つ

1.ライブラリー
2.ログ設定ファイル
3.カスタムパターン(レイアウト)ファイル
4.格ファイルでの出力方法

変更点1.ライブラリー

元々は以下のように log4j1 の core ライブラリを使っていた:build.grade

implementation ('org.springframework.boot:spring-boot-starter-web'){
    exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
implementation 'log4j:log4j:1.2.17'

logback に移行する場合、Spring Boot に元々含まれているため、追加の設定は基本不要。

implementation 'org.springframework.boot:spring-boot-starter-web'

ここで以下の設定も削除(理由は後述。変更点3と関連がある。)
developmentOnly("org.springframework.boot:spring-boot-devtools")

変更点2.ログ設定ファイル

元々ログ設定ファイルはlog4j.propertiesだったが、logback-spring.xmlに変更。
要求事項を満たすための内容を記載する。

<configuration>
    <conversionRule conversionWord="U" converterClass="com.example.logging.UserConverter" />
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>任意のパターン1</pattern>
        </encoder>
    </appender>

    <appender name="LogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/debug.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>任意のパターン2</pattern>
        </encoder>
    </appender>

    <!-- ルートロガー -->
    <root level="INFO">
        <appender-ref ref="Console"/>
    </root>
    <logger name="対象パッケージ" level="ALL">
        <appender-ref ref="LogFile"/>
    </logger>
    
</configuration>

① コンソール出力(infoレベル)ファイル出力(ALLレベル)、両方したい。
Console、LogFile、二つのappenderを格loggerに設定。

② ファイル出力は毎日ローテート。
特に設定タグとかはなくて、fileNamePatternに記載する%d{yyyy-MM-dd}から決められている。
%d{yyyy-MM-dd-HH-mm}にすると1分ずつファイルがセーブされる。

③ カスタムパターン(レイアウト)使いたい。
任意のパターンに、ユーザ情報も出力したい問いことで「%U」とかも記載する。
例えば

%d{yyyy-MM-dd HH:mm:ss} [%thread] &lt;%U&gt; %-5level %logger - %msg%n

変更点3.カスタムパターン(レイアウト)ファイル

%Uのようなカスタム変換子は、
log4j1ではorg.apache.log4j.PatternLayoutを継承したが、
logbackではClassicConverterを継承して自作する必要がある。

@Converter(name = "U", type = ConversionType.class)
public class UserConverter extends ClassicConverter {

    //@autowired
    //UserDto userdto;
    
    @Override
    public String convert(ILoggingEvent event) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
            .getRequestAttributes()).getRequest();

        UserDto user = (UserDto)request.getSession().getAttribute("USER_ID");
        return user.getXX(); // ユーザ情報
    }
}

本当は Springの@Autowiredを使ってセッション管理用のDTOなどを注入したかったが、
ClassicConverterはSpring管理下のBeanではないためDIが効かない。
そのため、RequestContextHolder を使って直接セッションから値を取得するようにした。
例えば、セッションに"USER_ID"を格納しておけば、その値をログに出力できる。

補足:
Sessionからユーザー情報(Object)を取得して、
カスタムConverter内で(UserDto)でキャストしようとしたところ、ClassCastExceptionが発生した。

原因は Spring Boot DevToolsによるクラスローダーの分離。
DevToolsは再起動用のクラスローダーを使用するため、
同じクラス(UserDto)でも異なるクラスローダーで読み込まれた結果、「同じ名前なのに別物」として扱われ、キャストに失敗した。
この問題を回避するため、build.gradle から DevToolsの依存を削除した。

変更点4.格ファイルでの出力方法

import org.apache.logging.log4j.Logger;
Logger log = Logger.getLogger(MyClass);

import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
Logger log = LoggerFactory.getLogger(MyClass);

終わりに

Log4j2は機能が豊富でパフォーマンスも良いが、Spring Bootとの相性やメンテナンス性を考えると、logbackの方が楽というのが今回の感想。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?