最近在研究springboot的日誌,因此記錄一下,作一下總結。php
幾篇關於日誌的文章:html
介紹日誌:https://blog.csdn.net/gwd1154978352/article/details/78344091java
https://www.cnblogs.com/bigdataZJ/p/springboot-log.htmlweb
記錄日誌:https://blog.csdn.net/heweimingming/article/details/76423186spring
日誌,一般不會在需求階段做爲一個功能單獨提出來,也不會在產品方案中看到它的細節。可是,這絲絕不影響它在任何一個系統中的重要的地位。sql
爲了保證服務的高可用,發現問題必定要即便,解決問題必定要迅速,因此生產環境一旦出現問題,預警系統就會經過郵件、短信甚至電話的方式實施多維轟炸模式,確保相關負責人不錯過每個可能的bug。shell
預警系統判斷疑似bug大部分源於日誌。好比某個微服務接口因爲各類緣由致使頻繁調用出錯,此時調用端會捕獲這樣的異常並打印ERROR級別的日誌,當該錯誤日誌達到必定次數出現的時候,就會觸發報警。apache
try { 調用某服務 } catch(Exception e) { LOG.error("錯誤信息", e); }
因此日誌相當重要,這篇就來介紹下在Spring Boot如何配置日誌。springboot
Spring Boot默認使用LogBack日誌系統,若是不須要更改成其餘日誌系統如Log4j2等,則無需多餘的配置,LogBack默認將日誌打印到控制檯上。bash
一、若是要使用LogBack,原則上是須要添加dependency依賴的
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency>
可是由於新建的Spring Boot項目通常都會引用spring-boot-starter
或者spring-boot-starter-web
,而這兩個起步依賴中都已經包含了對於spring-boot-starter-logging
的依賴,
因此,無需額外添加依賴,配置logback-spring.xml就能夠了。以logback-spring.xml命名,spring會自動識別加載。spring-boot-starterspring-boot-starter-webspring-boot-starter-logging
二、若是須要切換Log4j2,那麼在pom.xml中須要排除springboot自帶的commons‐logging,而後再引入log4j2的依賴:
<!--排除 commons‐logging--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>commons‐logging</groupId> <artifactId>commons‐logging</artifactId> </exclusion> </exclusions> </dependency> <!--引入log4j2 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
而後再引入log4j.properties文件就能夠了。
log4j.properties:
### set log levels ###
log4j.rootLogger = debug , stdout , D , E
### 輸出到控制檯 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} ===== %5p %c{ 1 }:%L - %m%n
#### 輸出到日誌文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/log.log
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = DEBUG ## 輸出DEBUG級別以上的日誌
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
#
#### 保存異常信息到單獨文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/error.log ## 異常日誌文件名
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = ERROR ## 只輸出ERROR級別以上的日誌!!!
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
日誌級別由低到高: trace < debug < info < warm < error ,設置的級別越低顯示的日誌級別的信息越多。
例如:若是設置的日誌級別是info,那麼此時,低於info級別的trace,debug日誌不會顯示。
springboot在不對日誌進行任何設置的狀況下,默認日誌root級別是INFO,輸出的是INFO級別以上的日誌。
package com.ll; import org.junit.Test; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class SpringbootCacheApplicationTests { private static final Logger log = LoggerFactory.getLogger(SpringbootCacheApplicationTests.class); /** * 測試 日誌級別: * 級別由低到高: trace < debug < info < warm < error 設置的級別越低顯示的日誌信息越多。 * 能夠調整輸出的日誌級別,只會顯示高於設置級別的日誌。 */ @Test public void testLog() { log.trace("這是track日誌。。。"); log.debug("這是debug日誌。。。"); //spring 默認設置的級別是info級別,沒有指定級別的狀況下,會使用spring默認的root級別(顯示的是info級別的信息) log.info("這是info日誌。。。"); log.warn("這是warm日誌。。。"); log.error("這是error日誌。。。"); } }
控制檯信息:
只會輸出INFO級別以上的日誌信息,開發環境中,要顯示打印sql語句等debug調試信息,要對日誌級別進行設置。
日誌能夠經過兩種方式配置:
1、application.properties或者application.yml文件配置:
這種方式須要把全部的日誌配置寫在properties或者yml文件裏面,配置遷移不方便,寫的感受也有點亂,很繁雜,對log4j2的支持也很差。推薦用第二種,logback的xml配置方便比較好,配置遷移複製粘貼,而後改一下里面的配置就行了。
簡單列舉一下:
logging.level.* = LEVEL
logging.level:日誌級別控制前綴,*爲包名或Logger名
LEVEL:選項TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
舉例說明:
logging.level.com.ll=DEBUG 表示com.ll包下全部class以DEBUG級別輸出(包含mapper所在的包,會打印sql語句)
logging.level.root=INFO 表示root日誌以INFO級別輸出
logging.path 該屬性用來配置日誌文件的路徑
logging.file 該屬性用來配置日誌文件名,若是該屬性不配置,默認文件名爲spring.log
logging.path=/springboot/log
在當前磁盤的根路徑下建立spring文件夾和裏面的log文件夾;若是不配置,使用 spring.log 做爲默認文件
logging.file=E:/springboot/log/spring.log 能夠指定完整的路徑(logging.path和logging.file 配置一個便可)
另外還有日誌的打印位置設置:
logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n
logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n
logging.pattern.console
該屬性用於定製日誌輸出格式。上述配置的編碼中,對應符號的含義以下:
%d{HH:mm:ss.SSS}——日誌輸出時間 %thread——輸出日誌的進程名字,這在Web應用以及異步任務處理中頗有用 %-5level——日誌級別,而且使用5個字符靠左對齊 %logger- ——日誌輸出者的名字 %msg——日誌消息 %n——平臺的換行符
appliacation.properties:
# com.ll包下全部class以DEBUG級別輸出(包含mapper所在的包,會打印sql語句)
logging.level.com.ll=DEBUG
# root日誌以INFO級別輸出
logging.level.root=INFO
# 在當前磁盤的根路徑下建立spring文件夾和裏面的log文件夾;若是不配置,使用 spring.log 做爲默認文件
#logging.path=/springboot/log
# 能夠指定完整的路徑(logging.path和logging.file 配置一個便可)
logging.file=E:/springboot/log/spring.log
#控制檯日誌格式 logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n #文件日誌格式 logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n
2、logback的xml文件配置:
因爲日誌服務通常都在ApplicationContext建立前就初始化了,它並非必須經過Spring的配置文件控制。所以經過系統屬性和傳統的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
Spring Boot官方推薦優先使用帶有-spring的文件名做爲你的日誌配置(如使用logback-spring.xml,而不是logback.xml),命名爲logback-spring.xml的日誌配置文件,spring boot能夠爲它添加一些spring boot特有的配置項(下面會提到)。
上面是默認的命名規則,而且放在src/main/resources下面便可。
若是你即想徹底掌控日誌配置,但又不想用logback.xml做爲Logback配置的名字,能夠經過logging.config屬性指定自定義的名字:ogging.config=classpath:logging-config.xm
雖然通常並不須要改變配置文件的名字,可是若是你想針對不一樣運行時Profile使用不一樣的日誌配置,這個功能會頗有用。
logback-spring.xml配置:
<?xml version="1.0" encoding="UTF-8"?> <!-- scan:當此屬性設置爲true時,配置文件若是發生改變,將會被從新加載,默認值爲true。 scanPeriod:設置監測配置文件是否有修改的時間間隔,若是沒有給出時間單位,默認單位是毫秒當scan爲true時,此屬性生效。默認的時間間隔爲1分鐘。 debug:當此屬性設置爲true時,將打印出logback內部日誌信息,實時查看logback運行狀態。默認值爲false。 --> <configuration scan="false" scanPeriod="60 seconds" debug="false"> <!-- 定義日誌的根目錄 --> <property name="LOG_HOME" value="/app/log" /> <!-- 定義日誌文件名稱 --> <property name="appName" value="ll-springboot"></property> <!-- ch.qos.logback.core.ConsoleAppender 表示控制檯輸出 --> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <!-- 日誌輸出格式: %d表示日期時間, %thread表示線程名, %-5level:級別從左顯示5個字符寬度 %logger{50} 表示logger名字最長50個字符,不然按照句點分割。 %msg:日誌消息, %n是換行符 --> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> </layout> </appender> <!-- 滾動記錄文件,先將日誌記錄到指定文件,當符合某個條件時,將日誌記錄到其餘文件 --> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 指定日誌文件的名稱 --> <file>${LOG_HOME}/${appName}.log</file> <!-- 當發生滾動時,決定 RollingFileAppender 的行爲,涉及文件移動和重命名 TimeBasedRollingPolicy: 最經常使用的滾動策略,它根據時間來制定滾動策略,既負責滾動也負責出發滾動。 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 滾動時產生的文件的存放位置及文件名稱 %d{yyyy-MM-dd}:按天進行日誌滾動 %i:當文件大小超過maxFileSize時,按照i進行文件滾動 --> <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern> <!-- 可選節點,控制保留的歸檔文件的最大數量,超出數量就刪除舊文件。假設設置天天滾動, 且maxHistory是365,則只保存最近365天的文件,刪除以前的舊文件。注意,刪除舊文件是, 那些爲了歸檔而建立的目錄也會被刪除。 --> <MaxHistory>365</MaxHistory> <!-- 當日志文件超過maxFileSize指定的大小是,根據上面提到的%i進行日誌文件滾動 注意此處配置SizeBasedTriggeringPolicy是沒法實現按文件大小進行滾動的,必須配置timeBasedFileNamingAndTriggeringPolicy --> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 日誌輸出格式: --> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern> </layout> </appender> <!-- logger主要用於存放日誌對象,也能夠定義日誌類型、級別 name:表示匹配的logger類型前綴,也就是包的前半部分 level:要記錄的日誌級別,包括 TRACE < DEBUG < INFO < WARN < ERROR additivity:做用在於children-logger是否使用 rootLogger配置的appender進行輸出, false:表示只用當前logger的appender-ref, true:表示當前logger的appender-ref和rootLogger的appender-ref都有效 --> <!-- logger是記錄Logger對象輸出的日誌級別的 sercvice實現類引入日誌對象能夠查看方法的報錯信息以及打印sql語句,public static final Logger logger = LoggerFactory.getLogger(SysUserServiceImpl.class); 生產環境: 通常把level設爲error,能夠記錄錯誤的日誌信息,畢竟主要是要記錄錯誤信息進行錯誤定位。 開發環境: 類中引入了logger日誌對象時,level級別用info,debug均可以,都有錯誤信息輸出。 --> <!-- hibernate logger --> <logger name="com.ll" level="info" /> <!-- Spring framework logger --> <logger name="org.springframework" level="debug" additivity="false"></logger> <!-- root與logger是父子關係,沒有特別定義則默認爲root,任何一個類只會和一個logger對應, 要麼是定義的logger,要麼是root,判斷的關鍵在於找到這個logger,而後判斷這個logger的appender和level。 --> <!-- 通常用默認的info就能夠 --> <root level="info"> <!-- 控制檯輸出日誌--> <appender-ref ref="stdout" /> <!-- 開發環境: 不須要往文件記錄日誌,能夠把這個appender-ref ref="appLogAppender"註釋,上面那個往文件寫日誌的appender也要註釋,否則天天都產生一個空文件; 生產環境: 須要往文件記錄日誌,此時appender-ref ref="appLogAppender"就不能註釋了,否則沒日誌記錄到文件,上面那個往文件寫日誌的appender也要放開。 --> <appender-ref ref="appLogAppender" /> </root> </configuration>
配置完logback-spring.xml,接下來須要作的就是在把Logger對象引入到須要記錄日誌的類了。
public static final Logger logger = LoggerFactory.getLogger(SysUserServiceImpl.class);
下面列舉一個記錄批量保存方法記錄錯誤日誌的例子:
package com.ll.service.impl; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import com.ll.bean.SysUser; import com.ll.mapper.SysUserMapper; import com.ll.service.SysUserService; import com.ll.utils.MyException; @Service public class SysUserServiceImpl implements SysUserService { public static final Logger logger = LoggerFactory.getLogger(SysUserServiceImpl.class); @Autowired SysUserMapper sysUserMapper; //開啓事務 @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,rollbackFor = MyException.class) @Override public int batchInsertUser(List<SysUser> userList) throws MyException { // try { sysUserMapper.batchInsertUser(userList); } catch (Exception e) { /**推薦printStackTrace()打印堆棧錯誤信息這個方法保留,紅色錯誤提示,開發的時候更方便查看錯誤信息*/ e.printStackTrace(); /**logger.error方法把異常錯誤e記錄進日誌文件,開發環境用logger.error方法結合printStackTrace()打印堆棧錯誤信息的方法就能夠了*/ logger.error("method:batchInsertUser,error:",e); /**由於logback-spring.xml的logger的level級別設置爲error時,logger.info的消息不會打印,也不會記錄進日誌文件,因此不要用logger.info方法,開發環境用printStackTrace()打印堆棧錯誤信息便可。*/ //logger.info("method:batchInsertUser",e); throw new MyException("批量新增失敗!",e.getCause()); } return 1; } }
有時候logger.error不能徹底地打印出網站的錯誤堆棧信息,只能打印這個錯誤是一個什麼錯誤。
爲何?
看Logger.error源碼
public void error(String msg, Throwable t);
public void error(String msg);
若是隻傳一個參數e進去,那麼e就被認爲是String類型(會自動調toString()方法把Exception轉成String),而不是Exception類型。
若是想打印堆棧信息,那麼必須傳兩個或以上參數,實際上就是爲了調用public void error(String msg, Throwable t);
因此咱們的寫法能夠是:
Logger.error(「xxx出錯」,e); //第二個參數是e
而不是:
Logger.error(「xxx出錯:」+e) 或 logger.error(e) 或logger.error(e.getMessage);
到此,springboot的slf4j簡單日誌門面,默認使用的logback-spring.xml配置和日誌記錄就完成了~~~~~~~