Spring Boot - 로깅

진경천·2024년 11월 27일

로깅의 필요성

흔히 사용하는 System.out.println()은 리소스를 많이 사용해 성능에 악영향을 끼친다.

Logger는 클래스의 이름, 시간, logging level 등의 정보를 제공한다.

  • 로그를 사용하면 로그를 기록하는 상황에 따라 커스터마이징, 정보를 간략하게 혹은 더욱 상세하게 표시할 수 있게 구성이 가능함

무엇을 기록할 것인가? (log contents)

항목세부 내용
Error메시지, 스택 추적, 에러 발생했을 때 애플리케이션이 실행하고 있던 작업
Debugging디버깅시 필요한 세부 추적 정보
- 적용되는 변수 값, 메서드 등 실행에 대한 세부 정보
주요 이벤트로그에 저장하고 싶은 중요 이벤트
- 엔티티 생성, 유저 로그인 성공, 작업 실행 등

어디에 기록할 것인가?

기록 위치세부 내용
콘솔직관적
- 애플리케이션 종료 혹은 콘솔 버퍼를 초과하면 내용이 휘발될 수 있음
파일로그가 휘발되지 않고 저장됨
- 눈으로 읽긴 쉽지만 프로그래밍처럼 패턴화 된 방식으로 필터링 해보기에는 다른 방법보다 어려움이 따름
이메일/문자 (SMTP/SMS)즉시 조치를 취해야 하는 등의 심각한 오류나 이벤트 시에는 관리자에게 알림이 가도록 설정
데이터베이스로그 필터링이 쉽고 효율적
- 파일보다 기록 속도가 느리고 로깅 양이 많을 때 부하가 발생할 수 있지만 NoSQL 데이터베이스(MongoDB 등)에 저장한다면 대부분의 문제가 해결됨

로그를 파일에 기록할 때는 파티션을 따로 나누어서 저장하는 것이 좋다.

서비스를 배포했을 때 생성되는 로그의 용량은 상당히 크기 때문에 서비스하는 공간과 다른 영역에 저장해야 한다.

어떻게 기록할 것인가? (logging level)

로그 내용에 따라서 log level을 구분 할 수 있다.

TRACE < DEBUG < INFO < WARN < ERROR

위 항목 처럼 Error가 가장 높은 레벨을 갖고 Trace가 가장 낮은 레벨을 갖는다.

로그를 작성할 때 이와 같은 레벨을 설정하여 원하는 로그만 출력시킬 수 있다.

log.info(...);

가령 위와 같이 log레벨을 INFO로 설정했을 때, INFO의 하위 레벨인 TRACE, DEBUG 레벨은 무시 되고, 상위레벨인 DEBUG, TRACE와 자기 자신인 INFO 레벨만 출력된다.

항목설명
ERROR즉시 대응해야 할 레벨
대응하지 않을 경우, 애플리케이션 동작 중지 등 심각한 장애를 겪을 수 있음
WARN상황에 따라 잠재적으로 위험할 수 있을 때 (예외 처리 등)
INFO로그에 저장하고 싶은 중요 애플리케이션 이벤트 (운영 참고 정보)
DEBUG개발 단계에서 사용 디버깅이 가능하도록 상세한 내용이 출력
TRACE개발 단계에서 사용 DEBUG 레벨보다 상세하며 모든 레벨 로그가 출력

SLF4J

Simple Logging Facade For Java

Spring에서 다양한 logging 관련 라이브러리들을 하나의 통일된 방식으로 사용할 수 있는 방법을 제공한다.

위 그림과 같이 logback, log4j, java.utill.logging 등의 라이브러리들을 SLF4J에 바인딩시켜 사용할 수 있다.

Facade Pattern이란?
복잡한 클래스 라이브러리에 대해 사용하기 편하게 간편한 인터페이스를 구성하기 위한 구조 패턴
즉, 복잡한 클래스들을 재정리하여 하나의 인터페이스 만들어둔 것

Logback

Java에서 가장 많이 사용되었던 log4j의 후속버전으로 log4j의 개선된 버전으로 볼 수 있다.

SLF4J를 사용해서 로깅을 할 때, 실제 로깅 작업은 구현체인 logback이 처리한다.

Logback 설정

application.properties 파일에서 간단히 설정하는 방법이 있고 logback-spring.xml 파일을 만들어 세부 설정하는 방법이 있다.

application.properties 설정

logging.level.root=warn
logging.level.org.springframework.web=debug
logging.level.org.hibernate=error

위와 같이 설정 난이도가 비교적 쉽지만 세부적인 설정이 불편하다

logback-spiring.xml 설정

Appender 영역, Encoder 영역, Root 영역으로 나뉘어 설정한다.

Appender

Log의 형태 및 어디에 출력할지 설정하기 위한 영역

<appender name="INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender"> 
  <filter class="ch.qos.logback.classic.filter. Threshold Filter"> 
    <level>INFO</level> 
  </filter>
  <file>${logdir}/${moduleld}/${logback)/info_${type}.log</file> 
  <append>true</append> 
  <rolling Policy class="ch.qos.logback.core.rolling. TimeBased Rolling Policy"> 
    <fileNamePattern>${logdir}/${moduleid}/${logback)/info_${type}.%d{yyyy-MM-dd}.gz</fileNamePattern> 
    <maxHistory>30</maxHistory> 
  </rollingPolicy> 
  <encoder> 
    <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern> 
  </encoder> 
</appender>

대표적인 Appender 형식

  • ConsoleAppender : 콘솔에 로그를 출력
  • FileAppender : 파일에 로그를 저장
  • RollingFileAppender: 여러 개의 파일을 순회하며 로그를 저장
  • SMTPAppender : 로그를 메일로 보냄
  • DBAppender: 데이터베이스에 로그를 저장

Encoder

Appender 내에 포함되는 항목이며, pattern을 사용하여 원하는 형시긍로 로그를 표현할 수 있다.

<encoder> 
  <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern> 
</encoder>

Root

설정한 Appender를 참조하여 로그의 레벨을 설정하는 영역이다.

root는 전역 설정이며, 지역 설정을 하기 위해서는 logger를 사용해야한다.

<root level="DEBUG">
  <appender-ref ref="INFO_LOG"/>
</root>
pattern설명
%Logger{length}Logger Name
%-5level로그 레벨, -5는 출력의 고정폭 값
%msg로그 메세지 영역 (==%message)
${PID:-}프로세스 id
%d로그 기록 시간
%p로깅 레벨
%F로깅이 발생한 프로그램 파일명
%M로깅이 발생한 메소드의 이름
%1로깅이 발생한 호출지의 정보
%L로깅이 발생한 호출지의 라인 수
%thread현재 Thread 명
%t로깅이 발생한 Thread 명
%c로깅이 발생한 카테고리
%C로깅이 발생한 클래스 명
%m로그 메시지
%n줄바꿈
%%% 출력
%r어플리케이션 실행 후 로깅이 발생한 시점까지의 시간
profile
어중이떠중이

0개의 댓글