如何在logback.xml中自定義動態屬性
原文地址:http://blog.jboost.cn/trick-logback-prop.html
當使用logback來記錄Web應用的日誌時,我們通過在logback.xml中配置appender來指定日誌輸出格式及輸出檔案路徑,這在一臺主機或一個檔案系統上部署單個例項沒有問題,但是如果部署多個例項(比如通過容器的方式),多個例項同時往同一檔案寫日誌可能就會引起問題。這時可以將每個例項的日誌檔案加以區分,如IP或UUID,或兩者結合的形式。這其實就涉及如何在logback.xml中自定義動態屬性的問題。
可以有4種方式來實現logback.xml中獲取自定義變數值:
- 通過設定環境變數或傳遞系統屬性(比如在程式啟動時通過-D傳遞)的方式,兩者是可以直接在logback.xml中通過
${變數名}
- 自定義logback.xml的載入時機,在其載入前將需要設定的屬性注入到logback的context中,這種方式相對複雜,本文不討論。
- 通過實現PropertyDefiner介面來提供屬性值設定
- 通過實現LoggerContextListener介面來設定屬性值
第一種方式簡單,但不能通過程式生成屬性值,第二種方式稍顯複雜,本文主要介紹後兩種方式。
PropertyDefiner方式
首先定義一個類,實現PropertyDefiner介面,可以通過繼承PropertyDefinerBase會更方便
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拼接到日誌檔名中,以區分不同例項,避免儲存到同一位置時的覆蓋衝突問題 * @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)及獲取屬性值的實現類,這樣就可以在配置中通過 ${localIP}
來引用該屬性值了。在實現方法 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方式
定義一個實現LoggerContextListener介面的類,在start方法中,將需要設定的屬性設定到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; /*** * 第二種實現方式 * @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; } //省略了其它函式
然後在logback.xml中,配置如上監聽器類,這樣就可以通過 ${localIP}
獲取到上面 context.putProperty("localIP", getUniqName());
設定的值了。
<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> # 省略了其它配置
這種方式能設定任意個數的屬性值,比前一種方式靈活。
總結
在logback.xml中獲取自定義屬性值,主要是需要在載入前將對應的屬性值進行設定,這樣載入時才能有效獲取。本文雖是自定義日誌檔名稱,但不侷限於此,所有需要動態獲取的變數都可以按這種方式實現。
如果覺得有幫助,請幫忙轉發、推薦。歡迎關注我的微信公眾號:jboost-ksxy
———————————————————————————————————————————————————————————————