登录Spring Boot-REST控制器和WebClient

时间:2019-06-21 14:17:49

标签: java spring-boot logging

我正在使用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实例中使​​用日志记录类,还是需要针对这两种情况编写单独的代码?

0 个答案:

没有答案