web-dev-qa-db-ja.com

spring-webflux WebFilterでslf4j MDCを正しく使用する方法

私はブログの投稿 Reactor ContextとMDCによるコンテキストログ を参照しましたが、WebFilterでreactorコンテキストにアクセスする方法がわかりません。

@Component
public class RequestIdFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        List<String> myHeader =  exchange.getRequest().getHeaders().get("X-My-Header");

        if (myHeader != null && !myHeader.isEmpty()) {
            MDC.put("myHeader", myHeader.get(0));
        }

        return chain.filter(exchange);
    }
}
9
bitweaver

以下のようなことができます。contextには任意のクラスを設定できます。この例では、ヘッダーを使用しただけですが、カスタムクラスでも問題ありません。ここで設定すると、ハンドラーなどのロギングもcontextにアクセスできます。
以下のlogWithContextはMDCを設定し、後でそれをクリアします。もちろん、これは好きなものに置き換えることができます。

public class RequestIdFilter  implements WebFilter {

    private Logger LOG = LoggerFactory.getLogger(RequestIdFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        HttpHeaders headers = exchange.getRequest().getHeaders();
        return chain.filter(exchange)
                .doAfterSuccessOrError((r, t) -> logWithContext(headers, httpHeaders -> LOG.info("Some message with MDC set")))
                .subscriberContext(Context.of(HttpHeaders.class, headers));
    }

    static void logWithContext(HttpHeaders headers, Consumer<HttpHeaders> logAction) {
        try {
            headers.forEach((name, values) -> MDC.put(name, values.get(0)));
            logAction.accept(headers);
        } finally {
            headers.keySet().forEach(MDC::remove);
        }

    }

}
9
Kevin Hussey