Вход в Spring Boot - контроллеры REST и WebClient - PullRequest
0 голосов
/ 21 июня 2019

Я создаю микросервис с помощью Spring Boot и пытаюсь разработать для него решение для ведения журнала. На данный момент я использую этот класс для регистрации запросов / ответов.

@Component
@Slf4j
public class RequestAndResponseLoggingFilter implements Filter {

    private static void logRequest(ContentCachingRequestWrapper request) {
        String queryString = request.getQueryString();
        if (queryString == null) {
            log.info("{} {}", request.getMethod(), request.getRequestURI());
        } else {
            log.info("{} {}?{}", request.getMethod(), request.getRequestURI(), queryString);
        }
        Collections.list(request.getHeaderNames()).forEach(headerName ->
                Collections.list(request.getHeaders(headerName)).forEach(headerValue ->
                        log.info("{}: {}", headerName, headerValue)));

        byte[] content = request.getContentAsByteArray();
        if (content.length > 0) {
            logContent(content, request.getContentType(), request.getCharacterEncoding());
        }
    }

    private static void logResponse(ContentCachingResponseWrapper response) {
        int status = response.getStatus();
        log.info("{} {}", status, HttpStatus.valueOf(status).getReasonPhrase());
        response.getHeaderNames().forEach(headerName ->
                response.getHeaders(headerName).forEach(headerValue ->
                        log.info("{}: {}", headerName, headerValue)));

        byte[] content = response.getContentAsByteArray();
        if (content.length > 0) {
            logContent(content, response.getContentType(), response.getCharacterEncoding());
        }
    }

    private static void logContent(byte[] content, String contentType, String contentEncoding) {
            try {
                String contentString = new String(content, contentEncoding);
                contentString = contentString.replace("\n", "").replace("\t", "");
                Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> log.info("{}", line));
            } catch (UnsupportedEncodingException e) {
                log.info("[{} bytes content]", content.length);
            }

    }

    private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) {
        if (request instanceof ContentCachingRequestWrapper) {
            return (ContentCachingRequestWrapper) request;
        } else {
            return new ContentCachingRequestWrapper(request);
        }
    }

    private static ContentCachingResponseWrapper wrapResponse(HttpServletResponse response) {
        if (response instanceof ContentCachingResponseWrapper) {
            return (ContentCachingResponseWrapper) response;
        } else {
            return new ContentCachingResponseWrapper(response);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {
        log.info("Initializing Request and Response Logging Filter");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        doFilterWrapped(wrapRequest(request), wrapResponse(response), filterChain);
    }

    @Override
    public void destroy() {

    }

    protected void doFilterWrapped(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response,
            FilterChain filterChain) throws ServletException, IOException {
        try {
            filterChain.doFilter(request, response);
        } finally {
            logRequestResponse(request, response);
            response.copyBodyToResponse();
        }
    }

    protected void logRequestResponse(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) {
        if (log.isInfoEnabled()) {
            logRequest(request);
            logResponse(response);
        }
    }
}

Этот класс отлично работает для меня: он печатает запрос и соответствующий ответ. Мой микросервис делает REST-вызовы на другие микросервисы и для этого я использую WebClient:

public testClient(ServiceConfig serviceConfig) {
    this.webClient = WebClient.builder()
            .filter(new TracingExchangeFilterFunction(GlobalTracer.get(),
                    Collections.singletonList(new WebClientSpanDecorator.StandardTags())))
            .baseUrl(serviceConfig.getMockUri())
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
            .build();
}

Проблема в том, что когда я запускаю свой микросервис, класс, отвечающий за ведение журнала, не "ловит" запрос / ответ, сделанный этим экземпляром WebClient.

1) Можете ли вы объяснить мне, почему это происходит?

2) Я также провел небольшой поиск и нашел фрагмент кода, который может регистрировать запрос, сделанный WebClient, и печатать то, что я хочу:

private ExchangeFilterFunction logRequest() {
    return (clientRequest, next) -> { 
        logger.info("Request: {} {}", clientRequest.method(), 
        clientRequest.url());
        clientRequest.headers()
            .forEach((name, values) -> values.forEach(value -> logger.info("{}= 
{}", name, value)));
        return next.exchange(clientRequest);
    };
}

Есть ли способ, которым я могу использовать свой класс ведения журнала в моем экземпляре WebClient или мне нужно написать отдельный код для этих двух случаев?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...