SpringBoot + @Slf4j + log4j 日誌分級輸出
一、概念介紹
- SLF4J
SLF4J,即簡單日誌門面(Simple Logging Facade for Java),不是具體的日誌實現方案,它只服務於各種各樣的日誌系統。按照官方的說法,SLF4J是一個用於日誌系統的簡單Facade,允許最終用戶在部署其應用時使用其所希望的日誌系統。 - Log4J
具體介紹這了不在贅述了~
二、環境準備
演示環境:SpringBoot 2.2.1.RELEASE、Slf4j簡單日誌門面、log4j
1、SpringBoot項目搭建
參考我的另外一篇博客:
鏈接: IDEA 創建SpringBoot多級Maven父子項目-swotXu.
2、依賴引入
- 引入
spring-boot-starter
包,
<!--
spring-boot-starter 包含了spring-boot-starter-logging,
引入log4j之前,需移除掉
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.1.RELEASE</version>
<!-- 移除默認log配置 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
注意:這裏需要移除默認log配置,否者拋出以下異常:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/maven/maven-repository-3.5.3/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/maven/maven-repository-3.5.3/org/slf4j/slf4j-log4j12/1.7.29/slf4j-log4j12-1.7.29.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
- 引入
log4j
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
- 引入
lombok
,可使用@Slf4j
註解,全局log
對象
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<optional>true</optional>
</dependency>
三、log4j 日誌配置
在項目resources
目錄下創建文件log4j.properties
博主這裏,將日誌分級別輸出到不同文件中
先定義日誌附加器:
- DEBUG 級別
輸出:項目名/debug/debug.log
策略:日誌文件每達到80M,生成一個新文件
log4j.appender.file_debug=org.apache.log4j.RollingFileAppender
log4j.appender.file_debug.layout=org.apache.log4j.PatternLayout
log4j.appender.file_debug.MaxFileSize=80MB
log4j.appender.file_debug.MaxBackupIndex=10
log4j.appender.file_debug.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss} (%C:%L line)] %m%n
log4j.appender.file_debug.Threshold=DEBUG
log4j.appender.file_debug.filter.F1=org.apache.log4j.varia.LevelRangeFilter
log4j.appender.file_debug.filter.F1.LevelMin=DEBUG
log4j.appender.file_debug.filter.F1.LevelMax=DEBUG
log4j.appender.file_debug.append=true
log4j.appender.file_debug.Encoding=UTF-8
log4j.appender.file_debug.File=logs/concurrency/debug/debug.log
- INFO 級別
輸出:項目名/info/info.log
策略:日誌文件每半天,生成一個新文件
log4j.appender.file_info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file_info.DatePattern='_'yyyy-MM-dd-a
log4j.appender.file_info.layout=org.apache.log4j.PatternLayout
log4j.appender.file_info.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss} (%C:%L line)] %m%n
log4j.appender.file_info.Threshold=INFO
log4j.appender.file_info.filter.F1=org.apache.log4j.varia.LevelRangeFilter
log4j.appender.file_info.filter.F1.LevelMin=INFO
log4j.appender.file_info.filter.F1.LevelMax=INFO
log4j.appender.file_info.append=true
log4j.appender.file_info.Encoding=UTF-8
log4j.appender.file_info.File=logs/concurrency/info/info.log
- ERROR 級別
輸出:項目名/erro/erro.log
策略:日誌文件每天,生成一個新文件
log4j.appender.file_error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file_error.DatePattern='_'yyyy-MM-dd
log4j.appender.file_error.layout=org.apache.log4j.PatternLayout
log4j.appender.file_error.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss} (%C:%L line)] %m%n
log4j.appender.file_error.Threshold=ERROR
log4j.appender.file_error.filter.F1=org.apache.log4j.varia.LevelRangeFilter
log4j.appender.file_error.filter.F1.LevelMin=ERROR
log4j.appender.file_error.filter.F1.LevelMax=ERROR
log4j.appender.file_error.append=true
log4j.appender.file_error.Encoding=UTF-8
log4j.appender.file_error.File=logs/concurrency/erro/error.log
- 控制檯輸出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.Encoding=UTF-8
log4j.appender.stdout.layout.ConversionPattern=[%-5p][%d{HH:mm:ss} %c{1}:%L line] %m%n
最後,設置項目日誌級別爲 INFO,使用前面定義的四種附加器
log4j.rootCategory=INFO,file_debug,file_info,file_error,stdout
四、日誌測試
- 測試代碼
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class LogTest {
public static void main(String[] args) {
log.debug("test debug!");
log.info("test info!");
log.error("test error!");
}
}
- 運行結果
控制檯,上面我們設置項目級別爲INFO,所以只輸出 INFO、ERROR級別日誌
- 對應日誌文件,博主這裏保留了之前產生的日誌文件
五、動態設置項目日誌級別
背景:修改日誌配置文件,無法立即生效,需要重新項目。在生成環境下,當然不能隨便重啓項目,可使用下面這種方式進行設置
import lombok.extern.slf4j.Slf4j;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Writer;
import java.util.Enumeration;
@Slf4j
@Controller
@RequestMapping("/logger")
public class LoggerController {
/**
* 設置指定包的日誌級別
* @param packageName 需要修改的包名
* @param logLevel 日誌級別
* @return
*/
@ResponseBody
@RequestMapping(value = "/change", method = RequestMethod.GET, produces = "application/json")
public String change(String packageName, String logLevel) {
try {
Level level = Level.toLevel(logLevel);
Logger logger = LogManager.getLogger(packageName);
logger.setLevel(level);
} catch (Exception e) {
return "失敗";
}
return "成功";
}
/**
* 修改全局日誌級別
* @param logLevel
* @return
*/
@ResponseBody
@RequestMapping(value = "/changeRoot", method = RequestMethod.GET, produces = "application/json")
public String change(String logLevel) {
try {
Level level = Level.toLevel(logLevel);
LogManager.getRootLogger().setLevel(level);
} catch (Exception e) {
return "失敗";
}
return "成功";
}
/**
* 查看現在包的日誌級別
* @param request
* @param response
*/
@RequestMapping(value = "/packageLoggers", method = RequestMethod.GET)
public void index(HttpServletRequest request, HttpServletResponse response) {
StringBuilder sb = new StringBuilder();
try {
sb.append("<html>");
Writer writer = response.getWriter();
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
Enumeration logs = LogManager.getCurrentLoggers();
while (logs.hasMoreElements()) {
Logger logger = (Logger) logs.nextElement();
sb.append("<span style='display:block;'>");
sb.append(logger.getName()).append(",").append(logger.getEffectiveLevel());
sb.append("</span>");
}
sb.append("</html>");
writer.write(sb.toString());
writer.flush();
if(writer != null){
writer.close();
}
log.info("項目日誌級別:{}", sb.toString());
} catch (Exception e) {
}
}
}
- 設置指定包
com.swotxu.webdemo.demo
日誌級別爲DEBUG
http://localhost:8080/logger/change?logLevel=DEBUG&packageName=com.swotxu.webdemo.demo2
- 設置全局日誌級別爲
DEBUG
http://localhost:8080/logger/changeRoot?logLevel=DEBUG
- 查看項目各包日誌級別
http://localhost:8080/logger/packageLoggers
大家如果有什麼疑問,歡迎評論留言!別忘了收藏關注~