在logback.xml中自定義動(dòng)態(tài)屬性的方法
當(dāng)使用logback來(lái)記錄Web應(yīng)用的日志時(shí),我們通過(guò)在logback.xml中配置appender來(lái)指定日志輸出格式及輸出文件路徑,這在一臺(tái)主機(jī)或一個(gè)文件系統(tǒng)上部署單個(gè)實(shí)例沒(méi)有問(wèn)題,但是如果部署多個(gè)實(shí)例(比如通過(guò)容器的方式),多個(gè)實(shí)例同時(shí)往同一文件寫(xiě)日志可能就會(huì)引起問(wèn)題。這時(shí)可以將每個(gè)實(shí)例的日志文件加以區(qū)分,如IP或UUID,或兩者結(jié)合的形式。這其實(shí)就涉及如何在logback.xml中自定義動(dòng)態(tài)屬性的問(wèn)題。
可以有4種方式來(lái)實(shí)現(xiàn)logback.xml中獲取自定義變量值:
- 通過(guò)設(shè)置環(huán)境變量或傳遞系統(tǒng)屬性(比如在程序啟動(dòng)時(shí)通過(guò)-D傳遞)的方式,兩者是可以直接在logback.xml中通過(guò) ${變量名} 獲取的。
- 自定義logback.xml的加載時(shí)機(jī),在其加載前將需要設(shè)置的屬性注入到logback的context中,這種方式相對(duì)復(fù)雜,本文不討論。
- 通過(guò)實(shí)現(xiàn)PropertyDefiner接口來(lái)提供屬性值設(shè)置
- 通過(guò)實(shí)現(xiàn)LoggerContextListener接口來(lái)設(shè)置屬性值
第一種方式簡(jiǎn)單,但不能通過(guò)程序生成屬性值,第二種方式稍顯復(fù)雜,本文主要介紹后兩種方式。
PropertyDefiner方式
首先定義一個(gè)類(lèi),實(shí)現(xiàn)PropertyDefiner接口,可以通過(guò)繼承PropertyDefinerBase會(huì)更方便
import ch.qos.logback.core.PropertyDefinerBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.UUID;
/***
* 將本地IP拼接到日志文件名中,以區(qū)分不同實(shí)例,避免存儲(chǔ)到同一位置時(shí)的覆蓋沖突問(wèn)題
* @Author ronwxy
* @Date 2019/8/20 16:17
*/
public class IPLogDefiner extends PropertyDefinerBase {
private static final Logger LOG = LoggerFactory.getLogger(IPLogDefiner.class);
private String getUniqName() {
String localIp = null;
try {
localIp = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
LOG.error("fail to get ip...", e);
}
String uniqName = UUID.randomUUID().toString().replace("-", "");
if (localIp != null) {
uniqName = localIp + "-" + uniqName;
}
return uniqName;
}
@Override
public String getPropertyValue() {
return getUniqName();
}
}
然后在logback.xml中,添加 <define> 配置,指定屬性名(本例中為localIP)及獲取屬性值的實(shí)現(xiàn)類(lèi),這樣就可以在配置中通過(guò) ${localIP}來(lái)引用該屬性值了。在實(shí)現(xiàn)方法 getPropertyValue 中返回你需要生成的值,本例中是返回 本地IP-UUID 的形式。
<configuration>
<define name="localIP" class="cn.jboost.common.IPLogDefiner"/>
<appender name="interfaceLogFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoding>UTF-8</encoding>
<File>D:\\logs\\elk\\interface-${localIP}.log</File>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
# 省略了其它配置
LoggerContextListener方式
定義一個(gè)實(shí)現(xiàn)LoggerContextListener接口的類(lèi),在start方法中,將需要設(shè)置的屬性設(shè)置到logback的Context中,
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggerContextListener;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.spi.ContextAwareBase;
import ch.qos.logback.core.spi.LifeCycle;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.UUID;
/***
* 第二種實(shí)現(xiàn)方式
* @Author ronwxy
* @Date 2019/8/20 18:45
*/
public class LoggerStartupListener extends ContextAwareBase
implements LoggerContextListener, LifeCycle {
private boolean started = false;
@Override
public void start() {
if (started) {
return;
}
Context context = getContext();
context.putProperty("localIP", getUniqName());
started = true;
}
private String getUniqName() {
String localIp = null;
try {
localIp = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
//LOG.error("fail to get ip...", e);
}
String uniqName = UUID.randomUUID().toString().replace("-", "");
if (localIp != null) {
uniqName = localIp + "-" + uniqName;
}
return uniqName;
}
//省略了其它函數(shù)
然后在logback.xml中,配置如上監(jiān)聽(tīng)器類(lèi),這樣就可以通過(guò) ${localIP} 獲取到上面 context.putProperty("localIP", getUniqName()); 設(shè)置的值了。
<configuration>
<!--<define name="localIP" class="com.cnbot.common.IPLogDefiner"/>-->
<contextListener class="cn.jboost.common.LoggerStartupListener"/>
<define name="localIP" class="com.cnbot.common.IPLogDefiner"/>
<appender name="interfaceLogFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoding>UTF-8</encoding>
<File>D:\\logs\\elk\\interface-${localIP}.log</File>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
# 省略了其它配置
這種方式能設(shè)置任意個(gè)數(shù)的屬性值,比前一種方式靈活。
總結(jié)
在logback.xml中獲取自定義屬性值,主要是需要在加載前將對(duì)應(yīng)的屬性值進(jìn)行設(shè)置,這樣加載時(shí)才能有效獲取。本文雖是自定義日志文件名稱(chēng),但不局限于此,所有需要?jiǎng)討B(tài)獲取的變量都可以按這種方式實(shí)現(xiàn)。
相關(guān)文章
springboot下添加日志模塊和設(shè)置日志文件輸出的方法
日志的使用將通過(guò)SLF4J來(lái)使用,SLF4J是一個(gè)為Java應(yīng)用提供簡(jiǎn)單日志記錄的接口,在Spring框架中,SLF4J常常用于處理框架本身以及應(yīng)用程序的日志記錄,本文給大家介紹springboot下添加日志模塊和設(shè)置日志文件輸出的相關(guān)知識(shí),感興趣的朋友一起看看吧2023-12-12
淺談Java內(nèi)部類(lèi)——靜態(tài)內(nèi)部類(lèi)
這篇文章主要介紹了Java靜態(tài)內(nèi)部類(lèi)的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java內(nèi)部類(lèi)的相關(guān)知識(shí),感興趣的朋友可以了解下2020-08-08
Java實(shí)現(xiàn)mybatis批量插入數(shù)據(jù)到Oracle
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)mybatis批量插入數(shù)據(jù)到Oracle 的相關(guān)資料,需要的朋友可以參考下2016-06-06
SpringBoot-RestTemplate如何實(shí)現(xiàn)調(diào)用第三方API
這篇文章主要介紹了SpringBoot-RestTemplate實(shí)現(xiàn)調(diào)用第三方API的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
SpringBoot文件訪問(wèn)映射如何實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot文件訪問(wèn)映射如何實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
MyBatis中使用分頁(yè)插件PageHelper實(shí)現(xiàn)分頁(yè)功能
分頁(yè)是經(jīng)常使用的功能,本文主要介紹了Mybatis中處理特殊SQL處理邏輯,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Mybatis-plus的selectPage()分頁(yè)查詢不生效問(wèn)題解決
本文主要介紹了Mybatis-plus的selectPage()分頁(yè)查詢不生效問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01

