[Spring Boot] 로그 남기기 : Logback
Logging
시스템의 상태나 Application 동작 정보를 출력 또는 기록하는 것을 로깅 (Logging)이라고 한다.
로깅을 통해 디버깅, 오류 내역 확인 등을 확인할 수 있다.
로그 레벨
로그 레벨은 총 6가지가 있다.
- FATAL
- ERROR
- WARN
- INFO
- DEBUG
- TRACE
주로 사용되는 레벨은 ERROR, INFO, DEBUG 3개 정도이다.
FATAL, ERROR, WARN 은 차이가 있지만 에러에 관한 레벨이다. 예기치 못한 에러들을 ERROR 레벨로 처리하고, 예상된 예외처리들은 INFO 레벨로 처리한다. 예를 들면 사용자가 잘못된 값을 전달했을 때 검증 후 INFO 레벨로 잘못된 인자를 받았음을 남겨주고, DB connection이 끊어지는 예기치 못한, 조치가 필요한 상황에는 ERROR 레벨로 처리해준다.
개발 중 값을 확인하는 목적으로는 DEBUG 레벨을 적용하면 되겠다. DEBUG 레벨은 개발 중에만 출력되도록 한다.
Logback
Logback 설정부터 사용까지
Logback 설정
Dependency에 이미 "spring-boot-starter-web" 이 추가돼있다면 Logback을 적용하기 위해 따로 Dependency를 추가할 필요가 없다. "spring-boot-starter-web"에 포함돼있기 때문이다.
Logback 을 적용하기 위해 설정 파일을 생성해보자.
resources/logback/logback-local.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="30 seconds">
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%-5level] [%d{yyy-MM-dd HH:mm:ss.SSS}] [%thread] %C %M\(\):%L \/\/ %msg%n</pattern>
</encoder>
</appender>
<appender name="INFO_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>infoo.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/controller/%d{yyyyMMdd}.log</fileNamePattern>
<totalSizeCap>15MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>[%-5level] [%d{yyy-MM-dd HH:mm:ss.SSS}] [%thread] %C %M\(\):%L \/\/ %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
</root>
<logger name="com.menuhwang.My.controller" level="DEBUG">
<appender-ref ref="INFO_LOG_FILE"/>
</logger>
</configuration>
resources/application.properties
logging.config=classpath:logback/logback-local.xml
* 추후 profiles 설정에 따라 logback 설정 파일 변경되도록 할 예정
<configuration/>
<configuration scan="true" scanPeriod="30 seconds">
...
</configuration>
scan속성을 true로 설정하면 logback설정 값을 변경했을 때 application실행 중에도 동적으로 적용할 수 있다.
scanPeriod속성에 정해진 시간마다 설정 파일을 확인한다
scanPeriod의 시간 단위로는 milliseconds, seconds, minutes, hours가 있다.
주의
logback-text.xml 파일을 main/resources 안에 작성하게 되는데, scan을 정상 작동되게 하기 위해서는 build/resources/main (Gradle 기준) 위치에 있어야 한다.
즉, 설정 파일도 빌드해야 된다는 것이다. 따라서 작성한 logback-text.xml 파일을 오른쪽 클릭한 뒤
"모듈 '{app name}' 빌드(M)" (인텔리제이 기준)을 클릭해주면 정상적으로 scan이 작동한다.
+ 수정할 때도 마찬가지로 빌드해줘야 된다.
<appender>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%-5level] [%d{yyy-MM-dd HH:mm:ss.SSS}] [%thread] %C %M\(\):%L \/\/ %msg%n</pattern>
</encoder>
</appender>
<appender name="INFO_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>infoo.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/controller/%d{yyyyMMdd}.log</fileNamePattern>
<totalSizeCap>15MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>[%-5level] [%d{yyy-MM-dd HH:mm:ss.SSS}] [%thread] %C %M\(\):%L \/\/ %msg%n</pattern>
</encoder>
</appender>
appender에 사용할 appender종류, name, 세부 값을 설정하고 그 name값으로 참조할 수 있다.
즉, 프리셋으로 보면 된다. 따라서 appender만 작성한다고 적용되는 것은 아니다.
Appender 종류
ConsoeAppender : 콘솔 출력 설정
FileAppender : 파일 저장 설정
RollingFileAppender : 용량이나, 시간에 따라 파일을 여러 개로 나눠 저장하기 위한 설정
등등...
Appender의 세부 설정을 전부 설명하기에는 너무 많아 아래 링크를 참고하는 걸로...
Chapter 4: Appenders
Logback delegates the task of writing a logging event to components called appenders. Appenders must implement the ch.qos.logback.core.Appender interface. The salient methods of this interface are summarized below: package ch.qos.logback.core; import ch.qo
logback.qos.ch
<root>
<root level="INFO">
<appender-ref ref="console"/>
</root>
위에서 설정한 appender를 적용하기 위해서는 어느 패키지에 적용할 것인지를 설정해야 한다.
root 설정에 appender 설정을 참조해오면 전체 경로에 appender 설정값이 적용된다.
또한 root에 level을 설정해줄 수도 있다.
<logger>
<logger name="com.menuhwang.My.controller" level="INFO" additivity="false">
<appender-ref ref="console"/>
<appender-ref ref="INFO_LOG_FILE"/>
</logger>
패키지마다 다른 설정을 하기 위해서는 <logger> 사용하면 된다.
name속성에 적용할 패키지명을 입력해주면 그 패키지에 대한 설정을 할 수 있다.
level설정을 다르게 적용해줄 수도 있다.
additivity속성은 상위 패키지에 적용된 설정값을 오버라이드 할 것인지에 대해 설정할 수 있다.
기본값은 true로 상위 패키지에 적용돼있는 설정을 그대로 적용한다.
기본값인 true로 설정되면 상위 패키지에 적용되는 root안의 Console Appender 설정까지 logger에 적용된다.
// 콘솔 출력
// 파일에 저장
false로 설정하면 root의 설정값을 logger가 상속받지 않고 각각 별개로 동작한다고 이해하면 될 것 같다.
// 콘솔 출력 X
// 파일에 저장
설정 요약
세부 설정도 많고 특히 Additivity는 이해하기 어렵다. 그래서 어떤 식으로 설정하면 좋을지, 사용하면 좋을지 정리해봤다.
1. Appender
Appender에 필터를 붙일 수 있지만, 필터는 root나 logger에 붙이도록 하자.
Appender는 프리셋, 메서드라고 생각하자. 미리 세팅해두고 다른 곳에 불러와 사용하는 메서드.
Filter에도 여러 종류가 있다. 설정 레벨 이상의 레벨을 필터링하는 필터, 해당 레벨만 나오게 하는 필터 등등..
이 Filter를 Appender에 붙여서 더 세부적으로 설정해줄 수 있지만 차근차근 하나씩 하기 위해 뒤로 미루도록 한다.
2. Root
Root는 전체 패키지에 적용될 공통된 Appender를 불러서 사용하자. 스프링 프레임워크, Controller, Service 등등 대부분의 로그를 콘솔에 띄운다면 Root에 Console Appender를 참조해준다.
3. Logger
Logger는 패키지 별로 디테일 설정을 해주기 위해 사용하자. 예를 들어 root의 level를 info로 설정해두고 logger의 level을 debug로 설정해준다면 스프링 프레임워크는 info레벨 이상의 로그들이 출력되고 해당 패키지의 로그는 debug도 출력된다. 또는 스프링 프레임워크의 로그는 따로 저장하지 않고 특정 패키지의 로그들만 저장할때도 가능하다.
이런 식으로 패키지마다 디테일을 잡아줄 때 logger를 이용하자.
4. 마무리
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="true" scanPeriod="30 seconds">
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%-5level] [%d{yyy-MM-dd HH:mm:ss.SSS}] [%thread] %C %M\(\):%L // %msg%n</pattern>
</encoder>
</appender>
<appender name="INFO_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>infoo.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/controller/%d{yyyyMMdd}.log</fileNamePattern>
<totalSizeCap>15MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>[%-5level] [%d{yyy-MM-dd HH:mm:ss.SSS}] [%thread] %C %M\(\):%L // %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
</root>
<logger name="com.menuhwang.My.controller" level="DEBUG">
<appender-ref ref="INFO_LOG_FILE"/>
</logger>
</configuration>
위 예시 코드를 통해 마지막으로 정리해본다.
ConsoleAppende와 RollingFileAppender를 미리 설정해둔 <appender> 태그.
전체 패키지의 info레벨 로그들을 출력하기 위해 "console" <appender>를 참조한 <root> 태그.
"com.menuhwang.My.controller"의 패키지는 debug레벨 로그도 출력하고 파일로도 저장하기 위해 레벨은 debug로 설정하고 "INFO_LOG_FILE" <appender>를 참조한 <logger> 태그.
로그 결과
스프링 프레임워크 : Info 레벨 이상의 로그 콘솔에 출력
com.menuhwang.My.controller : Debug 레벨 이상의 로그 콘솔에 출력 및 파일로 저장
사용
설정은 복잡했지만, 사용방법은 아주 간단하다.
1. LoggerFactory
@RestController
@RequestMapping("/api")
public class MyController {
private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
@ApiOperation(value = "PathVariable 예제", notes = "@PathVariable을 사용한 예제")
@GetMapping(value = "/hello1/{name}")
public String hello1(@ApiParam(value = "이름", required = true) @PathVariable("name") String userName) {
LOGGER.info("info level");
LOGGER.debug("debug level");
return "Hello-1, " + userName;
}
// ...
}
2. @Slf4j 어노테이션
@RestController
@RequestMapping("/api")
@Slf4j
public class MyController {
@ApiOperation(value = "PathVariable 예제", notes = "@PathVariable을 사용한 예제")
@GetMapping(value = "/hello1/{name}")
public String hello1(@ApiParam(value = "이름", required = true) @PathVariable("name") String userName) {
log.info("info level");
log.debug("debug level");
return "Hello-1, " + userName;
}
// ...
}
@Slf4j 어노테이션을 붙여주면 알아서 log에 LoggerFactory로 Logger를 생성해준다.
단, @Slf4j 어노테이션을 사용하려면 Lombok을 Dependency에 추가해줘야 한다.