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請求打印出的日志信息混淆。這樣即增加的日志的可讀性,也不會輸出太多的無用信息。