logback 動態配置
寫在前面
在做java日誌之前,強烈建議大家讀一下這篇java日誌的前世今生,對理清java日誌框架很有幫助!
奉上地址: 一個著名的日誌系統是怎麼設計出來的
然後說一下,爲啥要使用動態日誌配置。對於業務系統來講,有些日誌並非必須日誌,但是對於調試是很重要的,當我們需要監控一個時段的日誌,而過去這個時段,我們便不需要這些日誌了,我們就可以通過命令,或者請求,動態開啓日誌輸出,不想要日誌時,動態關閉日誌即可。
對於試運行階段的項目,我們需要收集比較詳細的日誌,當我們認爲系統穩定了,沒有問題了,就可以動態關閉日誌。
再者,有需求,我們的日誌輸出源發生改變,比如ELK變爲了kafka ,我們在不停止服務的情況下,就可以動態操作,修改掉輸出對象。
簡述java日誌框架
spring boot 默認的日誌框架爲 slf4j+logback 。這裏也強烈建議寫日誌時面向 slf4j(面向接口),幾乎目前主流的日誌框架(指java日誌框架)都實現了slf4j,因此面向slf4j寫日誌,日誌框架非常容易遷移。
例如將log4j2 遷移爲 logback ,只需要修改部分配置文件即可。
logback的執行步驟 :
logback的主要對象
對象 | 簡述 |
---|---|
LoggerContext | logback的核心對象,加載配置文件,存儲loggerList……是log back的核心容器 |
Logger | 這個Logger爲logback的logger 它實現了slf4j的Logger對象,除了實現了所有的logger方法外,我們動態配置日誌輸出源,也需要裏面的 addAppender(),detachAppender()方法 |
Appender | 日誌輸出的最終實現, doAppend(E e)方法,最終實現了日誌的輸出,如果自定義appender 需要最終實現該接口 |
注:以上對象並非logback全部核心對象,對於今天的日誌動態輸出,僅僅涉及到以上核心對象。
實現logback 動態改變日誌級別
實現流程如下 :
下面附上測試源代碼:
package com.kgo.logger.logback;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import com.kgo.logger.appender.DemoAppender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ContextTest {
public static final String demoApName = "demo";
public static void main(String[] args) {
// 定義日誌輸出
Logger logger = LoggerFactory.getLogger(ContextTest.class);
logger.debug("=== 我輸出了 === ");
// 第一步:獲取日誌上下文
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
// 第二步:獲取日誌對象 (日誌是有繼承關係的,關閉上層,下層如果沒有特殊說明也會關閉)
ch.qos.logback.classic.Logger logbackLogger = lc.getLogger("com.kgo.logger.logback");
ch.qos.logback.classic.Logger rootLogger = lc.getLogger("root");
// 第三步:修改日誌級別
logbackLogger.setLevel(Level.INFO);
logger.debug("===== 我是 debug =====");
logger.info("===== 我是 info =====");
logger.error("===== 我是 ERROR =====");
}
}
輸出結果如下:
可以看到 日誌級別修改爲INFO之後,日誌 “===== 我是 debug =====” 沒有輸出
logback 基本選擇規則如下 :
動態添加刪除 appender
實現步驟和 修改日誌級別基本一致,流程如下:
附上測試代碼:
package com.kgo.logger.logback;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChangeAppender {
public static final String demoApName = "demo";
public static void main(String[] args) {
// 定義日誌輸出
Logger logger = LoggerFactory.getLogger(ContextTest.class);
logger.debug("=== 我輸出了 === \n ");
// 第一步:獲取日誌上下文
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
// 第二步:獲取日誌對象 (日誌是有繼承關係的,關閉上層,下層如果沒有特殊說明也會關閉)
ch.qos.logback.classic.Logger logbackLogger = lc.getLogger("com.kgo.logger.logback");
ch.qos.logback.classic.Logger rootLogger = lc.getLogger("root");
// 第三步:移除 appender
logbackLogger.detachAppender("STDOUT");
logger.debug("僅僅移除 com.kgo.logger.logback 的 appender");
logger.debug("===== 我是 debug =====");
logger.info("===== 我是 info =====");
logger.error("===== 我是 ERROR =====");
rootLogger.detachAppender("STDOUT");
logger.debug("\n 僅僅移除root 的 appender");
logger.debug("===== 我是 debug =====");
logger.info("===== 我是 info =====");
logger.error("===== 我是 ERROR =====");
}
}
在執行這段代碼的時候我在本地已經配置的 logback-test.xml ,其中 “STDOUT” 便是在該文件中做的配置,配置如下:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
<logger name="com.kgo.logger.logback" level="DEBUG" >
<appender-ref ref="STDOUT" />
</logger>
</configuration>
輸出結果如下:
- 在配置文件裏配置了兩個 Logger ,都輸出給 STDOUT appender ,因此 “ === 我輸出了 === ” 被打印了兩次,
- 當我移除掉了名字爲 “ com.kgo.logger.logback” Logger的Appender , 下面的 日誌僅輸出了一次 (Root 的輸出),
- 當將root的appender 也移除掉後,日誌不在輸出(沒有了輸出對象)。
就先分享到這裏,接下里會寫一篇 自定義appender ,並且動態添加append的 博客 ,本系列的博客目標 爲 實現 日誌的 全自動化
包括:收集,上傳,分類 ,自定義字段,實時更新,elk 等。
如果感覺有用,點個贊再走吧,大佬
------------------------------------------------------- 這就是我的底線了 --------------------------------------------------------------