我有以下拦截器,它基于为每个请求保存和恢复存储在 MDC 上下文中的一些变量来跟踪请求/响应。
public class LoggingInterceptor implements DeferredResultProcessingInterceptor {
private final HelloSeeYouLogger helloSeeYouLogger;
private static final String X_UOW = "X-UOW";
private static final String X_REQUEST_ID = "X-RequestId";
private Map<String, String> context;
public LoggingInterceptor(HelloSeeYouLogger helloSeeYouLogger) {
this.helloSeeYouLogger = helloSeeYouLogger;
}
@Override
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) {
addUowAndRequestIdToMDC(request.getHeader(X_UOW), request.getHeader(X_REQUEST_ID));
final String uri = getUri((HttpServletRequest) request.getNativeRequest());
helloSeeYouLogger.logHelloThere(uri);
context = MDC.getCopyOfContextMap();
}
@Override
public <T> void afterCompletion(NativeWebRequest request, DeferredResult<T> deferredResult) {
if (context != null) {
MDC.setContextMap(context);
}
final String uri = getUri((HttpServletRequest) request.getNativeRequest());
String body = getBody((HttpServletRequest) request.getNativeRequest());
if (!StringUtils.isEmpty(body)) {
body = replaceMoreThanOneSpacesWithOneSpace(hideCreditCardNumber(body));
}
helloSeeYouLogger.logSeeYou(uri, body);
clearUowAndRequestIdFromMDC();
}
public static void addUowAndRequestIdToMDC(final String uow, final String requestId) {
//This NewRelic stuff shouldn't be here as it is used for distributed tracing and not logging.
// However it helps to levarage requests tracking from a metric service such as new relic to a log aggregation service
//such as ELK.
NewRelic.addCustomParameter(UOW, uow);
NewRelic.addCustomParameter(REQUEST_ID, requestId);
MDC.put(UOW, uow);
MDC.put(REQUEST_ID, requestId);
}
public static void clearUowAndRequestIdFromMDC() {
if (MDC.get(UOW) != null) {
MDC.remove(UOW);
}
if (MDC.get(REQUEST_ID) != null) {
MDC.remove(REQUEST_ID);
}
}
我认为我会遇到并发问题,因为上下文是一个实例变量,并且在运行多个并发线程时保存和恢复 MDC 上下文会导致错误的结果。同样使用 synchronize 关键字会增加性能问题。我想知道当弹簧控制器返回 DeferredResult 时是否有更好的方法来跟踪 MDC 上下文。
谢谢