1. 程式人生 > >Logback中%X的使用

Logback中%X的使用

1. 參考資料

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.