1

我有以下拦截器,它基于为每个请求保存和恢复存储在 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 上下文。

谢谢

4

1 回答 1

0

您可以尝试改用 HandlerInterceptorAdapter

检查:https ://www.logicbig.com/how-to/code-snippets/jcode-spring-mvc-deferredresultprocessinginterceptor.html

于 2019-05-28T16:18:51.950 回答