Logging
: 애플리케이션이 동작하는 동안 시스템의 상태나 동작 정보를 시간숙으로 기록하는 것
이는 비기능적 요구사항
에 해당함
-> 즉 사용자에게 필요한 기능은 아니지만 디버깅, 발생한 문제 해결 시에 원인을 분석하는데 필요한 요소
자바에서는 log4j 이후 출시된 LogBack
을 사용하며 spring-boot-starter-web 라이브러리 내부에 내장돼 있어 별도의 의존성을 추가하지 않아도 됨
크게 5개의 로그 레벨(TRACE, DEBUG, INFO, WARN,ERROR)
을 설정할 수 있다
실제 운영 환경 개발 환경에서 각각 다른 출력 레벨을 설정해서 로그 확인 가능
LogBack의 설정 파일을 일정 시간마다 스캔해서 애플리케이션을 재가동하지 않아도 설정 변경 가능
별도의 프로그램 지원 없이도 자체적으로 로그 파일 압축 가능
저장된 로그 파일에 대한 보관 기간 등을 설정해서 관리 가능
Error
: 로직 수행 중에 시스템에 심각한 문제가 발생해서 애플리케이션의 작동이 불가능한 경우
WARN
: 시스템 에러의 원인이 될 수 있는 경고 레벨 의미
INFO
: 애플리케이션의 상태 변경과 같은 정보 전달을 위해 사용
Debug
: 애플리케이션의 디버깅을 위한 메세지를 표시하는 레벨을 의미
TRACE
: 디버그 레벨보다 더 상세히 메세지를 표현하기 위한 레벨
우선 resources 폴더 안에 logback-spring.xml
파일을 추가합니다
log back 설정 파일 예시
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<property name="LOG_PATH" value="./logs"/>
<!-- Apenders -->
<appender name = "console" class = "ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>[%d{yyyy-mm-dd HH:mm:ss.SSS}] [%-5level][%thread] %logger %msg%n</pattern>
</encoder>
</appender>
<appender name ="INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class = "ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<file>${LOG_PATH}/info.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>$ {LOG_PATH}/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>
<!-- Trace>Debug>INFO>WARN>ERROR>OFF -->
<!-- Root Logger -->
<root level = "INFO">
<appender-ref ref="console"/>
<appender-ref ref="INFO_LOG"/>
</root>
</configuration>
총 5가지 영역으로 구성되어 있음
로그의 형태를 설정하고 어떤 방법으로 출력할지 설정하는 곳
하나의 인터페이스이며, 하위에 여런 구현체 존재
ConsoleAppender
: 콘솔에 로그 출력
FileAppender
: 파일에 로그 저장
RollingFileAppender
: 여러 개의 파일을 순회하면서 로그 저장
SMTPAppender
: 메일로 로그 전송
DBAppender
: 데이터베이스에 로그 저장
<appender name = "console" class = "ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>[%d{yyyy-mm-dd HH:mm:ss.SSS}] [%-5level][%thread] %logger %msg%n</pattern>
</encoder>
</appender>
appender 요소의 class 속성에 각 구현체를 정의
filter
요소로 각 Appender가 어떤 레벨로 로그를 기록
하는지 지정
encoder 요소를 통해 로그 표현 방식을 pattern
으로 지정
설정 파일에 정의된 Appender를 활용하려면 Root 영역에서 Appender를 참조 해서 로깅 레벨을 설정
특정 패키지에 대해 다른 로깅 레벨을 설정하고 싶다면 root 대신 logger
사용해 지정
<root level = "info">
<appender-ref ref="console"/>
<appender-ref ref="INFO_LOG"/>
</root>
<logger name="com.springboot.api.controller" level="DEBUG" additivity="false">
<appender-ref ref = "console"/>
<appender-ref ref = "INFO_LOG"/>
</logger>
여기서 name요소
에 패키지 단위로 로깅이 적용될 범위 지정하고 level 속성으로 로그 레벨 지정
additivity 속성
은 앞에서 지정한 패키지 범위에 하위 패키지를 포함할지 여부 결정
기본값은 true : 하위 패키지 모두 포함
logback-spring.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<property name="LOG_PATH" value="./logs"/>
<!-- Apenders -->
<appender name = "console" class = "ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>[%d{yyyy-mm-dd HH:mm:ss.SSS}] [%-5level][%thread] %logger %msg%n</pattern>
</encoder>
</appender>
<!-- Trace>Debug>INFO>WARN>ERROR>OFF -->
<!-- Root Logger -->
<root level = "INFO">
<appender-ref ref="console"/>
</root>
</configuration>
@RestController
@RequestMapping("/api/v1/get-api")
public class GetController {
private final Logger LOGGER = LoggerFactory.getLogger(GetController.class);
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String getHello(){
LOGGER.info("getHello 메서드가 호출되었습니다.");
return "Hello world";
}
@GetMapping(value = "/name")
public String getName(){
LOGGER.info("getName 메서드가 호출되었습니다.");
return "Flature";
}
@GetMapping(value = "/variable/{variable}")
public String getVariable(@PathVariable String variable){
LOGGER.info("@Pathvariable을 통해 들어 온 값: {}", variable);
return variable;
}
}
private final Logger LOGGER = LoggerFactory.getLogger(GetController.class)
Appender에게 전달할 Logger 객체를 각 클래스에서 정의하여 사용
LoggerFactory통해 객체를 생성하며 이때 클래스 이름을 함께 지정하여 클래스의 정보를 LOGGER에서 가져가게 함
LOGGER.info("getHello 메서드가 호출되었습니다.");
LOGGER.info("getName 메서드가 호출되었습니다.");
LOGGER.info("@Pathvariable을 통해 들어 온 값: {}", variable);
info 레벨의 로그 출력
위처럼 하였을 시 Swagger에서 테스트를 할때 각 메서드가 호출되면 콘솔창에 로그가 찍힘
[2022-22-26 13:22:27.085] [INFO ][http-nio-8080-exec-10] com.springboot.api.controller.GetController @Pathvariable을 통해 들어 온 값: hello
애플리케이션 마다 어떤 로그를 출력하는 것이 가장 이상적일지 상황에 맞게 고민해보자!!