I need log HttpRequest body and HttpResponse body in custom format. For example "Send request. Headers: {}, Body: {}, uri: {}"
How can I get request body?
I'm try this:
log.info("Send request. Headers: {}, Body: {}, uri: {}", request, headers, path);
return webClient.post()
.uri(path)
.headers(httpHeaders -> {....})
.bodyValue(request)...
But in this case, the log does not correspond to the fact of sending the request, but is only part of the reactor pipeline being formed
Can I log HttpRequest body and HttpResponse body in custom format in the moment of send/received this?
You can use RequestBodyAdviceAdapter & ResponseBodyAdvice for logging request-body, headers etc.
Please find the code snippets.
CustomResponseBodyAdviceAdapter.class.
import com.pmi.hyperface.constants.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ControllerAdvice
public class CustomResponseBodyAdviceAdapter implements ResponseBodyAdvice<Object> {
@Autowired
private LoggingService loggingService;
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType,
Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
if (serverHttpRequest instanceof ServletServerHttpRequest
&& serverHttpResponse instanceof ServletServerHttpResponse
&& (!serverHttpRequest.getURI().toString().contains(Constants.ACTUATOR_HEALTH_PATH))) {
loggingService.logResponse(((ServletServerHttpRequest) serverHttpRequest).getServletRequest(),
((ServletServerHttpResponse) serverHttpResponse).getServletResponse(), o);
}
return o;
}
CustomRequestBodyAdviceAdapter.class.
import com.pmi.hyperface.constants.Constants;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
import java.lang.reflect.Type;
@ControllerAdvice
public class CustomRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {
@Autowired
LoggingService loggingService;
@Autowired
HttpServletRequest httpServletRequest;
@Override
public boolean supports(MethodParameter methodParameter, Type type,
Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
if (!httpServletRequest.getRequestURI().contains(Constants.ACTUATOR_HEALTH_PATH))
loggingService.logRequest(httpServletRequest, body);
return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
}
}
LoggingServiceImpl.class.
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@Service
@Slf4j
public class LoggingServiceImpl implements LoggingService {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void logRequest(HttpServletRequest httpServletRequest, Object body) {
StringBuilder stringBuilder = new StringBuilder();
Map<String, String> parameters = buildParametersMap(httpServletRequest);
stringBuilder.append("\nREQUEST");
stringBuilder.append("\nmethod=[").append(httpServletRequest.getMethod()).append("]");
stringBuilder.append("\npath=[").append(httpServletRequest.getRequestURI()).append("]");
stringBuilder.append("\nheaders=[").append(buildHeadersMap(httpServletRequest)).append("]");
if (!parameters.isEmpty()) {
stringBuilder.append("\nparameters=[").append(parameters).append("] ");
}
if (body != null) {
try {
stringBuilder.append("\nbody=[" + objectMapper.writeValueAsString(body) + "]");
} catch (JsonProcessingException e) {
log.error("Json processing exception while logging request details");
}
}
log.info(stringBuilder.toString());
}
@Override
public void logResponse(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object body) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("\nRESPONSE");
stringBuilder.append("\nmethod=[").append(httpServletRequest.getMethod()).append("]");
stringBuilder.append("\npath=[").append(httpServletRequest.getRequestURI()).append("]");
stringBuilder.append("\nresponseHeaders=[").append(buildHeadersMap(httpServletResponse)).append("]");
try {
stringBuilder.append("\nresponseBody=[").append(objectMapper.writeValueAsString(body)).append("] ");
} catch (JsonProcessingException e) {
log.error("Json processing exception while logging request details");
}
log.info(stringBuilder.toString());
}
private Map<String, String> buildParametersMap(HttpServletRequest httpServletRequest) {
Map<String, String> resultMap = new HashMap<>();
Enumeration<String> parameterNames = httpServletRequest.getParameterNames();
while (parameterNames.hasMoreElements()) {
String key = parameterNames.nextElement();
String value = httpServletRequest.getParameter(key);
resultMap.put(key, value);
}
return resultMap;
}
private Map<String, String> buildHeadersMap(HttpServletRequest request) {
Map<String, String> map = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = headerNames.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
return map;
}
private Map<String, String> buildHeadersMap(HttpServletResponse response) {
Map<String, String> map = new HashMap<>();
Collection<String> headerNames = response.getHeaderNames();
for (String header : headerNames) {
map.put(header, response.getHeader(header));
}
return map;
}
}