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

大家如果有什麼疑問,歡迎評論留言!別忘了收藏關注~

發佈了6 篇原創文章 · 獲贊 5 · 訪問量 776
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章