[SPRING] Spring Rest에서 모든 요청 - 응답을 기록하는 방법은 무엇입니까?
SPRINGSpring Rest에서 모든 요청 - 응답을 기록하는 방법은 무엇입니까?
응용 프로그램은 비동기 적으로 (별도의 스레드에서) 클라이언트에 영향을주지 않고 다음 정보를 기록해야합니다.
필터에서 입력 스트림을 소비하면 json과 객체 매핑을 위해 봄에 다시 소비 될 수 없습니다. 객체 매핑에 대한 입력 스트림 중 어딘가에서 로거를 연결할 수 있습니까?
최신 정보:
우리는 MessageConverter에서 로깅 코드를 작성할 수 있지만 좋은 생각은 아닙니다.
public class MyMappingJackson2MessageConverter extends AbstractHttpMessageConverter<Object> {
...
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
InputStream inputStream = inputMessage.getBody();
String requestBody = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
String method = request.getMethod();
String uri = request.getRequestURI();
LOGGER.debug("{} {}", method, uri);
LOGGER.debug("{}", requestBody);
return objectMapper.readValue(requestBody, clazz);
}
protected void writeInternal(Object o, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
String responseBody = objectMapper.writeValueAsString(o);
LOGGER.debug("{}", responseBody);
outputMessage.getBody().write(responseBody.getBytes(StandardCharsets.UTF_8));
}
}
해결법
-
==============================
1.baeldung.com의 답변 :
baeldung.com의 답변 :
로깅을 비동기로 만들기 위해 비동기 애 퍼처를 사용할 수 있습니다. 불행히도 로깅 응답 페이로드는 지원하지 않습니다. :(
-
==============================
2.당신은 봄 양상을 사용하여 이것을 달성 할 수있다. @Before, @AfterReturning, @AfterThrowing 등의 주석을 제공합니다. 모든 끝점 로그가 필요하지 않을 수도 있으므로 여기에 패키지 기반의 필터가 있습니다. 여기 예시들이 있습니다 :
당신은 봄 양상을 사용하여 이것을 달성 할 수있다. @Before, @AfterReturning, @AfterThrowing 등의 주석을 제공합니다. 모든 끝점 로그가 필요하지 않을 수도 있으므로 여기에 패키지 기반의 필터가 있습니다. 여기 예시들이 있습니다 :
요청 :
@Before("within(your.package.where.is.endpoint..*)") public void endpointBefore(JoinPoint p) { if (log.isTraceEnabled()) { log.trace(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " START"); Object[] signatureArgs = p.getArgs(); ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); try { if (signatureArgs[0] != null) { log.trace("\nRequest object: \n" + mapper.writeValueAsString(signatureArgs[0])); } } catch (JsonProcessingException e) { } } } here `@Before("within(your.package.where.is.endpoint..*)")` has the package path. All endpoints within this package will generate the log.
응답 :
@AfterReturning(value = ("within(your.package.where.is.endpoint..*)"), returning = "returnValue") public void endpointAfterReturning(JoinPoint p, Object returnValue) { if (log.isTraceEnabled()) { ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); try { log.trace("\nResponse object: \n" + mapper.writeValueAsString(returnValue)); } catch (JsonProcessingException e) { System.out.println(e.getMessage()); } log.trace(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " END"); } } here `@AfterReturning("within(your.package.where.is.endpoint..*)")` has the package path. All endpoints within this package will generate the log. Also Object returnValue has the response.
예외 사항 :
@AfterThrowing(pointcut = ("within(your.package.where.is.endpoint..*)"), throwing = "e") public void endpointAfterThrowing(JoinPoint p, Exception e) throws DmoneyException { if (log.isTraceEnabled()) { System.out.println(e.getMessage()); e.printStackTrace(); log.error(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " " + e.getMessage()); } } here `@AfterThrowing(pointcut = ("within(your.package.where.is.endpoint..*)"), throwing = "e")` has the package path. All endpoints within this package will generate the log. Also Exception e has the error response.
전체 코드는 다음과 같습니다.
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Aspect @Order(1) @Component //@ConditionalOnExpression("${endpoint.aspect.enabled:true}") public class EndpointAspect { static Logger log = Logger.getLogger(EndpointAspect.class); @Before("within(your.package.where.is.endpoint..*)") public void endpointBefore(JoinPoint p) { if (log.isTraceEnabled()) { log.trace(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " START"); Object[] signatureArgs = p.getArgs(); ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); try { if (signatureArgs[0] != null) { log.trace("\nRequest object: \n" + mapper.writeValueAsString(signatureArgs[0])); } } catch (JsonProcessingException e) { } } } @AfterReturning(value = ("within(your.package.where.is.endpoint..*)"), returning = "returnValue") public void endpointAfterReturning(JoinPoint p, Object returnValue) { if (log.isTraceEnabled()) { ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); try { log.trace("\nResponse object: \n" + mapper.writeValueAsString(returnValue)); } catch (JsonProcessingException e) { System.out.println(e.getMessage()); } log.trace(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " END"); } } @AfterThrowing(pointcut = ("within(your.package.where.is.endpoint..*)"), throwing = "e") public void endpointAfterThrowing(JoinPoint p, Exception e) throws Exception { if (log.isTraceEnabled()) { System.out.println(e.getMessage()); e.printStackTrace(); log.error(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " " + e.getMessage()); } } }
AOP에 대한 자세한 정보는 여기를 방문하십시오 :
AOP에 관한 스프링 부두
AOP에 관한 샘플 기사
-
==============================
3.가장 좋은 방법은 비동기 메서드에서 로깅을하는 것입니다.
가장 좋은 방법은 비동기 메서드에서 로깅을하는 것입니다.
@Async public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously. " + Thread.currentThread().getName()); }
다음을 참조하십시오 :
비동기
비동기 방법
-
==============================
4.LoggingFilter와 Async 지원은 Spring의 2 가지 요소를 사용합니다. 첫 번째 경우, CommonsRequestLoggingFilter를 사용합니다. CommonsRequestLoggingFilter는 이미 HTTP 요청을 가로 채고이를위한 구성과 Async를 구성하는 방법을 이미 알고 있습니다. 다음과 같이 할 수 있습니다.
LoggingFilter와 Async 지원은 Spring의 2 가지 요소를 사용합니다. 첫 번째 경우, CommonsRequestLoggingFilter를 사용합니다. CommonsRequestLoggingFilter는 이미 HTTP 요청을 가로 채고이를위한 구성과 Async를 구성하는 방법을 이미 알고 있습니다. 다음과 같이 할 수 있습니다.
먼저 비동기 지원 활성화
@Configuration @EnableAsync public class SpringAsyncConfig { ... }
그런 다음 loggingFilter를 만듭니다.
public class LoggingFilter extends CommonsRequestLoggingFilter { @Override protected void beforeRequest(final HttpServletRequest request, final String message) { // DO something myAsyncMethodRequest(request, message) } @Override protected void afterRequest(final HttpServletRequest request, final String message) { // Do something myAsyncMethodResponse(request, message) } // ----------------------------------------- // Async Methods // ----------------------------------------- @Async protected void myAsyncMethodRequest(HttpServletRequest request, String message) { // Do your thing // You can use message that has a raw message from the properties // defined in the logFilter() method. // Also you can extract it from the HttpServletRequest using: // IOUtils.toString(request.getReader()); } @Async protected void myAsyncMethodResponse(HttpServletRequest request, String message) { // Do your thing } }
그런 다음 만든 필터에 대한 사용자 지정 로깅 구성을 만듭니다.
@Configuration public class LoggingConfiguration { @Bean public LoggingConfiguration logFilter() { LoggingFilter filter = new LoggingFilter(); filter.setIncludeQueryString(true); filter.setIncludePayload(true); filter.setIncludeHeaders(true); return filter; } }
요청에서 데이터를 추출하려면 message 매개 변수를 사용하거나 HttpServletRequest를 처리 할 수 있습니다. 예를 들면 다음과 같습니다.
from https://stackoverflow.com/questions/48301764/how-to-log-all-the-request-responses-in-spring-rest by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Hibernate lazy-load 애플리케이션 디자인 (0) | 2019.01.25 |
---|---|
[SPRING] Spring DAO 대 Spring ORM 대 Spring JDBC (0) | 2019.01.25 |
[SPRING] 스프링 부트 어떻게 jar 파일 외부의 특성 파일을 읽는가? (0) | 2019.01.25 |
[SPRING] 매개 변수 객체 속성 (0) | 2019.01.25 |
[SPRING] 두 변수를 추가 한 후 BeanCreationException 발생 (0) | 2019.01.25 |