<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          忽視日志吃大虧,手把手教你玩轉(zhuǎn) SpringBoot 日志

          共 22752字,需瀏覽 46分鐘

           ·

          2023-10-06 21:37

          一、日志重要嗎

          程序中的日志重要嗎? 在回答這個(gè)問(wèn)題前,筆者先說(shuō)個(gè)事例:

          ?

          筆者印象尤深的就是去年某個(gè)同事,收到了客戶(hù)反饋的緊急bug。盡管申請(qǐng)到了日志文件,但因?yàn)楹芏嚓P(guān)鍵步驟沒(méi)有打印日志,導(dǎo)致排查進(jìn)度很慢,數(shù)個(gè)小時(shí)都沒(méi)能排查到問(wèn)題,也無(wú)法給出解決對(duì)策。導(dǎo)致了客戶(hù)程序一直阻斷,最終產(chǎn)生了不少損失。 事后,經(jīng)過(guò)仔細(xì)推敲,成功復(fù)現(xiàn)了這個(gè)bug,其實(shí)是一個(gè)很不起眼的數(shù)據(jù)轉(zhuǎn)換導(dǎo)致的。可因?yàn)槿罩緝?nèi)容的匱乏,排查起來(lái)難度很大。其實(shí)只要在數(shù)據(jù)轉(zhuǎn)換前后進(jìn)行日志輸出,這個(gè)問(wèn)題就是一眼的事。但可惜沒(méi)如果,故事的最后,開(kāi)發(fā)部門(mén)還是遭到了客戶(hù)的投訴,影響到了部門(mén)績(jī)效

          ?

          對(duì)于剛學(xué)習(xí)編程的同學(xué),很多人都對(duì)日志滿不在乎,我們?cè)谧鯿ode review的時(shí)候,經(jīng)常發(fā)現(xiàn)一些新同學(xué)喜歡一個(gè)方法寫(xiě)得很長(zhǎng),然后中間的注釋和日志都少的可憐。

          坦白的說(shuō),這是很不好的習(xí)慣,這意味著日后方法出了bug,或者需要迭代,要花費(fèi)大量時(shí)間來(lái)理清方法的思路。千萬(wàn)別迷信什么“方法名、字段名起的見(jiàn)明知意,就可以不寫(xiě)注釋與日志”,那是他們的業(yè)務(wù)場(chǎng)景不夠復(fù)雜。以筆者為例,復(fù)雜的場(chǎng)景涉及很多公式、奇特的規(guī)定,不寫(xiě)注釋與日志,后續(xù)沒(méi)人能維護(hù)得了

          所以請(qǐng)務(wù)必記住,日志在開(kāi)發(fā)過(guò)程中非常重要。它可以幫助開(kāi)發(fā)人員了解程序中發(fā)生了什么,以及在某些情況下為什么會(huì)發(fā)生錯(cuò)誤或異常。通過(guò)查看日志,開(kāi)發(fā)人員可以輕松地定位并解決問(wèn)題,并且可以更好地監(jiān)控和調(diào)整應(yīng)用程序的性能,在必要時(shí)進(jìn)行故障排除和安全檢查

          二、日志分級(jí)

          最開(kāi)始的日志分級(jí)是由Syslog的開(kāi)發(fā)者Eric Allman在1981年提出的。之后,這個(gè)級(jí)別分級(jí)系統(tǒng)被廣泛應(yīng)用于各種領(lǐng)域的日志記錄和信息處理中。下面我們就來(lái)介紹下常用的日志等級(jí)

          • TRACE

          是最低級(jí)別的日志記錄,用于輸出最詳細(xì)的調(diào)試信息,通常用于開(kāi)發(fā)調(diào)試目的。在生產(chǎn)環(huán)境中,應(yīng)該關(guān)閉 TRACE 級(jí)別的日志記錄,以避免輸出過(guò)多無(wú)用信息。

          • DEBUG

          是用于輸出程序中的一些調(diào)試信息,通常用于開(kāi)發(fā)過(guò)程中。像 TRACE 一樣,在生產(chǎn)環(huán)境中應(yīng)該關(guān)閉 DEBUG 級(jí)別的日志記錄。

          • INFO

          用于輸出程序正常運(yùn)行時(shí)的一些關(guān)鍵信息,比如程序的啟動(dòng)、運(yùn)行日志等。通常在生產(chǎn)環(huán)境中開(kāi)啟 INFO 級(jí)別的日志記錄。

          • WARN

          是用于輸出一些警告信息,提示程序可能會(huì)出現(xiàn)一些異常或者錯(cuò)誤。在應(yīng)用程序中,WARN 級(jí)別的日志記錄通常用于記錄一些非致命性異常信息,以便能夠及時(shí)發(fā)現(xiàn)并處理這些問(wèn)題。

          • ERROR

          是用于輸出程序運(yùn)行時(shí)的一些錯(cuò)誤信息,通常表示程序出現(xiàn)了一些不可預(yù)料的錯(cuò)誤。在應(yīng)用程序中,ERROR 級(jí)別的日志記錄通常用于記錄一些致命性的異常信息,以便能夠及時(shí)發(fā)現(xiàn)并處理這些問(wèn)題。

          當(dāng)然,除了這五種級(jí)別以外,還有一些日志框架定義了其他級(jí)別,例如 Python 中的 CRITICAL、PHP 中的 FATAL 等。CRITICAL 和 FATAL 都是用于表示程序出現(xiàn)了致命性錯(cuò)誤或者異常,即不可恢復(fù)的錯(cuò)誤。當(dāng)然,對(duì)于我們今天要說(shuō)的內(nèi)容,知道上述五種日志等級(jí)就夠了。

          三、常用日志插件

          1. Log4j(1999年誕生)

          Log4j 是Java領(lǐng)域中最早的流行日志框架之一。它由Ceki Gülcü開(kāi)發(fā),并后來(lái)由Apache軟件基金會(huì)接管。Log4j 提供了靈活的配置選項(xiàng)、多種輸出目的地、日志級(jí)別和分層日志體系。盡管Log4j 1在其時(shí)代取得了巨大的成功,但在性能和某些功能方面存在限制,因此后來(lái)演化為L(zhǎng)og4j 2。

          1. SLF4J(2004年誕生)

          嚴(yán)格來(lái)說(shuō),SLF4J(Simple Logging Facade for Java)并不算一個(gè)插件,而是Ceki Gülcü開(kāi)發(fā)的一個(gè)日志門(mén)面接口。它為Java應(yīng)用程序提供了統(tǒng)一的日志抽象,使開(kāi)發(fā)人員可以使用一致的API進(jìn)行日志記錄,而不需要直接依賴(lài)于特定的日志實(shí)現(xiàn)。SLF4J 可以與多種底層日志框架(如Logback、Log4j 2、java.util.logging等)結(jié)合使用。

          1. Logback(2009年誕生)

          Logback 是Ceki Gülcü開(kāi)發(fā)的日志框架,他也是Log4j的作者。Logback 是Log4j 1的后續(xù)版本,旨在提供更高性能、更靈活的配置和現(xiàn)代化的日志解決方案。Logback 支持異步日志記錄、多種輸出格式、靈活的配置以及與SLF4J緊密集成。

          1. Log4j 2(2014年誕生)

          Log4j 2 是Apache軟件基金會(huì)開(kāi)發(fā)的Log4j的下一代版本。它引入了許多新特性,如異步日志記錄、插件支持、豐富的過(guò)濾器等,旨在提供更好的性能和靈活性。Log4j 2 在設(shè)計(jì)上考慮了Log4j 1的局限性,并且支持多種配置方式。

          1. 小故事

          不難注意到,一個(gè)有意思的小故事是,前三款日志插件都是Ceki Gülcü開(kāi)發(fā)的,但 Log4j 2 并不是,雖然現(xiàn)在有很多人以為log4j2也是他寫(xiě)的,但我們?cè)趃ithub上可以看到其個(gè)人說(shuō)明 “Unaffiliated with log4j 2.x.” (與 log4j 2.x 無(wú)關(guān)),所以log4j2 和 logback 都自稱(chēng)是log4j 的后續(xù)版本,到底誰(shuí)才算正統(tǒng)續(xù)作呢?這就留給各位讀者自己玩味了

          四、外觀模式與SLF4J

          在講解更多插件詳情之前,我們先來(lái)看看使用最多的SLF4J ,我們前面說(shuō)了 SLF4J(Simple Logging Facade for Java)是Ceki Gülcü開(kāi)發(fā)的一個(gè)日志門(mén)面接口,那么很顯然這里就用到了門(mén)面模式(即Facade 或 外觀模式),筆者比較習(xí)慣說(shuō)成是外觀模式,后續(xù)就稱(chēng)為外觀模式。

          1. 外觀模式

          定義:外觀模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,它提供了一個(gè)簡(jiǎn)單的接口,封裝了底層復(fù)雜的子系統(tǒng),使得客戶(hù)端可以更方便地使用這個(gè)子系統(tǒng)

          目的:外觀模式的目的是隱藏底層系統(tǒng)的復(fù)雜性,降低訪問(wèn)成本。

          如果說(shuō)看定義有些抽象,那我們可以以生活中的例子來(lái)說(shuō),我們都知道現(xiàn)在越來(lái)越流行智能家居,也就是家庭內(nèi)裝了很多智能家電,從電視、空調(diào)、到廊燈甚至窗簾都是智能的。這類(lèi)家庭往往會(huì)有一個(gè)控制中心,我們不需要手動(dòng)去開(kāi)電視,只需要對(duì)著控制中心說(shuō):“小A小A,幫我打開(kāi)電視,音量調(diào)到30%”,電視就會(huì)應(yīng)聲打開(kāi)并調(diào)節(jié)音量

          那么這樣的話,我們不需要知道怎么開(kāi)電視,怎么調(diào)音量。通通都能用最簡(jiǎn)單的話語(yǔ)來(lái)調(diào)節(jié)。同理,現(xiàn)在手機(jī)上的拍照功能:感光度,對(duì)焦,白平衡這些細(xì)節(jié)都給你自動(dòng)完成了,所以這些復(fù)雜的內(nèi)容你現(xiàn)在根本不用管,只需要猛按拍照鍵即可。

          這就是外觀模式的意義,外觀模式就是為了隱藏系統(tǒng)的復(fù)雜性而設(shè)計(jì)出來(lái)的,讓客戶(hù)端只對(duì)接觸到一個(gè)外觀類(lèi),而不會(huì)接觸到系統(tǒng)內(nèi)部的復(fù)雜邏輯

          2. SLF4J 的誕生

          在早期使用日志框架時(shí),應(yīng)用程序通常需要直接與具體的日志框架進(jìn)行耦合,這就導(dǎo)致了以下幾個(gè)問(wèn)題:

          • 代碼依賴(lài)性

          應(yīng)用程序需要直接引用具體的日志框架,從而導(dǎo)致代碼與日志框架強(qiáng)耦合,難以滿足應(yīng)用程序?qū)θ罩究蚣艿撵`活配置。

          • 日志框架不統(tǒng)一

          在使用不同的日志框架時(shí),應(yīng)用程序需要根據(jù)具體的日志框架來(lái)編寫(xiě)代碼,這不僅會(huì)增加開(kāi)發(fā)難度,而且在多種日志框架中切換時(shí)需要進(jìn)行大量的代碼改動(dòng)。

          • 性能問(wèn)題

          在日志輸出頻繁的情況下,由于日志框架的實(shí)現(xiàn)方式和API設(shè)計(jì)不同,可能會(huì)導(dǎo)致性能問(wèn)題。

          為了解決這些問(wèn)題,SLF4J提供了一套通用的日志門(mén)面接口,讓?xiě)?yīng)用程序可以通過(guò)這些接口來(lái)記錄日志信息,而不需要直接引用具體的日志框架。這樣,應(yīng)用程序就可以在不同的日志框架之間進(jìn)行靈活配置和切換,同時(shí)還可以獲得更好的性能表現(xiàn)。所以,我強(qiáng)烈建議各位使用SLF4J, 而不是直接對(duì)接某個(gè)具體的日志框架。

          3. SLF4J 的使用

          首先,我們需要在工程內(nèi)引入包,但是如果你用了springboot,各種 spring-boot-starter 啟動(dòng)器已經(jīng)引用過(guò)了,所以引用前最好確認(rèn)下:

          <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.32</version>
          </dependency>

          然后在我們要打印日志的類(lèi)里加上一行 ;private static final Logger logger = LoggerFactory.getLogger(XXXX.class); 即可使用,如下:

          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;

          public class MyClass {
              private static final Logger log = LoggerFactory.getLogger(MyClass.class);
              //...
              public static void main(String[] args) {
                  log.info("This is an info message.");
              }
          }

          如果我們引用了lombok的話,也可以使用lombok的注解@Slf4j 代替上面那句話來(lái)使用 SLF4J ,如下:

          import lombok.extern.slf4j.Slf4j;

          @Slf4j
          public class MyClass {
              public static void main(String[] args) {
                  log.info("This is an info message.");
              }
          }

          但是,我們都知道SLF4J僅僅是個(gè)門(mén)面,換句話說(shuō),僅有接口而沒(méi)有實(shí)現(xiàn),如果此刻我們直接運(yùn)行,打印日志是沒(méi)有用處的

          所以,我們?nèi)绻\(yùn)行,我們必須要給 SLF4J 安排上實(shí)現(xiàn),而目前最常用的就是 logback 和 log4j2 了,就讓我們接著往下看

          五、雙雄之爭(zhēng)

          其實(shí)關(guān)于 Logback 和 Log4j 2,網(wǎng)絡(luò)上有很多評(píng)測(cè),就不需贅述了,主要是圍繞性能方面的,從目前大家的反饋看,Log4j 2 晚出現(xiàn)好幾年,還是有后發(fā)優(yōu)勢(shì)的,性能會(huì)比 Logback 好。當(dāng)然, Logback 本身性能也很強(qiáng),對(duì)于大多數(shù)場(chǎng)景,完全是夠用的,而且配置比較直觀,是spring-boot 默認(rèn)使用的日志插件。

          所以,選誰(shuí)都可以,如果不想費(fèi)神,可以直接使用spring-boot自帶的Logback,如果對(duì)日志性能要求很高,使用log4j2更保險(xiǎn),我們接下來(lái)分別介紹兩者。

          1. Logback

          1. 引用

          由于 Logback 為 spring-boot 默認(rèn)日志框架,所以無(wú)需再引用,但對(duì)于非spring - boot 項(xiàng)目,可以做如下引用

          <dependency>
              <groupId>ch.qos.logback</groupId>
              <artifactId>logback-classic</artifactId>
              <version>1.2.12</version>
          </dependency>

          Logback 的核心模塊為 logback-classic,它提供了一個(gè) SLF4J 的實(shí)現(xiàn),兼容 Log4j API,可以無(wú)縫地替換 Log4j。它自身已經(jīng)包含了 logback-core 模塊,而 logback-core,顧名思義就是 logback 的核心功能,包括日志記錄器、Appender、Layout 等。其他 logback 模塊都依賴(lài)于該模塊

          2. 配置

          logback 可以通過(guò) XML 或者 Groovy 配置。下面以 XML 配置為例。logback 的 XML 配置文件名稱(chēng)通常為 logback.xml 或者 logback-spring.xml(在 Spring Boot 中),需要放置在 classpath 的根目錄下,

          <?xml version="1.0" encoding="UTF-8"?>
          <configuration>
              <!--定義日志文件的存儲(chǔ)地址,使用Spring的屬性文件配置方式-->
              <springProperty scope="context" name="log.home" source="log.home" defaultValue="logs"/>

              <!--定義日志文件的路徑-->
              <property name="LOG_PATH" value="${log.home}"/>

              <!--定義控制臺(tái)輸出-->
              <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
                  <encoder>
                      <pattern>%-5relative [%thread] %-5level %logger{35} - %msg%n</pattern>
                  </encoder>
              </appender>

              <!--定義 INFO 及以上級(jí)別信息輸出到控制臺(tái)-->
              <root level="INFO">
                  <appender-ref ref="console"/>
              </root>

              <!--定義所有組件的日志級(jí)別,如所有 DEBUG-->
              <logger name="com.example" level="DEBUG"/>

              <!-- date 格式定義 -->
              <property name="LOG_DATEFORMAT" value="yyyy-MM-dd"/>

              <!-- 定義日志歸檔文件名稱(chēng)格式,每天生成一個(gè)日志文件 -->
              <property name="ARCHIVE_PATTERN" value="${LOG_PATH}/%d{${LOG_DATEFORMAT}}/app-%d{${LOG_DATEFORMAT}}-%i.log.gz"/>

              <!--定義文件輸出,會(huì)根據(jù)定義的閾值進(jìn)行切割,支持自動(dòng)歸檔壓縮過(guò)期日志-->
              <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
                  <file>${LOG_PATH}/app.log</file>
                  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                      <!--定義日志文件切割的閾值,本例是 50MB-->
                      <maxFileSize>50MB</maxFileSize>
                      <!--定義日志文件保留時(shí)間,本例是每天生成一個(gè)日志文件-->
                      <fileNamePattern>${ARCHIVE_PATTERN}</fileNamePattern>
                      <maxHistory>30</maxHistory>
                      <!-- zip 壓縮生成的歸檔文件 -->
                      <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                          <maxFileSize>50MB</maxFileSize>
                      </timeBasedFileNamingAndTriggeringPolicy>
                      <!-- 刪除過(guò)期文件 -->
                      <cleanHistoryOnStart>true</cleanHistoryOnStart>
                  </rollingPolicy>
                  <encoder>
                      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n</pattern>
                  </encoder>
              </appender>

              <!--定義 ERROR 級(jí)別以上信息輸出到文件-->
              <logger name="com.example.demo" level="ERROR" additivity="false">
                  <appender-ref ref="file"/>
              </logger>

              <!--異步輸出日志信息-->
              <appender name="asyncFile" class="ch.qos.logback.classic.AsyncAppender">
                  <discardingThreshold>0</discardingThreshold>
                  <queueSize>256</queueSize>
                  <appender-ref ref="file"/>
              </appender>

              <!--定義INFO及以上級(jí)別信息異步輸出到文件-->
              <logger name="com.example" level="INFO" additivity="false">
                  <appender-ref ref="asyncFile"/>
              </logger>

          </configuration>

          其中,主要包括以下配置:

          • springProperty 定義了 log 文件的存儲(chǔ)路徑,可以通過(guò) Spring 的屬性文件配置方式進(jìn)行設(shè)置,如果沒(méi)有配置則默認(rèn)存儲(chǔ)在 logs 目錄下。
          • appender 定義了日志輸出的目標(biāo),這里包括了控制臺(tái)輸出和文件輸出兩種,具體可以根據(jù)需求進(jìn)行配置。
          • root 定義了默認(rèn)的日志級(jí)別和輸出目標(biāo),默認(rèn)情況下,INFO 級(jí)別以上的日志信息會(huì)輸出到控制臺(tái),可以根據(jù)實(shí)際需求進(jìn)行修改。
          • logger 定義了不同組件的日志級(jí)別和輸出目標(biāo),例如,這里定義了 com.example 這個(gè)組件的日志級(jí)別為 DEBUG,而 com.example.demo 這個(gè)組件的日志級(jí)別為 ERROR,并將其輸出到文件中。
          • rollingPolicy 定義了日志文件的切割規(guī)則和歸檔策略,此處定義了日志文件每個(gè) 50MB 進(jìn)行切割,每天生成一個(gè)日志文件,并且壓縮和刪除過(guò)期文件,最多保留 30 天的日志文件。
          • encoder 定義了日志信息的輸出格式,具體的格式可以自行定義。
          • asyncAppender 定義了異步輸出日志的方式,對(duì)于高并發(fā)時(shí),可以使用異步輸出來(lái)提高系統(tǒng)的性能。
          • discardingThreshold 定義了異步輸出隊(duì)列的閾值,當(dāng)隊(duì)列中的數(shù)據(jù)量超過(guò)此值時(shí),會(huì)丟棄最早放入的數(shù)據(jù),此處設(shè)置為 0 表示隊(duì)列不會(huì)丟棄任何數(shù)據(jù)。
          • queueSize 定義了異步輸出隊(duì)列的大小,當(dāng)隊(duì)列滿時(shí),會(huì)等待隊(duì)列中的數(shù)據(jù)被消費(fèi)后再將數(shù)據(jù)放入隊(duì)列中,此處設(shè)置為 256。
          3. 演示

          我們新建一個(gè)普通工程(非spring工程),引用Logback后,把上述配置文件復(fù)制進(jìn)logback.xml,然后將工程結(jié)構(gòu)設(shè)置成如下模式

          其中兩個(gè)類(lèi)的代碼如下:

          public class Main {
              private static final Logger log = LoggerFactory.getLogger(Main.class);
              public static void main(String[] args) {
                  log.trace("This is a Main trace message.");
                  log.debug("This is a Main debug message.");
                  log.info("This is a Main info message.");
                  log.warn("This is a Main warn message.");
                  log.error("This is a Main error message.");
                  Slave.main(args);
              }
          }

          public class Slave {
              private static final Logger log = LoggerFactory.getLogger(Slave.class);
              public static void main(String[] args) {
                  log.trace("This is a Slave trace message.");
                  log.debug("This is a Slave debug message.");
                  log.info("This is a Slave info message.");
                  log.warn("This is a Slave warn message.");
                  log.error("This is a Slave error message.");
              }
          }

          我們想實(shí)現(xiàn)這樣的效果,首先日志要同時(shí) 輸出到控制臺(tái) 及 日志文件,且不同層級(jí)的代碼,輸出的日志層級(jí)也不同。那么我們可以對(duì)上述的xml做出一些調(diào)整:

          因?yàn)槭欠荢pring項(xiàng)目,所以 springProperty 這樣的標(biāo)簽就不要用了,我們直接寫(xiě)死一個(gè)日志文件地址即可。

          <!--定義日志文件的路徑-->
          <property name="LOG_PATH" value="D://logs/log"/>

          去掉原有的那些root、logger標(biāo)簽,我們自己新建兩個(gè)logger,用于兩個(gè)不同的層級(jí)。我們想里層輸出 debug 級(jí)別,外層輸出info 級(jí)別,我們可以這么設(shè)置。并且同時(shí)輸出到控制臺(tái)及日志文件

          <logger name="com.zhanfu" level="INFO">
              <appender-ref ref="file" />
              <appender-ref ref="console"/>
          </logger>
          <logger name="com.zhanfu.child" level="DEBUG" additivity="false">
              <appender-ref ref="file" />
              <appender-ref ref="console"/>
          </logger>

          當(dāng)我們運(yùn)行Main.main的時(shí)候,就可以得到以下日志,slave 能輸出debug級(jí)別,Main 只能輸出 info及以上級(jí)別

          4. 細(xì)節(jié)點(diǎn)

          其實(shí)我們上面的演示,有兩個(gè)細(xì)節(jié)點(diǎn),需要注意一下。一個(gè)就是我們的

           <logger name="com.zhanfu.child" level="DEBUG" additivity="false">

          使用了一個(gè) additivity="false" 的屬性,這其實(shí)是因?yàn)?logger 這個(gè)標(biāo)簽在鎖定某個(gè)目錄時(shí),可能會(huì)發(fā)生層級(jí)關(guān)系。比如我們的兩個(gè) logger, 一個(gè)針對(duì)的目錄是 com.zhanfu 另一個(gè)是 com.zhanfu.child ,后者就會(huì)被前者包含。

          當(dāng)我們的 com.zhanfu.child.Slave 打印日志時(shí),當(dāng)然會(huì)使用后者(更精確)的設(shè)置,但前者的設(shè)置還使用嗎?就依賴(lài)于 additivity=“false”,此處如果我們把 additivity="false" (該屬性默認(rèn)值為true)去掉,再來(lái)打印日志

          就會(huì)發(fā)現(xiàn),Slave 的日志打了兩遍,而且連 debug 級(jí)別的都打了兩遍,我們可以把這種邏輯理解為繼承,子類(lèi)執(zhí)行一遍,父類(lèi)還能在執(zhí)行一遍,但 leve 屬性還是會(huì)采用子類(lèi)而非父類(lèi)的。

          另一點(diǎn)就是我們把 root 標(biāo)簽刪除了,root 其實(shí)是一個(gè)頂級(jí)的 logger , 其他的logger都可以視為它的子類(lèi),如果那些logger存在沒(méi)涵蓋的地方,或其沒(méi)有指定 additivity="false" ,那最后root的設(shè)置就會(huì)被使用。比如我們將設(shè)置改為如下:

          <logger name="com.zhanfu" level="INFO">
              <appender-ref ref="file" />
              <appender-ref ref="console"/>
          </logger>
          <logger name="com.zhanfu.child" level="DEBUG">
              <appender-ref ref="file" />
              <appender-ref ref="console"/>
          </logger>
          <root level="WARN">
              <appender-ref ref="console"/>
          </root>

          結(jié)果控制臺(tái)的輸出日志,Main會(huì)重復(fù)兩次,Slave 會(huì)重復(fù)三次,如下

          但是因?yàn)槲覀兊?root 只配置了控制臺(tái)輸出,所以日志文件里還是不會(huì)變的

          2. Log4j 2

          1. 引用

          對(duì)于spring-boot項(xiàng)目,除了引用 Log4j 2 我們還需要先剔除 Logback 的引用,對(duì)于普通項(xiàng)目,我們只需直接引用即可。但注意我們的原則,通過(guò) SLF4J 來(lái)使用 Log4j2,所以引用下面這個(gè)包

          <dependency>
               <groupId>org.apache.logging.log4j</groupId>
               <artifactId>log4j-slf4j-impl</artifactId>
               <version>2.13.3</version>
          </dependency>

          其內(nèi)包含 Log4j2 的實(shí)現(xiàn),和 SLF4J 的 API,如下:

          2. 配置

          Log4j2 的配置邏輯和 logback 是類(lèi)似的,只有些細(xì)節(jié)不同,比如Logger 的首字母大寫(xiě)等等,最后我們寫(xiě)下這樣一個(gè) log4j2.xml

          <?xml version="1.0" encoding="UTF-8"?>
          <Configuration status="INFO" monitorInterval="30">
            <Properties>
              <Property name="logPath">logs</Property>
            </Properties>
            <Appenders>
              <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{ISO8601} [%t] %-5level %logger{36} - %msg%n" />
              </Console>
              <RollingFile name="File" fileName="${logPath}/example.log"
                           filePattern="${logPath}/example-%d{yyyy-MM-dd}-%i.log">

                <PatternLayout pattern="%d{ISO8601} [%t] %-5level %logger{36} - %msg%n"/>
                <Policies>
                  <SizeBasedTriggeringPolicy size="10 MB"/>
                </Policies>
                <DefaultRolloverStrategy max="4"/>
              </RollingFile>
            </Appenders>
            <Loggers>
              <Logger name="com.zhanfu.child" level="DEBUG">
                <AppenderRef ref="File"/>
                <AppenderRef ref="Console"/>
              </Logger>
              <Logger name="com.zhanfu" level="INFO">
                <AppenderRef ref="File"/>
                <AppenderRef ref="Console"/>
              </Logger>
              <Root level="WARN">
                <AppenderRef ref="Console" />
              </Root>
            </Loggers>
          </Configuration>
          • Properties

          部分定義了一個(gè) logPath 屬性,方便在其他地方引用。

          • Appenders

          定義了兩個(gè) Appender:Console 和 RollingFile,分別將日志輸出到控制臺(tái)和文件中。RollingFile 使用了 RollingFileAppender,并設(shè)置了日志滾動(dòng)策略和默認(rèn)的備份文件數(shù)量。

          • Loggers

          定義了三個(gè) Logger:com.zhanfu.child 的日志級(jí)別為 DEBUG,com.zhanfu 的日志級(jí)別為INFO,Root Logger 的日志級(jí)別為 WARN。并指定了兩個(gè) Appender:Console 和 File。

          3. 演示

          由于我們的配置邏輯沒(méi)變,所以日志的結(jié)果還是一樣的:

          3. 對(duì)比

          Log4j2和Logback都是Java應(yīng)用程序中最流行的日志框架之一。它們均具備高度的可配置性和使用靈活性,并提供了一系列有用的功能,例如異步日志記錄和日志過(guò)濾等。下面從配置遍歷性、功能性、性能等方面進(jìn)行比較和總結(jié)。

          配置遍歷性

          Logback的配置文件格式相對(duì)簡(jiǎn)單,易于閱讀和修改。它支持符號(hào)來(lái)引用變量、屬性和環(huán)境變量等。此外,它還支持條件日志記錄(根據(jù)日志級(jí)別、日志記錄器名稱(chēng)或時(shí)間等),以及滾動(dòng)文件的大小或日期等。

          Log4j2的配置文件格式較復(fù)雜,但它在配置文件中提供了大量的選項(xiàng)來(lái)控制日志記錄。它支持在配置文件中直接聲明上下文參數(shù)、過(guò)濾器、輸出器和Appender等,這使得它的配置更加靈活。此外,Log4j2還支持異步日志記錄、日志事件序列化和性能優(yōu)化等。

          總體來(lái)說(shuō),兩者都很好地支持了配置遍歷性,但Log4j2提供了更多的選項(xiàng)和更高的靈活性。

          功能性

          Logback提供了一系列基本的日志記錄功能,例如異步Appender、滾動(dòng)文件和GZIP壓縮等。它還支持與SLF4J一起使用,可以很容易地與其他日志框架集成。

          Log4j2提供了更多的高級(jí)功能,例如異步日志記錄、性能優(yōu)化和日志事件序列化等。它還支持Lambda表達(dá)式,可以使日志記錄器更加簡(jiǎn)潔和易讀。此外,Log4j2還支持Flume和Kafka等大數(shù)據(jù)處理框架,可以方便地將日志記錄發(fā)送到這些框架中。

          總體來(lái)說(shuō),Log4j2提供了更多的高級(jí)功能,并且可以更好地與大數(shù)據(jù)處理框架集成。

          性能

          Logback的性能很好,可以處理高吞吐量的日志記錄。它采用了異步記錄器,利用了多線程來(lái)提高性能。

          Log4j2在性能方面更加強(qiáng)大。它使用了異步記錄器和多線程,還引入了RingBuffer數(shù)據(jù)結(jié)構(gòu)和Disruptor庫(kù)來(lái)加速日志事件的傳遞和處理。這使得它比Logback具有更高的吞吐量和更低的延遲。

          綜上所述,Log4j2在配置靈活性、功能性和性能方面都比Logback更為強(qiáng)大。但如果需要輕量級(jí)的日志框架或者只需要基本的日志記錄功能,Logback也是一個(gè)不錯(cuò)的選擇

          但如果我們同時(shí)引用了這兩者,會(huì)報(bào)錯(cuò)嗎?還是會(huì)使用其中的某一個(gè)?

           <dependency>
              <groupId>ch.qos.logback</groupId>
              <artifactId>logback-classic</artifactId>
              <version>1.2.12</version>
          </dependency>
          <dependency>
              <groupId>org.apache.logging.log4j</groupId>
              <artifactId>log4j-slf4j-impl</artifactId>
              <version>2.13.3</version>
          </dependency>

          可以看到,SLF4J 發(fā)現(xiàn)了系統(tǒng)中同時(shí)存在兩個(gè)插件框架,并最終選擇了使用 Logback

          總結(jié)

          學(xué)習(xí)完本文,你應(yīng)當(dāng)對(duì)現(xiàn)在這幾個(gè)常用框架的有所了解,并能基礎(chǔ)應(yīng)用了。此次我們沒(méi)有講源碼,也沒(méi)有深入的講其配置及進(jìn)階使用,這些我們會(huì)在后面慢慢學(xué)習(xí)。但現(xiàn)在我希望你能知道的是。一定要寫(xiě)好日志,一定要寫(xiě)好日志,一定要寫(xiě)好日志。重要的事情說(shuō)三遍!這是區(qū)別新人和老鳥(niǎo)的一個(gè)重要依據(jù),也是讓自己排查問(wèn)題更輕松的不二法門(mén)!

          另外,現(xiàn)在很多中間件都自己引用了日志插件,我們作為一個(gè)整體工程在使用中間件時(shí),要及時(shí)發(fā)現(xiàn)并解決插件沖突,避免我們自己的日志配置失效,這也是一個(gè)程序員該注意的點(diǎn)。

          來(lái)源:blog.csdn.net/u011709538/
          article/details/132363370


          到此文章就結(jié)束了。Java架構(gòu)師必看一個(gè)集公眾號(hào)、小程序、網(wǎng)站(3合1的文章平臺(tái),給您架構(gòu)路上一臂之力)。如果今天的文章對(duì)你在進(jìn)階架構(gòu)師的路上有新的啟發(fā)和進(jìn)步,歡迎轉(zhuǎn)發(fā)給更多人。歡迎加入架構(gòu)師社區(qū)技術(shù)交流群,眾多大咖帶你進(jìn)階架構(gòu)師,在后臺(tái)回復(fù)“加群”即可入群。



          這些年小編給你分享過(guò)的干貨


          1.idea永久激活碼(親測(cè)可用)

          2.優(yōu)質(zhì)ERP系統(tǒng)帶進(jìn)銷(xiāo)存財(cái)務(wù)生產(chǎn)功能(附源碼)

          3.優(yōu)質(zhì)SpringBoot帶工作流管理項(xiàng)目(附源碼)

          4.最好用的OA系統(tǒng),拿來(lái)即用(附源碼)

          5.SBoot+Vue外賣(mài)系統(tǒng)前后端都有(附源碼

          6.SBoot+Vue可視化大屏拖拽項(xiàng)目(附源碼)


          轉(zhuǎn)發(fā)在看就是最大的支持??

          瀏覽 690
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美爱爱视频免费看 | 国产91人妻 | 天天添天天操 | 欧美一级看片a免费观看 | 色呦呦一区二区三区 |