java 日志框架Spring Boot分析
引言:我們需要在已有的微服務(wù)代碼中添加日志功能,用于輸出需要關(guān)注的內(nèi)容,這是最平常的技術(shù)需求了。由于我們的微服務(wù)代碼是基于SpringBoot開發(fā)的,那么問題就轉(zhuǎn)換為如何在Spring Boot應(yīng)用程序中輸出相應(yīng)的日志。
在傳統(tǒng)Java應(yīng)用程序中,我們一般會使用類似Log4j這樣的日志框架來輸出日志,而不是直接在代碼中通過System.out.println()來輸出日志。為什么要這么做呢?原因有兩點。其一,我們希望日志能輸出到文件中,而不是輸出到應(yīng)用程序的控制臺中,這樣更加容易收集和分析。其二,我們可以通過異步多線程的方式,將日志輸出到文件中,這樣既不會影響主線程,可以提高應(yīng)用程序的吞吐率,也是一種節(jié)省性能開銷的方法。直接將內(nèi)容打印到控制臺中,這種做法比較粗暴,不是業(yè)界所推薦的做法。
這樣一來,我們最終要解決的問題就非常清楚了,那就是如何在Spring Boot中添加日志框架。幸運的是,Spring Boot自帶了一款名為Spring Boot Logging的插件(在Spring Boot中,稱插件為Starter),它已經(jīng)為我們提供了日志功能。
1 使用Spring Boot Logging插件
Spring Boot使用Apache開源項目Commons Logging作為內(nèi)部的日志框架,它是一個日志接口,在實際應(yīng)用中,我們需要為該接口指定相應(yīng)的日志實現(xiàn)。Spring Boot默認的日志實現(xiàn)是Java Util Logging,它是JDK自帶的日志包,一般場景下很少會用到。此外,Spring Boot也提供了Log4J、Logback這類流行的日志實現(xiàn),我們只需要添加簡單的配置,就能開啟對這些日志實現(xiàn)的支持。
為了便于描述,我們將以上提到的“日志實現(xiàn)”統(tǒng)稱為“日志框架”。
大家可以通過以下網(wǎng)站,進一步學習這類日志框架。
Commons Logging官網(wǎng):https://commons.apache.org/proper/commons-logging/。
Log4J官網(wǎng):https://logging.apache.org/log4j/2.x/。
Logback官網(wǎng):https://logback.qos.ch/。
在Java應(yīng)用程序中,日志一般分為以下5個級別。
ERROR:錯誤信息;
WARN:警告信息;
INFO:一般信息;
DEBUG:調(diào)試信息;
TRACE:跟蹤信息。
以上日志級別按照嚴重程度,從高往低排序,一般常用的三種日志級別是ERROR、INFO、DEBUG。Spring Boot Logging插件默認輸出到INFO級別,也就是說,只包含ERROR、WARN、INFO,不包含DEBUG、TRACE。如果我們希望日志可以輸出到DEBUG級別,則需在Spring Boot的application.properties文件中添加如下配置:
logging .level.root=DEBUG
重新運行應(yīng)用程序,我們就可在代碼中看到DEBUG級別的日志了。
以下是Spring Boot的應(yīng)用程序代碼片段,我們使用SLF4J類庫輸出日志,而不要使用具體的日志實現(xiàn)類庫,比如Log4J。
packagedemo.msa; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; 。。.@RestController@SpringBootApplicationpublicclassHelloApplication{privatestaticLogger logger =LoggerFactory.getLogger(HelloApplication.class); publicstaticvoidmain(String[] args) { SpringApplication.run(HelloApplication.class, args); } @GetMapping( “/hello”)publicString hello() { logger.debug( “l(fā)og.。?!保? // 輸出DEBUG級別的日志return“hello”; } }
運行以上Spring Boot應(yīng)用程序,會發(fā)現(xiàn)控制臺中輸出了大量INFO級別的日志,這些日志是由Spring Boot框架輸出的。因為我們調(diào)整日志輸出到DEBUG級別,而INFO級別在DRBUG級別之上,所以INFO級別的日志也會輸出,但TRACE級別的日志不會輸出。
當我們打開瀏覽器,發(fā)送http://localhost:8080/hello請求時,可在控制臺中看到我們想要輸出的DEBUG級別日志。
如果我們不想關(guān)注Spring Boot框架的日志,則可將日志級別統(tǒng)一設(shè)置為ERROR,此時只會輸出ERROR級別的日志。隨后,再將Spring Boot應(yīng)用程序指定的包(應(yīng)用程序所對應(yīng)的包)設(shè)置為DEBUG級別的日志,此時我們看到的就只是指定包中的日志了。
logging .level.root=ERROR logging .level.demo.msa=DEBUG
上面的logging.level.root表示所有包,logging.level.demo.msa表示應(yīng)用程序的指定包(demo.msa是包名)。以上配置可以理解為,整個應(yīng)用程序的日志輸出到ERROR級別,除了demo.msa包中的日志輸出到DEBUG級別。這是一種“先禁止所有,再允許個別”的配置方法,這種配置方法在很多技術(shù)中都應(yīng)用過。
默認情況下日志框架會將日志輸出到控制臺中,我們需要在application.properties文件中添加如下配置,才能將日志輸出到文件中:
logging .file=${user .home}/logs/hello .log
其中,${user.home}表示當前用戶目錄(該變量由Spring Boot框架在運行時傳入),后面的/logs/hello.log是相對于該目錄的路徑。大家可根據(jù)實際情況,設(shè)置所需的日志文件路徑,以上僅為示例。
重新運行應(yīng)用程序,就能看到日志輸出到指定路徑下的文件中了。
目前我們雖然可以將日志輸出到文件中,但控制臺中仍然會輸出同樣的日志,這不是我們最終想要的效果。我們希望的是日志全部輸出到文件中,控制臺中不輸出任何日志。也就是說,我們需要關(guān)閉控制臺中的輸出。通過以上的嘗試,我們不難發(fā)現(xiàn),僅通過修改Spring Boot的配置,貌似是無法做到的。
下面我們不妨考慮集成經(jīng)典的Log4J日志框架,看看能否實現(xiàn)我們的需求。
2 集成Log4J日志框架
Spring Boot Logging默認集成了Logback,我們只需提供Logback的配置文件就能開啟Logback日志功能,但我們現(xiàn)在想要嘗試的是自己熟知的Log4J,而不是比較新潮的Logback。毫不猶豫,現(xiàn)在我們就來開啟對Log4J的支持。通過學習Spring Boot的官方文檔與示例代碼,我們了解到,只需在pom.xml文件中添加如下Maven配置,就能在Spring Boot中集成Log4J。
《dependency》《groupId》org.springframework.boot 《/groupId》《artifactId》spring-boot-starter 《/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》
在第一段dependency配置中,我們排除掉spring-boot-starter-logging依賴是因為要去掉默認集成的Logback日志功能。在第二段dependency配置中,我們自行添加了spring-boot-starter- log4j2依賴,它是Spring Boot所提供的Log4J插件,此時使用的是Log4J的2.x版本。
當完成了Maven依賴配置以后,我們接下來需要在源碼中的resources目錄下添加log4j2.xml文件,其內(nèi)容如下:
《?xml version=“1.0” encoding=“UTF-8”?》《configuration》《appenders》《Filename=“file”fileName=“${sys:user.home}/logs/hello.log”》《PatternLayoutpattern=“%d{HH:mm:ss,SSS} %p %c (%L) - %m%n”/》《/File》《/appenders》《loggers》《rootlevel=“ERROR”》《appender-refref=“file”/》《/root》《loggername=“demo.msa”level=“DEBUG”/》《/loggers》《/configuration》
log4j2.xml配置文件分為兩大部分,即appenders與loggers。在appenders中,我們添加了一個File類型的appenders,表示日志以文件的方式進行輸出,該文件路徑基于根目錄${sys:user.home},即當前用戶目錄(該變量由Log4J框架在運行時傳入)。此外,還需指定PatternLayout為日志輸出格式。在loggers中,我們先后添加了兩段配置,第一段的root表示將所有包中的日志輸出到ERROR級別,第二段的logger表示將指定包demo.msa中的日志輸出到DEBUG級別。很明顯,這段配置與之前在Spring Boot中配置的意義相同。
通過以上配置,可將Log4J集成到Spring Boot應(yīng)用中。
重新運行應(yīng)用程序,日志不再輸出到控制臺中,而是全部輸出到指定路徑下的文件中了。
大家如果想了解更為詳盡的Spring Boot日志特性,可參考它的官方技術(shù)文檔。
Spring Boot日志:
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html。
目前,雖然日志已經(jīng)成功輸出到文件中,但是我們的微服務(wù)是以Docker容器的方式來運行的,此時輸出的日志文件仍然和應(yīng)用程序在一個Docker容器中,我們得想辦法將日志文件輸出到Docker容器外。也就是說,需要將數(shù)據(jù)與程序相分離,以便后續(xù)更加方便地獲取并分析日志內(nèi)容。
3 將日志輸出到Docker容器外
最容易想到的辦法就是,通過Docker數(shù)據(jù)卷的方式,將文件路徑掛載到Docker容器上,這樣日志文件就自然與Docker文件分離了,就像下面這樣啟動Docker容器。
docker run -v ~ /logs:~/logshello
這樣一來,我們可隨時在宿主機上查看Docker容器內(nèi)部的日志了。但是回過頭想想,卻不難發(fā)現(xiàn),其實完全不需要將日志輸出到文件中,因為即便將日志輸出到控制臺中,我們也能隨時通過docker logs的方式來獲取日志內(nèi)容,將日志輸出到文件似乎有些多余了,還占用了磁盤空間。
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%