Springboot中統(tǒng)一日志管理
一、為什么要用日志?
一般分為兩個大類:操作日志和系統(tǒng)日志
**操作日志:**用戶在操作軟件時記錄下來的操作步驟,便于用戶自己查看。主要針對的是用戶。
**系統(tǒng)日志:**系統(tǒng)日志是記錄系統(tǒng)中硬件、軟件和系統(tǒng)問題的信息,同時還可以監(jiān)視系統(tǒng)中發(fā)生的事件。用戶可以通過它來檢查錯誤發(fā)生的原因,或者尋找受到攻擊時攻擊者留下的痕跡。系統(tǒng)日志包括系統(tǒng)日志、應用程序日志和安全日志。主要針對的是軟件開發(fā)人員(包括測試、維護人員)。
日志的作用:
日志是系統(tǒng)運行的“照妖鏡”,通過它能夠實時反映系統(tǒng)的運行狀態(tài);
良好的日志便于后期運維和開發(fā)人員迅速定位線上問題,加快止損速度,減少系統(tǒng)故障帶來的損失;
日志能夠無縫與監(jiān)控系統(tǒng)結合,通過監(jiān)控系統(tǒng)進行日志采集,拿到系統(tǒng)運行的相關性能指標,有利于分析系統(tǒng)的性能瓶頸、提前規(guī)避風險;
便于統(tǒng)計與業(yè)務相關的指標數(shù)據(jù),進行相關業(yè)務分析和功能優(yōu)化.
二、日志級別
使用日志級別的好處在于,調整級別,就可以屏蔽掉很多調試相關的日志輸出。不同的日志框架定義的日志級別不太一樣,不過也都大同小異。
ALL 最低等級的,用于打開所有日志記錄。
TRACE 很低的日志級別,一般不會使用。
DEBUG 指出細粒度信息事件對調試應用程序是非常有幫助的,主要用于開發(fā)過程中打印一些運行信息。比如函數(shù)里的輸入輸出。
INFO 消息在粗粒度級別上突出強調應用程序的運行過程。打印一些你感興趣的或者重要的信息,這個可以用于生產環(huán)境中輸出程序運行的一些重要信息,但是不能濫用,避免打印過多的日志。
WARN 表明會出現(xiàn)潛在錯誤的情形,有些信息不是錯誤信息,但是也要給程序員的一些提示。
ERROR 指出雖然發(fā)生錯誤事件,但仍然不影響系統(tǒng)的繼續(xù)運行。打印錯誤和異常信息,如果不想輸出太多的日志,可以使用這個級別。
FATAL 指出每個嚴重的錯誤事件將會導致應用程序的退出。這個級別比較高了。重大錯誤,這種級別你可以直接停止程序了。
OFF 最高等級的,用于關閉所有日志記錄。
如果將log level設置在某一個級別上,在你的系統(tǒng)中如果開啟了某一級別的日志后,就不會打印比它級別低的日志,只打印比此級別優(yōu)先級高的log。例如,如果設置優(yōu)先級為WARN,那么OFF、FATAL、ERROR、WARN 4個級別的log能正常輸出,而INFO、DEBUG、TRACE、 ALL級別的log則會被忽略。Log4j建議只使用四個級別,優(yōu)先級從高到低分別是ERROR、WARN、INFO、DEBUG。
三、什么時候打印什么級別的日志
我們之前講Mybatis時也打印過日志,比如打印一下sql,但現(xiàn)在看來只是打印Sql是不夠的,那么我們應該在哪些地方打印,打印哪些東西,打印什么級別的呢?
3.1 在哪些地方需要打印日志?
1、調用第三方接口時會打印日志,比如具體的Request和Response
2、狀態(tài)變化
3、重要方法的輸入和輸出
4、業(yè)務異常
5、非預期執(zhí)行(比如刪除一條數(shù)據(jù),可能成功可能數(shù)據(jù)本身不存在)
6、很少出現(xiàn)的else情況
7、程序運行時間
8、大批量數(shù)據(jù)的執(zhí)行進度3.2 打印哪些內容?
打印的內容一定要從實際出發(fā)。也就是說如果在實際的生產環(huán)境中,你的用戶量很大,日志在不停地刷新,如何定位某個用戶的整個登錄以及后續(xù)的操作呢?當然就是根據(jù)用戶名來跟蹤。所以打印內容的第一要素就是要能便于定位;定位過后也許用戶在好幾個模板中進行操作,還是定位,這個時候定的是模塊的位;還有一點當然就是用戶操作時的具體參數(shù);最后一點就是用戶干了什么。
總結就是,[id, module, params, content](關鍵字,模塊,參數(shù),內容)。
比如:
log.error("{}|ReqId={}|ID={}|業(yè)務執(zhí)行異常|參數(shù)={}|e={}",EVENT_NAME, ReqId, ID, param, e.toString(), e); log.debug("開始獲取員工[{}] [{}]年基本薪資",employee,year);3.3 打印什么級別?
ERROR級別:
影響到程序正常運行、當前請求正常運行的異常情況:
打開配置文件失敗所有第三方對接的異常(包括第三方返回錯誤碼)所有影響功能使用的異常,包括:SQLException和除了業(yè)務異常之外的所有異常(RuntimeException和Exception)如果進行了拋出異常操作,請不要記錄error日志,由異常最終處理方進行處理,比如:
try{ .... }catch(Exception ex){ logger.error(....); //不要在這里加error日志 ,應該在處理這個異常的類中加 throw new UserServiceException(errorMessage,ex); }WARN級別
不應該出現(xiàn)但是不影響程序、當前請求正常運行的異常情況:
有容錯機制的時候出現(xiàn)的錯誤情況找不到配置文件,但是系統(tǒng)能自動創(chuàng)建配置文件即將接近臨界值的時候,例如:緩存池占用達到警告線,業(yè)務異常的記錄等INFO級別
系統(tǒng)運行信息和調用第三方接口信息
Service方法中對于系統(tǒng)/業(yè)務狀態(tài)的變更主要邏輯中的分步驟客戶端請求參數(shù)(REST/WS)調用第三方時的調用參數(shù)和調用結果DEBUG級別
可以填寫所有的想知道的相關信息(但不代表可以隨便寫,debug信息要有意義,最好有相關參數(shù))生產環(huán)境需要關閉DEBUG信息如果在生產情況下需要開啟DEBUG,需要使用開關進行管理,不能一直開啟。四、Java日志框架體系
Java 中的日志框架主要分為兩大類:日志門面和日志實現(xiàn)。
日志門面
日志門面定義了一組日志的接口規(guī)范,它并不提供底層具體的實現(xiàn)邏輯。Apache Commons Logging 和 Slf4j 就屬于這一類。
日志實現(xiàn)
日志實現(xiàn)則是日志具體的實現(xiàn),包括日志級別控制、日志打印格式、日志輸出形式(輸出到數(shù)據(jù)庫、輸出到文件、輸出到控制臺等)。Log4j、Log4j2、Logback 以及 Java Util Logging 則屬于這一類。
如圖所示:
我們使用的時候一般是 ,一個"門面"搭配一個實現(xiàn)層使用。
比如:Slf4j +Log4j
? Slf4j +Logback 。
五 、SpringBoot中如何統(tǒng)一日志管理
spring boot默認使用slf4j+logback作為日志框架。
5.1 怎么導入Logback框架
? 在 Spring Boot 項目中,只要添加了 web 依賴,日志依賴就自動添加進來了:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>并且可以在需要的位置通過下面方式來打印日志:
private static final Logger log = LoggerFactory.getLogger(UserController.class);默認日志是輸出在控制臺的
5.2 application.properties中配置日志管理
? 如果無需復雜的日志配置,執(zhí)行簡單設置日志打印級別,打印方式可直接再 application.properties中配置。
1.設置日志打印級別
#root表示整個項目 logging.level.root=info #表示web層 logging.level.org.springframework.web=debug #表示持久層 logging.level.org.hibernate=error #表示具體某個包 logging.level.com.test.util=debug2.設置日志輸出到文件中
#輸出在根目錄下的daimenglaoshi.log logging.file.name=daimenglaoshi.log #輸出在根目錄下aaa文件夾下的daimenglaoshi.log logging.file.name=aaa/daimenglaoshi.log3.如果想對輸出到文件中的日志進行精細化管理,還有如下一些屬性可以配置
#日志歸檔的文件名,日志文件達到一定大小之后,自動進行壓縮歸檔。 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: #日志文件保存的天數(shù)。 logging.logback.rollingpolicy.max-history:但這些配置在Logback 配置文件中配置更方便
5.3 Logback 配置文件中配置日志管理
在 application.properties 中只能實現(xiàn)對日志一些非常簡單的配置,如果想實現(xiàn)更加細粒度的日志配置,那就需要使用日志實現(xiàn)的原生配置,例如 Logback 的 classpath:logback.xml,Log4j 的 classpath:log4j.xml 等。
使用 xml 后要將 application.properties 中的配置去掉,避免沖突.
1.配置文件如何導入
根據(jù)不同的日志系統(tǒng),按照指定的規(guī)則組織配置文件名,并放在 resources 目錄下,就能自動被 spring boot 加載:
Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy Log4j: log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml Log4j2: log4j2-spring.xml, log4j2.xml JDK (Java Util Logging): logging.properties想要自定義文件名的可配置:logging.config指定配置文件名:
logging.config=classpath:logging-config.xml2.logback 配置文件的組成
根節(jié)點<configuration>有 5 個子節(jié)點,下面來進行一一介紹。
root節(jié)點
root 節(jié)點是必選節(jié)點,用來指定最基礎的日志輸出級別,只有一個 level 屬性,用于設置打印級別,可選如下:TRACE,DEBUG,INFO,WARN,ERROR,ALL,OFF。
root 節(jié)點可以包含 0 個或多個元素,將appender添加進來。如下:
<root level="debug"> <appender-ref ref="console" /> <appender-ref ref="file" /> </root>? appender 也是子節(jié)點之一,將會在后面說明。
contextName節(jié)點
設置上下文名稱,默認為default,可通過%contextName來打印上下文名稱,一般不使用此屬性。
property節(jié)點
用于定義變量,方便使用。有兩個屬性:name,value。定義變量后,可以使用${}來使用變量。如下:
<property name="path" value="./log"/> <property name="appname" value="app"/>appender節(jié)點
appender 用來格式化日志輸出的節(jié)點,這個最重要。有兩個屬性:
name:該 appender 命名class:指定輸出策略,通常有兩種:控制臺輸出,文件輸出下面通過例子來說明這個怎么用:
輸出到控制臺/按時間輸出日志<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"> <!--設置存儲路徑變量--> <property name="LOG_HOME" value="./aaa"/> <!--控制臺輸出appender--> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <!--設置輸出格式--> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度 %msg:日志消息,%n是換行符--> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <!--設置編碼--> <charset>UTF-8</charset> </encoder> </appender> <!--文件輸出,時間窗口滾動--> <appender name="timeFileOutput" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--日志名,指定最新的文件名,其他文件名使用FileNamePattern --> <File>${LOG_HOME}/daimenglaoshi.log</File> <!--文件滾動模式--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日志文件輸出的文件名,可設置文件類型為gz,開啟文件壓縮--> <FileNamePattern>${LOG_HOME}/info.%d{yyyy-MM-dd}.%i.log.gz</FileNamePattern> <!--日志文件保留天數(shù)--> <MaxHistory>30</MaxHistory> <!--按大小分割同一天的--> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!--輸出格式--> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日志消息,%n是換行符--> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <!--設置編碼--> <charset>UTF-8</charset> </encoder> </appender> <!--指定基礎的日志輸出級別--> <root level="INFO"> <!--appender將會添加到這個loger--> <appender-ref ref="console"/> <appender-ref ref="timeFileOutput"/> </root> </configuration>在 appender 中設置,filter 子節(jié)點,在默認級別上再此過濾,配置 onMatch,onMismatch 可實現(xiàn)只輸出單個級別
<appender ...> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <!--接受匹配--> <onMatch>ACCEPT</onMatch> <!--拒絕不匹配的--> <onMismatch>DENY</onMismatch> </filter> </appender>logger節(jié)點
此節(jié)點用來設置一個包或具體的某一個類的日志打印級別、以及指定<appender>,有以下三個屬性:
name: 必須。用來指定受此 loger 約束的某個包或者某個具體的類level:可選。設置打印級別。默認為 root 的級別。addtivity: 可選。是否向上級 loger(也就是 root 節(jié)點)傳遞打印信息。默認為 true。使用示例如下:
不指定級別,不指定 appender<!-- 控制com.example.service下類的打印,使用root的level和appender --> <logger name="com.test.service"/>2.指定級別,不指定 appender
<!-- 控制com.example.service下類的打印,使用root的appender打印warn級別日志 --> <logger name="com.test.service" level="WARN"/>3.指定級別,指定 appender
<!-- 控制com.example.service下類的打印,使用console打印warn級別日志 --> <!-- 設置addtivity是因為這里已經指定了appender,如果再向上傳遞就會被root下的appender再次打印 --> <logger name="com.test.service" level="WARN" addtivity="false"> <appender-ref ref="console"> </logger>通過指定 appender 就能將指定的包下的日志打印到指定的文件中。
多環(huán)境日志輸出
通過設置文件名為-spring 結尾,可分環(huán)境配置 logger,示例如下:
<configuration> <!-- 測試環(huán)境+開發(fā)環(huán)境. 多個使用逗號隔開. --> <springProfile name="test,dev"> <logger name="com.example.demo.controller" level="DEBUG" additivity="false"> <appender-ref ref="console"/> </logger> </springProfile> <!-- 生產環(huán)境. --> <springProfile name="prod"> <logger name="com.example.demo" level="INFO" additivity="false"> <appender-ref ref="timeFileOutput"/> </logger> </springProfile> </configuration>