Я создаю микросервис с помощью 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 или мне нужно написать отдельный код для этих двух случаев?