운영 업무를 하다보면 카탈리나 로그를 분석해야 하는 일들이 많은데 로그가 너무 많이 쌓이다보니 분석하는데 어려움이 있어 어떻게 하면 좋을지 고민하고 찾아보던중 aop를 이용하여 request, response 로그를 따로 출력 할 수 있는 방법을 찾을 수 있었다.
aop 코드 작성
@Aspect
@Component
@RequiredArgsConstructor
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
private final ObjectMapper objectMapper;
// 모든 컨트롤러 대상으로 로그 수집
@Pointcut("within(*..*Controller)")
public void onRequest() { }
@Around("onRequest()")
public Object requestLogging(ProceedingJoinPoint joinPoint) throws Throwable {
// 리퀘스트 정보를 담을 객체
final RequestApiInfo apiInfo = new RequestApiInfo(joinPoint, objectMapper);
// 로그 적재할 객체
final LogInfo logInfo = new LogInfo(
apiInfo.getUrl(),
apiInfo.getMethod(),
apiInfo.getHeaders(),
apiInfo.getParameters(),
apiInfo.getIp()
);
try {
final Object result = joinPoint.proceed(joinPoint.getArgs());
// 호출 결과를 로그 적재할 객체에 셋팅
logInfo.setResponse(result);
// 로그를 json 으로 변환하여 출력
final String logMessage = objectMapper.writeValueAsString(Map.entry("logInfo", logInfo));
logger.debug(logMessage);
return result;
} catch (Exception e) {
// 예외가 발생했을때 로그 적재
if (e instanceof BizException) {
StringBuilder builder = new StringBuilder(e.toString());
Exception exception = ((BizException) e).getException();
if (exception != null) {
builder.append(" || ");
builder.append(exception.toString());
}
logInfo.setException(builder.toString());
} else {
final StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
logInfo.setException(sw.toString());
}
final String logMessage = objectMapper.writeValueAsString(logInfo);
logger.error(logMessage);
throw e;
}
}
}
log4j2.xml 파일 작성
appender 태그에 file 태그안에 경로를 알맞게 수정 필요.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProfile name="loc">
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="applicationLogFile"/>
</root>
<logger name="com.example.logging.aop.LoggingAspect" level="DEBUG">
<appender-ref ref="requestLogFile"/>
</logger>
</springProfile>
<appender name="requestLogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>D:/log/requestLog.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%d{yyyy-MM-dd HH:mm:ss}][%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>D:/log/requestLog.log.%d{yyyy-MM-dd}.gz</fileNamePattern>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<appender name="applicationLogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="com.example.logging.filter.CustomLogbackFilter" />
<file>D:/log/application.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%d{yyyy-MM-dd HH:mm:ss}][%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>D:/log/application.log.%d{yyyy-MM-dd}.gz</fileNamePattern>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.springframework.security" level="INFO"/>
<logger name="org.springframework.jndi" level="INFO"/>
<logger name="org.springframework.beans.factory.support" level="INFO"/>
<logger name="org.springframework.data.convert" level="INFO"/>
</configuration>
필요한 코드를 작성하고 테스트 해보면 아래와 같이 application.log, requestLog.log 파일이 별도로 생성되고
api에 대한 request, response 로그가 출력된 것을 알 수 있다.
여러 블로그를 찾아 본 결과 해당 방법을 이용하여 로그를 키바나로 보는 방법도 있고 별도 디비에 적재하여 관리하는 방법도 있지만 현재 회사에서 키바나 같은 인프라를 구축해서 사용하지 않기 때문에 파일로 저장해서 보는 방식으로 구현해봤다.
'springboot' 카테고리의 다른 글
스프링부트 RestTemplate with axios, ajax 로 파일 다운로드 하기 (0) | 2023.08.27 |
---|---|
스프링부트 apache poi 이용하여 엑셀 작업하기 (0) | 2023.08.26 |
JWT(JSON Web Token) 토큰에 대하여... (0) | 2023.06.09 |
3년차 웹 개발자에 스프링부트 아키텍처 고찰... (0) | 2023.05.29 |
spring boot + vue.js 환경 구성하기 (0) | 2023.01.24 |
댓글