Logback中%X的使用
阿新 • • 發佈:2018-11-01
1. 參考資料
- https://gist.github.com/logogin/ff44c254f655340b653c
- http://www.cnblogs.com/zhudongchang/p/6861375.html
2. 環境
Java: jdk1.8.0_144
Logback: 1.0.13
3. %X
的使用方法
%X用於輸出和當前執行緒相關聯的NDC(巢狀診斷環境),在程式碼中給org.slf4j.MDC新增key/value即可增加新值
示例 | 說明 |
---|---|
%X | 輸出所有值 |
%X{testKey} | 輸出testKey所對應的value,且無預設值 |
%X{testKey:-} | 輸出testKey所對應的value,預設為空 |
%X{testKey:-aaa} | 輸出testKey所對應的value,預設為aaa |
測試程式碼
public class AbstractLogWrapper<T> { private final T job; private final Map<?, ?> context; public AbstractLogWrapper(T t) { this.job = t; this.context = MDC.getCopyOfContextMap(); } public void setLogContext() { if (this.context != null) { MDC.setContextMap(this.context); } } public void clearLogContext() { MDC.clear(); } public T getJob() { return this.job; } } public class LogSupplier<T> extends AbstractLogWrapper<Supplier<T>> implements Supplier<T> { public LogSupplier(Supplier<T> supplier) { super(supplier); } @Override public T get() { this.setLogContext(); try { return getJob().get(); } finally { this.clearLogContext(); } } } @RunWith(MockitoJUnitRunner.class) public class LogSupplierTest { private static final Logger LOGGER = LoggerFactory.getLogger(LogSupplierTest.class); private ExecutorService executorService; @Before public void setUp() { executorService = Executors.newFixedThreadPool(2); } @Test public void testGet() { AtomicInteger counter = new AtomicInteger(0); Supplier<String> supplier = () -> { String rtn = String.valueOf(counter.incrementAndGet()); // 往MDC中新增內容 MDC.put(RunnabeTestHelper.RUNNABLE, rtn); LOGGER.info("This is {} supplier.", rtn); return rtn; }; LogSupplier<String> logSupplier = Mockito.spy(new LogSupplier<>(supplier)); Set<String> set = new HashSet<>(); Mockito.doAnswer(invocation -> set.add(invocation.getMethod().getName())).when(logSupplier).setLogContext(); Mockito.doAnswer(invocation -> set.add(invocation.getMethod().getName())).when(logSupplier).clearLogContext(); List<CompletableFuture<String>> futures = IntStream.rangeClosed(0, 4).mapToObj(index -> CompletableFuture.supplyAsync(logSupplier, executorService)).collect(Collectors.toList()); futures.forEach(CompletableFuture::join); Assert.assertEquals("[setLogContext, clearLogContext]", set.toString()); } } class RunnabeTestHelper { static final String RUNNABLE = "runn_able"; }
- 輸出所有
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="stdot" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%X %m%n</pattern> </layout> </appender> <root level="debug"> <appender-ref ref="stdot"/> </root> </configuration>
結果
runn_able=1 This is 1 supplier.
runn_able=3 This is 3 supplier.
runn_able=2 This is 2 supplier.
runn_able=4 This is 4 supplier.
runn_able=5 This is 5 supplier.
- 輸出特定值(不指定預設值/預設空/預設非空)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="stdot" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%X{runn_able} %X{runn_able:-} %X{runnable:-aaa} %m%n</pattern>
</layout>
</appender>
<root level="debug">
<appender-ref ref="stdot"/>
</root>
</configuration>
結果
1 1 aaa This is 1 supplier.
2 2 aaa This is 2 supplier.
3 3 aaa This is 3 supplier.
5 5 aaa This is 5 supplier.
4 4 aaa This is 4 supplier.
4. 與%replace
的配合使用
示例 | 說明 |
---|---|
%replace(p ){r, t} | p 為日誌內容,r 是正則表示式,將p 中符合r 的內容替換為t |
- 把只有key沒有value內容從日誌中替換掉
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="stdot" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%replace(Test_Method=%X{method} runn-able=%X{runn_able}){'.+=( |$)', ''} -> %m%n</pattern>
</layout>
</appender>
<root level="debug">
<appender-ref ref="stdot"/>
</root>
</configuration>
結果
runn-able=2 -> This is 2 supplier.
runn-able=3 -> This is 3 supplier.
runn-able=4 -> This is 4 supplier.
runn-able=5 -> This is 5 supplier.
runn-able=1 -> This is 1 supplier.