로깅을 json 형식으로 하여, 분석을 보다 용이하게 할 수 있다. 토스에서도 이런 방식으로 사용한다고 한다.
기본적인 로깅 설정은 https://dean83.tistory.com/315 여기에 명시해 두었다.
라이브러리를 추가 하여 이용하는것이 일반적이다. gradle 에 다음을 추가 한다.
implementation 'net.logstash.logback:logstash-logback-encoder:7.4'
일단, logback 설정 파일의 예를들면 다음과 같다.
- 개발환경에서는 json 형식으로 콘솔에만 출력
- 파일은 7일 후 삭제, 분 단위로 파일로 저장
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<!-- 현재 활성 프로필 불러오기 -->
<springProperty scope="context" name="springProfile" source="spring.profiles.active" />
<!-- 로그 경로 / 파일명 설정 -->
<property name="LOG_PATH" value="logs" />
<property name="LOG_FILE" value="${LOG_PATH}/app-${springProfile}.log" />
<!-- ========================================================= -->
<!-- 🔹 개발환경(dev): JSON 형식 콘솔 출력 -->
<!-- ========================================================= -->
<springProfile name="dev">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp timeZone="Asia/Seoul" />
<logLevel />
<threadName />
<loggerName />
<message />
<mdc />
<arguments />
<stackTrace />
<jsonProvider class="net.logstash.logback.composite.GlobalCustomFieldsJsonProvider">
<customFields>{"env":"dev","service":"my-service"}</customFields>
</jsonProvider>
</providers>
</encoder>
</appender>
<!-- 개발 환경에서는 DEBUG 로그까지 출력 -->
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</springProfile>
<!-- ========================================================= -->
<!-- 🔹 운영환경(prod): JSON 형식 파일 저장 -->
<!-- ========================================================= -->
<springProfile name="prod">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}</file>
<!-- 1분 단위 로그 롤링 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/app-%d{yyyy-MM-dd_HH-mm}.log</fileNamePattern>
<maxHistory>7</maxHistory> <!-- 7일간 보존 -->
</rollingPolicy>
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp timeZone="Asia/Seoul" />
<logLevel />
<threadName />
<loggerName />
<message />
<mdc />
<arguments />
<stackTrace />
<jsonProvider class="net.logstash.logback.composite.GlobalCustomFieldsJsonProvider">
<customFields>{"env":"prod","service":"my-service"}</customFields>
</jsonProvider>
</providers>
</encoder>
</appender>
<!-- 운영 환경에서는 INFO 이상만 기록 -->
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</springProfile>
</configuration>
사용할때는 그냥 동일하게 log를 통해 작성하면 된다.
만일 내가 원하는 필드를 추가하고, 해당 필드에 값을 채워 넣고 싶을 경우, MDC를 이용하게 된다.
(이를 위해 위의 설정에서 <mdc/> 가 들어가 있다)
MDC를 이용하면, 컨트롤러 -> 서비스 -> 리파지토리 간 데이터를 공유 메모리를 통해 공유할 수 있다. 따라서 TraceID 같은것을 공유하여 로깅을 할 수 있다.
사용 예를 보면,
MDC.put("userId", "U12345");
MDC.put("traceId", UUID.randomUUID().toString());
log.info("User login success");
MDC.clear();
이런식으로 사용할 수 있다. 그러나 매번 이렇게 로깅하는것은 코드 복잡성도 증가 시키고 좋지가 않기 때문에 보통은 Filter와 인터셉터를 통해 작업을 하게 된다.
Filter와 인터셉터는 Controller 에 요청이 닿기전에 들어오므로, 하나의 요청(Trace) 에 일관되게 적용을 할 수 있다.
@Component
public class LoggingMdcFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
try {
MDC.put("traceId", UUID.randomUUID().toString());
MDC.put("method", request.getMethod());
MDC.put("uri", request.getRequestURI());
// 인증된 사용자 정보가 있다면 userId 추가
// MDC.put("userId", userService.getCurrentUserId());
filterChain.doFilter(request, response);
} finally {
MDC.clear();
}
}
}
** 만일, MDC를 이용하나 json 형식이 아닌 포멧 형식으로 로깅을 한다면, MDC 항목을 로깅하기 위해 %X{이름} 포멧을 사용하게 된다. 이름은 MDC.put 에서 추가하는 키값과 일치시키는게 좋다.
'Backend > SpringBoot' 카테고리의 다른 글
| BaseEntity 사용 및 time 정보 자동 생성 (0) | 2025.10.31 |
|---|---|
| Custom Annotation (Custom validation) (0) | 2025.10.29 |
| EC2 에 배포한 서버에 Https 적용하기 (0) | 2025.09.22 |
| Swagger 사용하기 (0) | 2025.09.22 |
| 간단하게 API 테스트 하기 (파일명.http) (0) | 2025.09.19 |