log4J2自定义pattern参数输出
log4j2官网地址:http://logging.apache.org/log4j/2.x/manual/extending.html#PatternConverters
原文地址https://blog.csdn.net/hfismyangel/article/details/80182662
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.pattern.ConverterKeys;
import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
import org.apache.logging.log4j.core.pattern.PatternConverter;
@Plugin(name = "TIDPatternConverter", category = PatternConverter.CATEGORY)//Plugin 表示的是这是一个插件,name是名称,category为PatternConverter.CATEGORY(目前插件只有这个选择)ConverterKeys表示的就是自定义的参数,可以多个
@ConverterKeys({ "T", "TID" }) //
public class TIDPatternConverter extends LogEventPatternConverter { //定义一个类继承LogEventPatternConverter
private static final TIDPatternConverter INSTANCE = new TIDPatternConverter();
public static TIDPatternConverter newInstance( //定义的这个类必须提供一个newInstance方法,参数是final String[] options,返回值为定义的类(对于是否是单例没有明确的要求)
final String[] options) {
return INSTANCE;
}
private TIDPatternConverter(){ //提供一个私有的构造函数,调用父类的构造函数,函数需要提供两个参数 第一个参数是转换器的名称,第二个是css样式
super("TID", "TID");
}
@Override
public void format(LogEvent event, StringBuilder toAppendTo) { //还有主要的工作format,这里有两个参数,LogEvent是系统已经存在的一些可选数据,StringBuilder 表示的是最终的输出字符流。一般都是将自定义的append进去
toAppendTo.append(Thread.currentThread().getId());
}
}
定义好了之后,然后在log4j2的配置文件中设置
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn"
packages="com.hoperun.zhulongxiang.asnc_print_different_logfile">
<Appenders>
<console name="console" target="system_out">
<!-- 只输出level及以上级别的信息(onmatch),其他的直接拒绝(onmismatch)。默认就是trace。
<thresholdfilter
level="trace" onmatch="accept" onmismatch="deny"/> -->
<patternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-10T] [%-5level] %l - %m%n" />
</console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="console" />
</Root>
</Loggers>
</Configuration>
这个方法好像自己试了下没有试通,这个T本来就有,可以直接用(待定)
下面这个方法使用log4j2自带的功能 MDC
<DynamicThresholdFilter key="loginId" defaultThreshold="ERROR" onMatch="ACCEPT" onMismatch="DENY"> <KeyValuePair key="User1" value="DEBUG" /> </DynamicThresholdFilter>
<File name="testUserLog" fileName="target/testUserLog2" append="true">
<ThreadContextMapFilter onMatch="ACCEPT" onMismatch="DENY">
<KeyValuePair key="loginId" value="User1" />
</ThreadContextMapFilter>
<PatternLayout pattern="%n%t %-5p %c{2} MDC%X - %m" />
</File>
import java.util.UUID;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class TestRequestListener implements ServletRequestListener {
protected static final Logger LOGGER = LoggerFactory.getLogger(TestRequestListener.class);
public void requestInitialized(ServletRequestEvent arg0) {
ThreadContext.put("id", UUID.randomUUID().toString());
}
public void requestDestroyed(ServletRequestEvent arg0) {
ThreadContext.clearMap();
}
}
在log4j2.xml文件中使用 %X{id}
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn"
packages="com.hoperun.zhulongxiang.asnc_print_different_logfile">
<Appenders>
<console name="console" target="system_out">
<patternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} {%X{id}} [%-5level] %l - %m%n" />
</console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="console" />
</Root>
</Loggers>
</Configuration>
以上是log4j2的配置,使用log4j可以继承patternLayout和patternParser,自定义一个patternConverter实现。如下:自己还没有亲自试过下面的方法
https://blog.csdn.net/huaieli1/article/details/58601306
import org.apache.log4j.helpers.FormattingInfo;
import org.apache.log4j.helpers.PatternConverter;
import org.apache.log4j.helpers.PatternParser;
import org.apache.log4j.spi.LoggingEvent;
public class ExPatternParser extends PatternParser {
public ExPatternParser(String pattern) {
super(pattern);
}
/**
* 重写finalizeConverter,对特定的占位符进行处理,T表示线程ID占位符
*/
@Override
protected void finalizeConverter(char c) {
if (c == 'T') {
this.addConverter(new ExPatternConverter(this.formattingInfo));
} else {
super.finalizeConverter(c);
}
}
private static class ExPatternConverter extends PatternConverter {
public ExPatternConverter(FormattingInfo fi) {
super(fi);
}
/**
* 当需要显示线程ID的时候,返回当前调用线程的ID
*/
@Override
protected String convert(LoggingEvent event) {
return String.valueOf(Thread.currentThread().getId());
}
}
}
import org.apache.log4j.PatternLayout;
import org.apache.log4j.helpers.PatternParser;
public class ExPatternLayout extends PatternLayout {
public ExPatternLayout(String pattern) {
super(pattern);
}
public ExPatternLayout() {
super();
}
/**
* 重写createPatternParser方法,返回PatternParser的子类
*/
@Override
protected PatternParser createPatternParser(String pattern) {
return new ExPatternParser(pattern);
}
}
修改Log4j的配置文件,将输出样式修改为拓展类ExPatternLayout
#设置输出样式 log4j.appender.appender1.layout=org.apache.log4j.ExPatternLayout
到此已经扩展完成,将以上内容编译后(可以打成jar包)和log4j.jar一同使用(使用同一个类装载器装载),然后配置log4j.properties类,修改
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout为
log4j.appender.stdout.layout=ex.log4j.ExPatternLayout
在输出格式中增加%T(log4j定义%t表示线程名称,%T没有定义,所以这里使用%T表示线程ID),log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %T %c %5p - %m%n
下面就按照平常的习惯使用log4j即可,再输出的日志中就会包含线程ID,例如:2009-03-29 10:43:58 1 test.log.Log4jTest INFO - ok
时间后面的'1'就表示线程id,当在多线程环境下,例如web环境,用这种方式就能很容易区分出一次web请求过程中打印出的日志信息,而不会和其他web请求打印出的日志信息混淆。这样即增加的日志的可读性,也不会输出太多的无用信息。

浙公网安备 33010602011771号