로깅
- 로그를 사용하는 이유는 애플리케이션 동작을 감시하여 문제가 발생했을 때 신속하게 대응하기 위해서이다.
System.out.println()을 사용하면 되지, 꼭 로깅할 필요가 있을까?
- 로깅 라이브러리는 유연성, 성능, 유지보수 측면에서 큰 이점을 제공한다.
- 로그 레벨(trace, debug, info, warn, error)등으로 유연하게 정보를 로깅할 수 있다.
- 로깅은 내부 버퍼를 사용하여 비동기적으로 로깅할 수 있어 성능상 이점이 있다. (별도의 스레드 사용, I/O 지연 처리)
- 로깅 관련 설정(로그 레벨, 포멧, 출력 대상)을 파일 하나로 관리할 수 있으며 필요에 따라 콘솔, 파일, 네트워크에 리다이렉션 할 수 있다.
로깅 사용
- 로거 인스턴스 사용
private static final Logger log = LoggerFactory.getLogger(LoggingController.class);
- @Slf4j 롬복 어노테이션 사용
@Slf4j
@Service
public class ContactService {}
로깅 레벨
- TRACE < DEBUG < INFO < WARN < ERROR
- 왼쪽으로 갈수록 상세한 수준의 로그로 다음 레벨의 내용을 포함한다.
- TRACE 로그의 경우 DEBUG, INFO, WARN, ERROR 로그를 모두 포함한다.
- ERROR: 즉시 대응해야 할 에러 로그
- WARN: 상황에 따라 잠재적으로 위험할 수 있을 때 또는 예외 처리
- INFO: 로그에 저장하고 싶은 중요 애플리케이션 이벤트
- DEBUG: 개발 단계에서 사용. 디버깅이 가능하도록 상세한 내용 출력
- TRACE: 개발 단계에서 사용. 모든 레벨 로그가 출력
SpringBoot 기본 로깅
- 기본적인 로깅 수준은 INFO로 사전 설정되어 있다. application.yml에서 패키지, 클래스 별로 어느 정도의 정보를 로그로 남길지 정할 수 있다.
logging:
level:
root: warn
org.springframework.web: debug
org.hibernate: error
com.core.book.BookServiceController: trace
- 설정을 변경하지 않고 로깅 수준을 변경하려면 jar로 컴파일 시에 -debug, -trace 인수를 전달하면 된다.
java -jar target/spring-boot-logging-0.0.1-SNAPSHOT.jar --trace
- 추가로 VM 옵션에서 로깅 수준을 설정하거나 Maven 또는 Gradle로 빌드할 때 로그 설정을 인수로 전달할 수 있다.
SLF4J(Simple Logging Facade for Java)
- SLF4J는 여러 로깅 프레임워크(logback, log4j, java.util.logging)에 대한 일관된 인터페이스를 제공하는 로깅 API의 집합이다.
- 로깅 구현체와의 결합을 최소화하여 로깅 구현체의 내부 구조나 동작 방식을 알 필요 없이 로깅 기능을 사용할 수 있다.
- spring-boot-starter 의존성이 추가되어 있으면 logback 로그 프레임워크를 사용할 수 있다.
public void logs() {
log.error("error message");
log.warn("warn message");
log.info(info message");
log.debug("debug message");
log.trace("trace message");
}
로깅 성능
logger.debug("The new entry is "+entry+"."); logger.debug("The new entry is {}.", entry);
logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);
- 공식문서에서 아래 코드가 대략 30배 정도 더 빠르다고 한다. 그 이유를 살펴보면,
- 지연 문자열 평가(Lazy String Evaluation)
- 전자는 로깅 레벨에 상관없이 모든 문자열 연산이 수행되지만, 후자는 로깅 레벨을 만족해야 문자열 연산이 수행된다.
- 효율적인 문자열 처리
- 전자는 문자열 연산마다 새로운 문자열을 만들고 이를 복사하는 연산이 추가로 들어가지만, 후자는 필요한 최종 문자열의 형태가 만들어지고 실제 값이 로깅 시에만 삽입된다고 한다.
Logback 설정
- Logback이란 로깅 구현체로 실제 로깅을 수행하는 역할을 하며 성능 향상과 유연한 구성 옵션을 제공한다.
- 다음 이름 중 하나에 해당하는 파일이 있으면 해당 파일로 세부 설정을 할 수 있다.
- logback-spring.xml, logback.xml, logback-spring.grooby, logback.groovy
- 여기서 세부 설정이란 다양한 색상, 출력 형식, 로깅 이름, 로깅 레벨, 스레드 이름, 콘솔과 파일 출력, 대량 로그 파일 생성 방지를 위한 롤링 정책 등을 말한다.
- 기본 구조
- property
- appender
- encoder
- pattern
- root
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} - %level [%thread] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/myapp.log</file>
<encoder>
<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>logs/archived/myapp-%d{yyyy-MM-dd}.log.zip</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<root level="info">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
<logger name="org.springframework.web" level="debug"/>
<logger name="org.hibernate" level="error"/>
</configuration>
- appender는 어디에 로그를 출력할 것인가를 설정한다.
- 위의 예시에선 로그 메시지를 콘솔(STDOUT) 또는 파일(FILE)에 출력한다. 각각 ConsoleAppender(콘솔 저장), RollingFileAppender(어러 파일 순회하며 저장)를 사용한다.
- 이외에도 FileAppender(파일 저장), SMTPAppender(메일 저장), DBAppender(DB 저장) 구현체가 존재한다.
- encoder는 로그 메시지의 형식을 지정한다.
- TimeBasedRollingPolicy는 로그 파일을 날짜별로 롤링하여 저장한다.
- logs/archived/myapp-%d{yyyy-MM-dd}.log.zip 날짜별 롤링
- logs/archived/myapp-%d{yyyy-MM-dd-HH-mm}.log.zip 분별 롤링
- 아래처럼 로그파일이 롤링된다.
RollingFileAppender 옵션
- 롤링 전략(Rolling Policy): 롤링이 언제 발생할지를 결정
- TimeBasedRollingPolicy: 시간(예: 매일, 매시간)에 따라 파일을 롤링
- SizeBasedTriggeringPolicy: 파일 크기가 특정 기준을 초과했을 때 롤링
- FixedWindowRollingPolicy: 고정된 수의 롤링 파일을 유지하며, 새 파일이 추가될 때 가장 오래된 파일을 삭제
- Triggering Policy(트리거 정책): 롤링이 발생하는 조건을 정의
- SizeBasedTriggeringPolicy: 파일 크기에 따라 롤링을 시작
- TimeBasedTriggeringPolicy: 시간 간격에 따라 롤링을 시작
- MaxFileSize(최대 파일 크기): 한 로그 파일의 최대 크기를 설정. 이 크기를 초과하면 새로운 로그 파일이 생성
- MaxHistory(최대 기록): 보관할 로그 파일의 최대 수를 설정. 이 수를 초과하는 오래된 파일은 자동으로 삭제
- TotalSizeCap(총 크기 제한): 모든 로그 파일의 총 크기 제한을 설정. 이 제한을 초과하면 오래된 파일부터 삭제
- append: 로그 파일이 이미 존재할 때, 새로운 로그를 파일 끝에 추가할지 여부를 결정. 기본값은 true
참고자료