スポンサーリンク
技術関係

Spring Bootのロギング実装は「Commons-Logging + Logback」がデフォルト設定であることを確認する

これがSpring Bootのロギング実装って何もしない設定しない場合どうなっているのだろうか・・・?

という疑問が湧いたので調べてみた。

Spring Bootでは全ての内部ロギングでCommons Loggingを利用しているが、基本となるログ実装部分は開発者に委ねられている。

(中略)

デフォルト設定では、Starter POMを利用する場合はLogbackが採用される。Logback以外を利用したければdependencyを変更するだけでOK。

Spring Boot Features 4. Logging / Spring Boot Reference Documentation

Spring Bootのログ出力(概要) / @NagaokaKenichi

 

Spring Boot内のロギングではインターフェースとして「Commons-Logging」を使用する。

実際のログ出力処理の際には「Logback」というライブラリを使用する。(デフォルト時)

 

これがSpring Bootのデフォルトの実装となる。

 

ロギングの歴史と仕組みを全く知らないと非常に分かりづらいが、要するに

import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory

class HogeMoge {
    private val log: Log = LogFactory.getLog(javaClass)

    fun MoMoge() {
        log.info("INFOです")
    }
}

上記のような形だと一見ログ処理は「Commons-Logging」が担当しており、ログ出力する実際の処理も「Commons-Logging」で行っている風に見える。

 

が、あくまでも「Commons-Logging」とはインターフェースを提供するライブラリ。

 

出力処理の実装を担っているのは「Logback」という別のライブラリになる。

スポンサーリンク

環境情報

Gradle: 6.0.1

Spring Boot: 2.2.4.RELEASE

Spring Bootデフォルトのログ出力

Spring Initializrでサンプルプロジェクトを用意してBootRunしてみる。
依存関係にはspring-starter-webだけを設定。

何も弄っていないデフォルトのログ出力はこんな感じ。

「Commons-Logging」→「Logback」という形でログが出力されている。

Spring BootプロジェクトからLogbackを除外してみる

build.gradle.ktsにてLogbackをexcludeする記述を書いてみます。

 

spring-boot-starter-loggingを依存関係から除してみます。

configurations.all {
   exclude(module = "spring-boot-starter-logging")
}

このライブラリはspring-boot-starter-webで自動的に依存関係のライブラリとして入れられるものです。

 

そしてBootRunしてみる。すると以下のようになる。

ログが赤字で表示されている。

現在の状態は

 

Spring Bootの内部ロギングで使用している「Commons-Logging」 は存在する

が、肝心のログ出力処理を実装しているライブラリ「Logback」は存在しない

 

 

 

そのため、いつも見るLogbackで出力される白文字のログは出ていない事が分かる。

 

「Logbackが存在しないと全くログが出力されないのでは?」

 

と思ったが、そのような事はなくTomcatの依存関係であるログライブラリがログを出力しており、Tomcat側がログを出力する形になるとのこと。

Spring Bootの赤字で出るログは何が出力している?/ teratail

Spring BootプロジェクトからCommons-Loggingを除外してみる

次はCommons-Loggingを除外してみます。

 

 

build.gradle.ktsにてspring-jclをexcludeすればOK。

configurations.all {
   exclude(module = "spring-jcl")
}

命名も相まって理解を難しくさせるが、「jcl」とは「Jakarta Commons Logging」の略称。

 

 

BootRunして確認してみる。

 

 

java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactoryと出ているのが分かる。

> Task :bootRun FAILED
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
    at org.springframework.boot.SpringApplication.(SpringApplication.java:196)
    at com.test2.test2.Test2ApplicationKt.main(Test2Application.kt:28)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 2 more

現在の状態は

 

 

Spring Bootの内部ロギングで使用している「Commons-Logging」 は存在しない

実際にログ出力処理を実装しているライブラリ「Logback」は存在する

 

そのため、当然NoClassDefFoundErrorでBuildに失敗する。

spring-jcl

Spring Framework 5.0からは、「Commons LoggingのAPIを実装したブリッジライブラリ」の部分をspring-jclが担うため、jcl-over-slf4jなどのブリッジライブラリを追加することなく、Commons LoggingのAPIを使用して「Log4j 2.x」「SLF4J」「JUL(java.util.logging)」経由でログを出力することができます。

Spring Framework 5.0 コア機能の主な変更点 @kazuki43zoo

 

spring-jclはすごいやつ(超意訳)」

 

登場前は開発者側がブリッジライブラリ追加や「本家Commons-Logging」除外などを行わなければならなかった。

しかし、spring-jclモジュールが存在するだけでそれを解決してくれるすごいやつ。

slf4j

ここで出た「SLF4J」とは「Commons-Logging」と同じくインターフェース的ライブラリ。

ちなみに「ログファサードライブラリ」とも呼ぶ。

jcl-over-slf4j

jcl-over-slf4jの例があるが、これは「Commons-Logging」での実装を「SLF4J」をバイパスしてくれるもの。

spring-jcl登場以前は別個でこのライブラリを追加しなければならなかった。

要するに、spring-jclが「Commons-Logging」と「SLF4J」の2つのログ出力が依存モジュールで混在していてもブリッジの役割を果たして出力してくれるという事になる。

 

 

サンプルプロジェクトではSpring Bootの最小構成であるが、プロジェクトが大きくなるにつれてライブラリも増えログ出力の種類が混在してくるようになる。

その時になると恩恵を感じられるようになるもの。

 

分かりづらい世界であるが、下記記事が分かりやすく参考になる。

Javaのロギングライブラリの歴史と現状をふんわり把握する(初学者向け) / @nisshiee

まとめ

何も考えずにSpring Bootロギングの奥を覗いてみたら、Javaのロギングの歴史に片足を突っ込んでしまった。

 

しかし、基本的にアプリ開発者は煩わしい事を考えずにログ実装が出来るようにされてある。

$ ./gradlew dependencies
+--- org.springframework.boot:spring-boot-starter-web -> 2.2.4.RELEASE
| +--- org.springframework.boot:spring-boot-starter:2.2.4.RELEASE
| | +--- org.springframework.boot:spring-boot:2.2.4.RELEASE
| | | +--- org.springframework:spring-core:5.2.3.RELEASE
| | | | \--- org.springframework:spring-jcl:5.2.3.RELEASE
~~~~~~~~~~~(中略)~~~~~~~~~~~
| | | \--- org.springframework.boot:spring-boot:2.2.4.RELEASE (*)
| | +--- org.springframework.boot:spring-boot-starter-logging:2.2.4.RELEASE
| | | +--- ch.qos.logback:logback-classic:1.2.3
| | | | +--- ch.qos.logback:logback-core:1.2.3
| | | | \--- org.slf4j:slf4j-api:1.7.25 -> 1.7.30
| | | +--- org.apache.logging.log4j:log4j-to-slf4j:2.12.1
| | | | +--- org.slf4j:slf4j-api:1.7.25 -> 1.7.30
| | | | \--- org.apache.logging.log4j:log4j-api:2.12.1
| | | \--- org.slf4j:jul-to-slf4j:1.7.30
| | | \--- org.slf4j:slf4j-api:1.7.30

 

おしまい。

コメント

タイトルとURLをコピーしました