打印日志
打印日志的步驟:
? 在程序中得到日志對象.
? 使用日志對象輸出要打印的內容
在程序中得到日志對象
在程序中獲取日志對象需要使用日志工廠LoggerFactory,代碼如下:
package com.example.demo;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class LoggerController {private static Logger logger = LoggerFactory.getLogger(LoggerController.class);
}
LoggerFactory.getLogger需要傳遞一個參數,用于標識該日志的出處,這樣就可以清晰的看出該日志是哪個類輸出的日志,方便觀察調試,定位問題
這里需要注意的是:
Logger和LoggerFactory這兩個類是屬于org.slf4j包下的
使用日志對象輸出要打印的內容
日志對象的打印級別有很多種,這里先打印info級別的日志:
package com.example.demo;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/logger")
public class LoggerController {private static Logger logger = LoggerFactory.getLogger(LoggerController.class);@RequestMapping("/printLogger")public String printLogger(){logger.info("我是info級別的日志");return "打印日志";}
}
門面模式
真假日志框架
前面我們創建日志對象,導入了slf4j的包,因此,我們需要對slf4j進行深入的學習,要了解slf4j,就得先了解門面模式
門面模式提供了一個統一的接口,用于調用子系統中的一群子接口,并對子系統的接口提供了一套規范,標準,接口.所有SLF4J并不能獨立使用,需要和具體的日志框架配合使用
slf4j就是這樣一個門面系統,因為它本身并不是一個真正的日志實現,而只是一個抽象層,對真正的日志框架提供了規范.
常見的真正的日志框架有log4j,logback
等
存在即合理
既然有真正的日志框架,那么為什么需要門面模式的存在?
在不引入門面模式的時候
當一個項目已經試用了log4j,假如出現一種情況,需要把logback也引入進去,那么就會引出以下問題:
- 不同日志框架的API接口和配置文件不同,如果多個日志框架共存,那么不得不維護多套配置文件(這 個配置文件是指用戶自定義的配置文件).
- 如果要更換日志框架,應用程序將不得不修改代碼,并且修改過程中可能會存在一些代碼沖突.
- 如果引入的第三方框架,使用了多套,那就不得不維護多套配置 這時我們將門面模式引入,引入門面日志框架之后,應用程序和日志框架(框架的具體實現)之間有了統?的API接口(門面日志框架實現),此時應用程序只需要維護?套日志文件配置,且當底層實現框架改變時,也不需要更改應用程序代碼.
門面模式的優點
? 減少了系統的相互依賴.實現了客戶端與子系統的耦合關系,這使得子系統的變化不會影響到調用它的客戶端;
? 提高了靈活性,簡化了客戶端對子系統的使用難度,客戶端無需關心子系統的具體實現方式,而只需要和門面對象交互即可.
? 提高了安全性.可以靈活設定訪問權限,不在門面對象中開通方法,就無法訪問
日志格式的說明
打印的日志分別代表什么呢?
從上圖可以看到,日志輸出內容元素具體如下:
- 時間日期:精確到毫秒
- 日志級別:ERROR,WARN,INFO,DEBUG或TRACE
- 進程ID
- 線程名
- Logger名(通常使用源代碼的類名)
- 日志內容
日志級別
日志級別的分類
日志的級別從高到低依次為:FATAL、ERROR、WARN、INFO、DEBUG、TRACE
? FATAL:致命信息,表示需要立即被處理的系統級錯誤.
? ERROR:錯誤信息,級別較高的錯誤日志信息,但仍然不影響系統的繼續運行.
? WARN:警告信息,不影響使用,但需要注意的問題
? INFO:普通信息,用于記錄應用程序正常運行時的?些信息,例如系統啟動完成、請求處理完成等.
? DEBUG:調試信息,需要調試時候的關鍵信息打印.
? TRACE:追蹤信息,比DEBUG更細粒度的信息事件(除非有特殊用意,否則請使用DEBUG級別替代)
日志級別的使用
logger.trace("================= trace ===============");logger.debug("================= debug ===============");logger.info("================= info ===============");logger.warn("================= warn ===============");logger.error("================= error ===============");return "打印不同日志";
SpringBoot默認的日志框架是Logback,Logback沒有 FATAL 級別,它被映射到ERROR .
出現fatal日志,表示服務已經出現了某種程度的不可用,需要需要系統管理員緊急介入處理.通常情況下,一個進程生命周期中應該最多只有一次FATAL記錄.
結果發現,只打印了info,warn和error級別的日志
這與日志級別的配置有關,日志的輸出級別默認是info級別,所以只會打印大于等于此級別的日志,也就是info,warn和error.
日志配置
properties配置:
logging.level.root: debug
yml配置:
logging:level:root: debug
重新運行,就可以得到下面結果
日志持久化
以上的日志都是輸出在控制臺上的,然而在線上環境中,我們需要把日志保存下來,以便出現問題之后追溯問題.把日志保存下來就叫持久化.
日志持久化有兩種方式:
1.配置日志文件名
logging.file.name= logger.log
logging:file:name: logger.log
運行結果顯示,日志內容保存在了對應的目錄下
2.配置日志的存儲目錄
logging.file.path: D:/temp
logging:file:path: D:/temp
運行程序,日志就會被保存到設置的磁盤目錄下,但是這種方式只能設置日志的路徑,文件名固定為spring.log
注意:
logging.file.name 和 logging.file.path 兩個都配置的情況下,只生效其?,以
logging.file.name 為準
配置日志文件分割
如果我們的日志都放在?個文件中,隨著項目的運行,日志文件會越來越大,需要對日志文件進行分割,當然,如果我們不對它進行配置,系統就會讓它走默認配置,即超過10MB就進行分割
配置項 | 說明 | 默認值 |
---|---|---|
logging.logback.rollingpolicy.file-name-pattern | ?志分割后的?件名格式 | ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz |
logging.logback.rollingpolicy.max-file-size | 日志文件超過這個大小就自動分割 | 10MB |
Properties配置: |
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}.%i
logging.logback.rollingpolicy.max-file-size=1KB
yml配置:
logging:logback:rollingpolicy:max-file-size: 1KBfile-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i
運行項目,多打印一些日志,得到以下結果:
更簡單的日志輸出
- 添加lombok框架支持
- 使用 @slf4j 注解輸出日志
添加lombok依賴
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
日志輸出
lombok提供的 @Slf4j 會幫我們提供?個日志對象log,我們直接使用就可以
package com.example.demo;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class LogController {@RequestMapping("/info")public void log(){log.info("info");}
}