私はブログの投稿 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);
}
}
以下のようなことができます。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);
}
}
}