java日誌列印使用指南
一、簡介
- 日誌列印是java程式碼開發中不可缺少的重要一步。
- 日誌可以排查問題,可以蒐集資料
二、常用日誌框架
比較常用的日誌框架就是logback, 一些老專案會使用log4j,他們用的都是slf4j-api統一介面。
(1) 使用log4j
log4j使用: 1. slf4j-api-1.5.11.jar 2. slf4j-log4j12-1.5.11.jar 3. log4j-1.2.15.jar 4. log4j.properties
程式碼中
import org.slf4j.Logger; import org.slf4j.LoggerFactory; Logger logger = LoggerFactory.getLogger(xx.class);
(2) 使用logback
logback使用: 1. slf4j-api-1.5.11.jar 2. logback-core.jar 3. logback-classic.jar 4. logback.xml
程式碼同log4j
import org.slf4j.Logger; import org.slf4j.LoggerFactory; Logger logger = LoggerFactory.getLogger(xx.class);
三、日誌級別
TRACE < DEBUG < INFO < WARN < ERROR
日常使用較多的是error, info , debug
四、logback簡單介紹
簡單介紹下常用的logback,logback優點:
- 比log4j更快
- 和log4j使用了同一個介面,slf4j-api,可以非常方便切換
- 定義了功能非常豐富的appender
- 支援日誌壓縮
logback要正確理解xml配置檔案
- configuration:總的父節點
- property:自定義屬性
- appender:輸出控制器,可以輸出到控制檯,自定義檔案等
- logger:日誌級別
- root:控制器級別
一個例子:
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="60 seconds"> <contextName>XXXXXXXX</contextName> <property name="log.path" value="./log/"/> <!-- 日誌最大的歷史 30天 --> <property name="maxHistory" value="30"/> <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] [%-5level] [%logger{30}:%line] %msg%n"/> <!--輸出到控制檯--> <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"> <!--此日誌appender是為開發使用,只配置最底級別,控制檯輸出的日誌級別是大於或等於此級別的日誌資訊--> <!--LevelFilter: 級別過濾器,根據日誌級別進行過濾。如果日誌級別等於配置級別,過濾器會根據onMath 和 onMismatch接收或拒絕日誌。--> <!--例如:將過濾器的日誌級別配置為INFO,所有INFO級別的日誌交給appender處理,非INFO級別的日誌,被過濾掉。--> <!--<filter class="ch.qos.logback.classic.filter.LevelFilter">--> <!--<level>INFO</level>--> <!--<onMatch>ACCEPT</onMatch>--> <!--<onMismatch>DENY</onMismatch>--> <!--</filter>--> <!--ThresholdFilter: 臨界值過濾器,過濾掉低於指定臨界值的日誌。當日志級別等於或高於臨界值時,過濾器返回NEUTRAL;當日志級別低於臨界值時,日誌會被拒絕。--> <!-- 過濾掉所有低於 DEBUG 級別的日誌,留下DEBUG及以上級別的日誌 --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <encoder> <pattern>${log.pattern}</pattern> </encoder> </appender> <!-- 時間滾動輸出 level為 INFO 日誌 --> <appender name="errorFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--LevelFilter: 級別過濾器,根據日誌級別進行過濾。如果日誌級別等於配置級別,過濾器會根據onMath 和 onMismatch接收或拒絕日誌。--> <!--例如:將過濾器的日誌級別配置為INFO,所有INFO級別的日誌交給appender處理,非INFO級別的日誌,被過濾掉。--> <!--<filter class="ch.qos.logback.classic.filter.LevelFilter">--> <!--<level>INFO</level>--> <!--<onMatch>ACCEPT</onMatch>--> <!--<onMismatch>DENY</onMismatch>--> <!--</filter>--> <!--ThresholdFilter: 臨界值過濾器,過濾掉低於指定臨界值的日誌。當日志級別等於或高於臨界值時,過濾器返回NEUTRAL;當日志級別低於臨界值時,日誌會被拒絕。--> <!-- 過濾掉所有低於 DEBUG 級別的日誌,留下DEBUG及以上級別的日誌 --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> <!-- 正在記錄的日誌檔案的路徑及檔名 --> <file>${log.path}/error.log</file> <!-- 日誌記錄器的滾動策略,按日期,按大小記錄 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天日誌歸檔路徑以及格式 --> <fileNamePattern>${log.path}/error-%d{yyyyMMdd}.%i.log.zip</fileNamePattern> <!--日誌檔案保留天數--> <maxHistory>${maxHistory}</maxHistory> <!-- 日誌總儲存量為2GB --> <totalSizeCap>2GB</totalSizeCap> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!--檔案達到 最大100MB時會被壓縮和切割 --> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>${log.pattern}</pattern> </encoder> </appender> <!-- 時間滾動輸出 level為 INFO 日誌 --> <appender name="infoFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--LevelFilter: 級別過濾器,根據日誌級別進行過濾。如果日誌級別等於配置級別,過濾器會根據onMath 和 onMismatch接收或拒絕日誌。--> <!--例如:將過濾器的日誌級別配置為INFO,所有INFO級別的日誌交給appender處理,非INFO級別的日誌,被過濾掉。--> <!--<filter class="ch.qos.logback.classic.filter.LevelFilter">--> <!--<level>INFO</level>--> <!--<onMatch>ACCEPT</onMatch>--> <!--<onMismatch>DENY</onMismatch>--> <!--</filter>--> <!--ThresholdFilter: 臨界值過濾器,過濾掉低於指定臨界值的日誌。當日志級別等於或高於臨界值時,過濾器返回NEUTRAL;當日志級別低於臨界值時,日誌會被拒絕。--> <!-- 過濾掉所有低於 DEBUG 級別的日誌,留下DEBUG及以上級別的日誌 --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <!-- 正在記錄的日誌檔案的路徑及檔名 --> <file>${log.path}/info.log</file> <!-- 日誌記錄器的滾動策略,按日期,按大小記錄 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天日誌歸檔路徑以及格式 --> <fileNamePattern>${log.path}/info-%d{yyyyMMdd}.%i.log.zip</fileNamePattern> <!--日誌檔案保留天數--> <maxHistory>${maxHistory}</maxHistory> <!-- 日誌總儲存量為10GB --> <totalSizeCap>2GB</totalSizeCap> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!--檔案達到 最大100MB時會被壓縮和切割 --> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>${log.pattern}</pattern> </encoder> </appender> <!-- 時間滾動輸出 level為 INFO 日誌 --> <appender name="debugFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--LevelFilter: 級別過濾器,根據日誌級別進行過濾。如果日誌級別等於配置級別,過濾器會根據onMath 和 onMismatch接收或拒絕日誌。--> <!--例如:將過濾器的日誌級別配置為INFO,所有INFO級別的日誌交給appender處理,非INFO級別的日誌,被過濾掉。--> <!--<filter class="ch.qos.logback.classic.filter.LevelFilter">--> <!--<level>INFO</level>--> <!--<onMatch>ACCEPT</onMatch>--> <!--<onMismatch>DENY</onMismatch>--> <!--</filter>--> <!--ThresholdFilter: 臨界值過濾器,過濾掉低於指定臨界值的日誌。當日志級別等於或高於臨界值時,過濾器返回NEUTRAL;當日志級別低於臨界值時,日誌會被拒絕。--> <!-- 過濾掉所有低於 DEBUG 級別的日誌,留下DEBUG及以上級別的日誌 --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <!-- 正在記錄的日誌檔案的路徑及檔名 --> <file>${log.path}/debug.log</file> <!-- 日誌記錄器的滾動策略,按日期,按大小記錄 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天日誌歸檔路徑以及格式 --> <fileNamePattern>${log.path}/debug-%d{yyyyMMdd}.%i.log.zip</fileNamePattern> <!--日誌檔案保留天數--> <maxHistory>${maxHistory}</maxHistory> <!-- 日誌總儲存量為2GB --> <totalSizeCap>2GB</totalSizeCap> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <!--檔案達到 最大100MB時會被壓縮和切割 --> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>${log.pattern}</pattern> </encoder> </appender> <logger name="com.baomidou" level="debug"/> <root level="info"> <appender-ref ref="consoleAppender"/> <appender-ref ref="errorFileAppender"/> <appender-ref ref="infoFileAppender"/> <appender-ref ref="debugFileAppender"/> </root> </configuration>
五、常見問題
- 1、日誌打的少,不好排查問題?
我們經常會遇到一個生產問題,去看日誌,啥都沒有,只能重新加日誌,發包,再排查問題; 所以我們要養成打日誌的習慣,開發環境可以debug看,生產看不了,只能加日誌,在開發的時候就把必要的日誌加上; 比較重要的是介面的入參,返回,重要節點開始,結束,mq傳送接收等。
- 2、error, info , debug分別都什麼時候使用?
error: 捕獲異常的時候使用,這個沒有異議 info: 比較重要的資訊,使用頻次不是非常高的場景,比如入參出參 debug: 一個是不是特別重要的資訊,但是又不能少,還有資料量大的資料,比如大量mq資訊,訪問頻繁的介面入參出參
- 3、開啟debug好多無用的debug資訊怎麼辦?
把專案的目錄定為debug,其它定成info。這樣只有本專案的debug日誌會列印了 logging.level.root=info logging.level.cn.mypackage=debug
- 4、需要自定義日誌檔案嗎?
logback可以把日誌寫進自定義檔案,debug,info,error分開儲存,歷史資料還能壓縮; 按自己專案的需求來,大型專案建議分開儲存。
- 5、springboot啟動命令自帶的日誌和自定義日誌檔案的日誌重複怎麼辦?
我們一般啟動springboot專案命令為:nohup java -jar XXXXXXXX.jar >> XXXXXXX.log 2>&1 & 這個會生成一個日誌檔案,logback配置也會生成自己的日誌檔案,就會重複,造成空間浪費,如何取捨? 如果你們公司統一打包指令碼的話,就用命令生成的日誌檔案吧,把logback配置去掉; 如果你們公司自由度比較高,就用logback生成的日誌,把命令改成 >/dev/null 就可以了
- 6、debug日誌正確寫法?
有些人可能打debug日誌直接logger.debug("****"); 如果專案的日誌級別比較高,就比較浪費效能,可以加一個 if (log.isDebugEnabled()) { log.debug("XXXXXXXXXXXXX"); }
- 7、動態日誌級別?
有些公司支援動態配置檔案,比如diamond,nacos等,可以修改配置檔案的級別,動態生效 logging.level.root=info #logging.level.root=debug 日常開在info,出了問題開debug找,資源有限可以這樣做,不推薦生產使用
歡迎關注微信公眾號:豐極,更多技術學習分享。
「其他文章」
- 模板化的封裝,降低業務程式碼開發
- 分享一個 SpringCloud Feign 中所埋藏的坑
- MySQL 事務常見面試題總結 | JavaGuide 稽核中
- 型別安全的 Go HTTP 請求
- 從幾次事故引起的對專案質量保障的思考
- 聯盟鏈 Hyperledger Fabric 應用場景
- 上半年最中意的 GitHub 更新「GitHub 熱點速覽 v.22.21」
- 為什麼我寫了路由懶載入但程式碼卻沒有分割?
- 這個設計原則,你認同嗎?
- SpringCloud基礎概念學習筆記(Eureka、Ribbon、Feign、Zuul)
- 自動微分原理
- layui資料表格搜尋
- Python 中的記憶體管理
- spring 配置檔案 --bean
- 【leetcode】239. 滑動視窗最大值
- Spring 原始碼(17)Spring Bean的建立過程(8)Bean的初始化
- SpringBoot進階教程(七十四)整合ELK
- 連結串列的基本操作和高頻演算法題
- 【python】python連線Oracle資料庫
- Python技法:浮點數取整、格式化和NaN處理