Spring Boot 日誌各類使用姿式,是時候捋清楚了!

@[toc] 以前錄過一個視頻和你們分享 Spring Boot 日誌問題,可是總感受差點意思,所以鬆哥打算再經過一篇文章來和你們捋一捋 Java 中的日誌問題,順便咱們把 Spring Boot 中的日誌問題也說清楚。java

1. Java 日誌概覽

說到 Java 日誌,不少初學者可能都比較懵,由於這裏涉及到太多東西了:Apache Commons LoggingSlf4jLog4jLog4j2LogbackJava Util Logging 等等,這些框架各自有什麼做用?他們之間有什麼區別?git

1.1 整體概覽

下面這張圖很好的展現了 Java 中的日誌體系:web

能夠看到,Java 中的日誌框架主要分爲兩大類:日誌門面日誌實現spring

日誌門面sql

日誌門面定義了一組日誌的接口規範,它並不提供底層具體的實現邏輯。Apache Commons LoggingSlf4j 就屬於這一類。數據庫

日誌實現apache

日誌實現則是日誌具體的實現,包括日誌級別控制、日誌打印格式、日誌輸出形式(輸出到數據庫、輸出到文件、輸出到控制檯等)。Log4jLog4j2Logback 以及 Java Util Logging 則屬於這一類。tomcat

將日誌門面和日誌實現分離實際上是一種典型的門面模式,這種方式可讓具體業務在不一樣的日誌實現框架之間自由切換,而不須要改動任何代碼,開發者只須要掌握日誌門面的 API 便可。app

日誌門面是不能單獨使用的,它必須和一種具體的日誌實現框架相結合使用。框架

那麼日誌框架是否能夠單獨使用呢?

技術上來講固然沒問題,可是咱們通常不會這樣作,由於這樣作可維護性不好,並且後期擴展不易。例如 A 開發了一個工具包使用 Log4j 打印日誌,B 引用了這個工具包,可是 B 喜歡使用 Logback 打印日誌,此時就會出現一個業務使用兩個甚至多個日誌框架,開發者也須要維護多個日誌的配置文件。所以咱們都是用日誌門面打印日誌。

1.2 日誌級別

使用日誌級別的好處在於,調整級別,就能夠屏蔽掉不少調試相關的日誌輸出。不一樣的日誌實現定義的日誌級別不太同樣,不過也都大同小異。

Java Util Logging

Java Util Logging 定義了 7 個日誌級別,從嚴重到普通依次是:

  • SEVERE
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST

由於默認級別是 INFO,所以 INFO 級別如下的日誌,不會被打印出來。

Log4j

Log4j 定義了 8 個日誌級別(除去 OFF 和 ALL,能夠說分爲 6 個級別),從嚴重到普通依次是:

  • OFF:最高等級的,用於關閉全部日誌記錄。
  • FATAL:重大錯誤,這種級別能夠直接中止程序了。
  • ERROR:打印錯誤和異常信息,若是不想輸出太多的日誌,可使用這個級別。
  • WARN:警告提示。
  • INFO:用於生產環境中輸出程序運行的一些重要信息,不能濫用。
  • DEBUG:用於開發過程當中打印一些運行信息。
  • TRACE
  • ALL 最低等級的,用於打開全部日誌記錄。

Logback

Logback 日誌級別比較簡單,從嚴重到普通依次是:

  • ERROR
  • WARN
  • INFO
  • DEBUG
  • TRACE

1.3 綜合對比

Java Util Logging 系統在 JVM 啓動時讀取配置文件並完成初始化,一旦應用程序開始運行,就沒法修改配置。另外,這種日誌實現配置也不太方便,只能在 JVM 啓動時傳遞參數,像下面這樣:

-Djava.util.logging.config.file=<config-file-name>。

因爲這些侷限性,致使 Java Util Logging 並未普遍使用。

Log4j 雖然配置繁瑣,可是一旦配置完成,使用起來就很是方便,只須要將相關的配置文件放到 classpath 下便可。在不少狀況下,Log4j 的配置文件咱們能夠在不一樣的項目中反覆使用。

Log4j 能夠和 Apache Commons Logging 搭配使用,Apache Commons Logging 會自動搜索並使用 Log4j,若是沒有找到 Log4j,再使用 Java Util Logging

Log4j + Apache Commons Logging 組合更得人心的是 Slf4j + Logback 組合。

LogbackSlf4j 的原生實現框架,它也出自 Log4j 做者(Ceki Gülcü)之手,可是相比 Log4j,它擁有更多的優勢、特性以及更強的性能。

1.4 最佳實踐

  • 若是不想添加任何依賴,使用 Java Util Logging 或框架容器已經提供的日誌接口。
  • 若是比較在乎性能,推薦:Slf4j + Logback
  • 若是項目中已經使用了 Log4j 且沒有發現性能問題,推薦組合爲:Slf4j + Log4j2

2. Spring Boot 日誌實現

Spring Boot 使用 Apache Commons Logging 做爲內部的日誌框架門面,它只是一個日誌接口,在實際應用中須要爲該接口來指定相應的日誌實現。

Spring Boot 默認的日誌實現是 Logback。這個很好查看:隨便啓動一個 Spring Boot 項目,從控制檯找一行日誌,例以下面這樣:

考慮到最後的 prod 是一個能夠變化的字符,咱們在項目中全局搜索:The following profiles are active,結果以下:

在日誌輸出的那一行 debug。而後再次啓動項目,以下圖:

此時咱們就能夠看到真正的日誌實現是 Logback

其餘的諸如 Java Util LoggingLog4j 等框架,Spring Boot 也有很好的支持。

在 Spring Boot 項目中,只要添加了以下 web 依賴,日誌依賴就自動添加進來了:

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-web</artifactid>
</dependency>

2.1 Spring Boot 日誌配置

Spring Boot 的日誌系統會自動根據 classpath 下的內容選擇合適的日誌配置,在這個過程當中首選 Logback。

若是開發者須要修改日誌級別,只須要在 application.properties 文件中經過 logging.level 前綴+包名 的形式進行配置便可,例以下面這樣:

logging.level.org.springframework.web=debug
logging.level.org.hibernate=error

若是你想將日誌輸出到文件,能夠經過以下配置指定日誌文件名:

logging.file.name=javaboy.log

logging.file.name 能夠只指定日誌文件名,也能夠指定日誌文件全路徑,例以下面這樣:

logging.file.name=/Users/sang/Documents/javaboy/javaboy.log

若是你只是想從新定義輸出日誌文件的路徑,也可使用 logging.file.path 屬性,以下:

logging.file.path=/Users/sang/Documents/javaboy

若是想對輸出到文件中的日誌進行精細化管理,還有以下一些屬性能夠配置:

  • logging.logback.rollingpolicy.file-name-pattern:日誌歸檔的文件名,日誌文件達到必定大小以後,自動進行壓縮歸檔。
  • logging.logback.rollingpolicy.clean-history-on-start:是否在應用啓動時進行歸檔管理。
  • logging.logback.rollingpolicy.max-file-size:日誌文件大小上限,達到該上限後,會自動壓縮。
  • logging.logback.rollingpolicy.total-size-cap:日誌文件被刪除以前,能夠容納的最大大小。
  • logging.logback.rollingpolicy.max-history:日誌文件保存的天數。

日誌文件歸檔這塊,小夥伴們感興趣能夠本身試下,能夠首先將 max-file-size 屬性調小,這樣方便看到效果:

logging.logback.rollingpolicy.max-file-size=1MB

而後添加以下接口:

@RestController
public class HelloController {
    private static final Logger logger = getLogger(HelloController.class);
    @GetMapping("/hello")
    public void hello() {
        for (int i = 0; i &lt; 100000; i++) {
            logger.info("hello javaboy");
        }
    }
}

訪問該接口,能夠看到最終生成的日誌文件被自動壓縮了:

application.properties 中還能夠配置日誌分組。

日誌分組可以把相關的 logger 放到一個組統一管理。

例如咱們能夠定義一個 tomcat 組:

logging.group.tomcat=org.apache.catalina,org.apache.coyote, org.apache.tomcat

而後統一管理 tomcat 組中的全部 logger:

logging.level.tomcat=TRACE

Spring Boot 中還預約義了兩個日誌分組 web 和 sql,以下:

不過在 application.properties 中只能實現對日誌一些很是簡單的配置,若是想實現更加細粒度的日誌配置,那就須要使用日誌實現的原生配置,例如 Logbackclasspath:logback.xmlLog4jclasspath:log4j.xml 等。若是這些日誌配置文件存在於 classpath 下,那麼默認狀況下,Spring Boot 就會自動加載這些配置文件。

2.2 Logback 配置

2.2.1 基本配置

默認的 Logback 配置文件名有兩種:

  • logback.xml:這種配置文件會直接被日誌框架加載。
  • logback-spring.xml:這種配置文件不會被日誌框架直接加載,而是由 Spring Boot 去解析日誌配置,可使用 Spring Boot 的高級 Profile 功能。

Spring Boot 中爲 Logback 提供了四個默認的配置文件,位置在 org/springframework/boot/logging/logback/,分別是:

  • defaults.xml:提供了公共的日誌配置,日誌輸出規則等。
  • console-appender.xml:使用 CONSOLE_LOG_PATTERN 添加一個ConsoleAppender。
  • file-appender.xml:添加一個 RollingFileAppender。
  • base.xml:爲了兼容舊版 Spring Boot 而提供的。

若是須要自定義 logback.xml 文件,能夠在自定義時使用這些默認的配置文件,也能夠不使用。一個典型的 logback.xml 文件以下(resources/logback.xml):

<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
    <logger name="org.springframework.web" level="DEBUG" />
</configuration>

能夠經過 include 引入 Spring Boot 已經提供的配置文件,也能夠自定義。

2.2.2 輸出到文件

若是想禁止控制檯的日誌輸出,轉而將日誌內容輸出到一個文件,咱們能夠自定義一個 logback-spring.xml 文件,並引入前面所說的 file-appender.xml 文件。

像下面這樣(resources/logback-spring.xml):

<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}" />
    <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
    <root level="INFO">
        <appender-ref ref="FILE" />
    </root>
</configuration>

2.3 Log4j 配置

若是 classpath 下存在 Log4j2 的依賴,Spring Boot 會自動進行配置。

默認狀況下 classpath 下固然不存在 Log4j2 的依賴,若是想使用 Log4j2,能夠排除已有的 Logback,而後再引入 Log4j2,以下:

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-web</artifactid>
    <exclusions>
        <exclusion>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-logging</artifactid>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-log4j2</artifactid>
</dependency>

Log4j2 的配置就比較容易了,在 reources 目錄下新建 log4j2.xml 文件,內容以下:

<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration status="warn">
    <properties>
        <property name="app_name">logging</property>
        <property name="log_path">logs/${app_name}</property>
    </properties>
    <appenders>
        <console name="Console" target="SYSTEM_OUT">
            <patternlayout pattern="[%d][%t][%p][%l] %m%n" />
        </console>
        <rollingfile name="RollingFileInfo" filename="${log_path}/info.log" filepattern="${log_path}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
            <filters>
                <thresholdfilter level="INFO" />
                <thresholdfilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL" />
            </filters>
            <patternlayout pattern="[%d][%t][%p][%c:%L] %m%n" />
            <policies>
                <timebasedtriggeringpolicy interval="1" modulate="true" />
                <sizebasedtriggeringpolicy size="2 MB" />
            </policies>
            <defaultrolloverstrategy compressionLevel="0" max="10" />
        </rollingfile>
        <rollingfile name="RollingFileWarn" filename="${log_path}/warn.log" filepattern="${log_path}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz">
            <filters>
                <thresholdfilter level="WARN" />
                <thresholdfilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL" />
            </filters>
            <patternlayout pattern="[%d][%t][%p][%c:%L] %m%n" />
            <policies>
                <timebasedtriggeringpolicy interval="1" modulate="true" />
                <sizebasedtriggeringpolicy size="2 MB" />
            </policies>
            <defaultrolloverstrategy compressionLevel="0" max="10" />
        </rollingfile>

        <rollingfile name="RollingFileError" filename="${log_path}/error.log" filepattern="${log_path}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
            <thresholdfilter level="ERROR" />
            <patternlayout pattern="[%d][%t][%p][%c:%L] %m%n" />
            <policies>
                <timebasedtriggeringpolicy interval="1" modulate="true" />
                <sizebasedtriggeringpolicy size="2 MB" />
            </policies>
            <defaultrolloverstrategy compressionLevel="0" max="10" />
        </rollingfile>
    </appenders>
    <loggers>
        <root level="info">
            <appender-ref ref="Console" />
            <appender-ref ref="RollingFileInfo" />
            <appender-ref ref="RollingFileWarn" />
            <appender-ref ref="RollingFileError" />
        </root>
    </loggers>
</configuration>

首先在 properties 節點中指定了應用名稱以及日誌文件位置。

而後經過幾個不一樣的 RollingFile 對不一樣級別的日誌分別處理,不一樣級別的日誌將輸出到不一樣的文件,並按照各自的命名方式進行壓縮。

這段配置比較程式化,小夥伴們能夠保存下來作成 IntelliJ IDEA 模版以便平常使用。

3.小結

好啦,這就是鬆哥和小夥伴們分享的 Spring Boot 日誌了,總體來講並不難,小夥伴們能夠仔細品一品。

最後,鬆哥還蒐集了 50+ 個項目需求文檔,想作個項目練練手的小夥伴不妨看看哦~

需求文檔地址:https://gitee.com/lenve/javadoc</config-file-name>

相關文章
相關標籤/搜索