在logback.xml中自定义动态属性的方法
当使用logback来记录Web应用的日志时,我们通过在logback.xml中配置appender来指定日志输出格式及输出文件路径,这在一台主机或一个文件系统上部署单个实例没有问题,但是如果部署多个实例(比如通过容器的方式),多个实例同时往同一文件写日志可能就会引起问题。这时可以将每个实例的日志文件加以区分,如IP或UUID,或两者结合的形式。这其实就涉及如何在logback.xml中自定义动态属性的问题。
可以有4种方式来实现logback.xml中获取自定义变量值:
- 通过设置环境变量或传递系统属性(比如在程序启动时通过-D传递)的方式,两者是可以直接在logback.xml中通过${变量名}获取的。
- 自定义logback.xml的加载时机,在其加载前将需要设置的属性注入到logback的context中,这种方式相对复杂,本文不讨论。
- 通过实现PropertyDefiner接口来提供属性值设置
- 通过实现LoggerContextListener接口来设置属性值
第一种方式简单,但不能通过程序生成属性值,第二种方式稍显复杂,本文主要介绍后两种方式。
PropertyDefiner方式
首先定义一个类,实现PropertyDefiner接口,可以通过继承PropertyDefinerBase会更方便
importch.qos.logback.core.PropertyDefinerBase;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importjava.net.InetAddress;
importjava.net.UnknownHostException;
importjava.util.UUID;
/***
*将本地IP拼接到日志文件名中,以区分不同实例,避免存储到同一位置时的覆盖冲突问题
*@Authorronwxy
*@Date2019/8/2016:17
*/
publicclassIPLogDefinerextendsPropertyDefinerBase{
privatestaticfinalLoggerLOG=LoggerFactory.getLogger(IPLogDefiner.class);
privateStringgetUniqName(){
StringlocalIp=null;
try{
localIp=InetAddress.getLocalHost().getHostAddress();
}catch(UnknownHostExceptione){
LOG.error("failtogetip...",e);
}
StringuniqName=UUID.randomUUID().toString().replace("-","");
if(localIp!=null){
uniqName=localIp+"-"+uniqName;
}
returnuniqName;
}
@Override
publicStringgetPropertyValue(){
returngetUniqName();
}
}
然后在logback.xml中,添加
UTF-8 D:\\logs\\elk\\interface-${localIP}.log INFO #省略了其它配置
LoggerContextListener方式
定义一个实现LoggerContextListener接口的类,在start方法中,将需要设置的属性设置到logback的Context中,
importch.qos.logback.classic.Level;
importch.qos.logback.classic.Logger;
importch.qos.logback.classic.LoggerContext;
importch.qos.logback.classic.spi.LoggerContextListener;
importch.qos.logback.core.Context;
importch.qos.logback.core.spi.ContextAwareBase;
importch.qos.logback.core.spi.LifeCycle;
importjava.net.InetAddress;
importjava.net.UnknownHostException;
importjava.util.UUID;
/***
*第二种实现方式
*@Authorronwxy
*@Date2019/8/2018:45
*/
publicclassLoggerStartupListenerextendsContextAwareBase
implementsLoggerContextListener,LifeCycle{
privatebooleanstarted=false;
@Override
publicvoidstart(){
if(started){
return;
}
Contextcontext=getContext();
context.putProperty("localIP",getUniqName());
started=true;
}
privateStringgetUniqName(){
StringlocalIp=null;
try{
localIp=InetAddress.getLocalHost().getHostAddress();
}catch(UnknownHostExceptione){
//LOG.error("failtogetip...",e);
}
StringuniqName=UUID.randomUUID().toString().replace("-","");
if(localIp!=null){
uniqName=localIp+"-"+uniqName;
}
returnuniqName;
}
//省略了其它函数
然后在logback.xml中,配置如上监听器类,这样就可以通过${localIP}获取到上面context.putProperty("localIP",getUniqName());设置的值了。
UTF-8 D:\\logs\\elk\\interface-${localIP}.log INFO #省略了其它配置
这种方式能设置任意个数的属性值,比前一种方式灵活。
总结
在logback.xml中获取自定义属性值,主要是需要在加载前将对应的属性值进行设置,这样加载时才能有效获取。本文虽是自定义日志文件名称,但不局限于此,所有需要动态获取的变量都可以按这种方式实现。