Search
📒

6-2. Logging

저희가 일반적인 코딩 공부를 할때, 현재 작성한 코드를 디버거 없이 상태를 확인할때, 저희는 터미널에 출력을 합니다. Java의 경우는 System.out.println 입니다. 디버거를 능숙하게 사용한다면 그럴일은 비교젹 적겠지만, 변수의 내용을 그 시점에서 출력하는 것은 문제 해결을 위해 매우 흔히 하는 행동입니다.
저희는 웹 서비스를 만들기 위해 Spring Boot를 공부합니다. 웹 서비스는 한번 실행된 이후로 저희가 꾸준하게 지켜보고 있을 수 없습니다. 그래서 어플리케이션에서 무슨일이 일어났는지를 남겨주는 역할을 하는 로깅은 한번쯤 짚고 넘어갈 주제입니다.

Logging Dependencies

기본적으로 로깅을 하기위해서 필요한 가장 기초적인 의존성은 apache-commons-logging 입니다. 하지만 이는 Spring 5.X (Spring Boot 2.X) 버전부터 spring-jcl 에 포함되어 있으며, 저희가 사용하고 있는 spring-boot-starter 에 자동으로 포함된 경우가 많기 때문에 일반적으로는 걱정할 필요는 없습니다. 즉, spring boot를 사용하면 로깅 라이브러리가 포함되어 있다는 이야기입니다.
이렇게 진행할경우 기본으로 사용하는 라이브러리는 Logback 입니다. 이 외에 다른 라이브러리를 사용하고 싶다면 해당 Logging 라이브러리의 의존성을 추가하고,
configurations { compile.exclude module: 'spring-boot-starter-logging' }
Java
복사
build.gradle 추가하여, 기본적으로 제공되는 의존성을 제거해야 합니다.

Log Level

로깅을 진행할때는 다섯가지 level이 있습니다. (언어, 환경에 따라 조금씩 차이 존재)
@RequestMapping("/") public String index() { logger.trace("A TRACE Message"); logger.debug("A DEBUG Message"); logger.info("An INFO Message"); logger.warn("A WARN Message"); logger.error("An ERROR Message"); return "index"; }
Java
복사
위의 예시 코드들은 아래에서 위로 갈수록 어느정도 수준에서 확인해야 하는 메시지 인지를 의미합니다. 위에서 아래로 갈수록 반드시 알아야 하는 메시지 내용을 의미하게 되는데, 즉 trace 에 가까울수록 사소한 진행 상황에 대한 메시지, error 에 가까울수록 서비스에 위협이 될 수 있는 내용을 알려주는 메시지를 기록하는 용도로 사용하게 됩니다. 특히 error 는 서비스에서 사용자의 요청을 처리하는데 실패하는, 서비스 제공에 심각한(fatal 또는 critical) 수준의 메시지를 알리는데 사용됩니다.

Log Level 설정

이 로그 레벨은 어플리케이션을 실행하면서 어느 수준의 로그까지 출력할지를 지정할 수 있습니다. 이때, 위에서 언급한 중요도 순에서, 지정한 레벨과 같거나 더 중요한 메시지까지 출력하게 됩니다. 실행시 설정한 로그 레벨이 warn 이면, warn 보다 높거나 같은 메시지, 즉 logger.warn()logger.error() 으로 작성한 로그만 남게 됩니다. 즉 작성되는 모든 로그 메시지를 보고싶다면 trace 로 설정해서 실행하면 됩니다.
기본적으로 java 를 이용해 실행한다면 tracedebug 는 추가 설정없이 실행단계에서 바로 설정이 가능합니다.
java -jar spring-boot.jar --trace java -jar spring-boot.jar --debug
Bash
복사

설정 파일로 상세 로그 설정

application.properties 또는 application.yml 파일로 로그 레벨을 설정할 수 있습니다.
logging.level.root=warn
Plain Text
복사
logging: level: root: warn
YAML
복사
기본적으로 전체 어플리케이션에 적용되는 로그 레벨을 지정하고 싶다면, logging.level.root 속성에 설정하고 싶은 레벨을 지정해주면 됩니다. 그 외에 특정 클래스나 패키지 단위로 로그 레벨을 설정할 수 있습니다.
logging: level: root: warn org.springframework: info
YAML
복사
위와 같이 설정하게 될 경우, 기본적으로 로그 메시지는 warn 메시지까지만 출력하지만, org.springframework 패키지의 하위 패키지 또는 클래스들에서 작성하는 로그 메시지들은 info 까지 출력됩니다. 여기서 이 패키지라는 것은 결과적으로 LoggerFactory에 요청할때 전달하는 인자로 전달됩니다.
private static final Logger logger = LoggerFactory.getLogger(PostController.class);
Java
복사
이는 실행 단계에서 JVM에 시스템 설정값으로 전달할 수도 있습니다.
java -Dlogging.level.org.hibernate=info -jar spring-boot.jar
Bash
복사

Logback 살펴보기

우선 Logback 이 어떻게 로그를 작성하고, 어디에 어떻게 로그를 정리하는지 알아보기 위해 간단한 구조를 살펴봅시다.
Logback 은 기본적으로 Appender 라는 interface 단위로 로그 작성 방식을 결정하게 됩니다. 위의 class diagram을 보시면 ConsoleAppender , FileAppender , RollingFileAppender 와 같은 class들이 보입니다. 이러한 Appender 를 상속받은 class가 Logback 에 등록되면, 각각 정의된 방식으로 로그를 남기는 형태로 Logback 이 작동하게 됩니다. 즉 Logback 을 설정한다는 것은, 위와 같은 class들이 필요로 하는 정보들을 xml 파일의 형태로 작성하여 Logback 내부에서 객체화 될 수 있도록 하는것이라 볼 수 있습니다. xml 로 객체화한 Appender는 이후 Logger에 추가하여, Logger가 메시지를 전달할때 Appender가 작동하게 됩니다.
logback-spring.xml 전체 예시

Appender 설정

Appender 를 정의한 설정부터 살펴보면,
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern> %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable </Pattern> </layout> </appender>
XML
복사
<appender> 요소에 작성된 내용을 바탕으로, Spring Boot 실행시 Appender 객체가 생성됩니다. Appender 의 구분자는 name 속성으로, 정확한 인스턴스 클래스는 class 속성으로 정의합니다. Appender 가 출력하는 메시지의 내용은 layout 또는 encoder 로 정의하는데, layoutencoder 의 차이는 출력의 (내부) 결과가 String 이냐 아니면 OutputStream 으로 보내는 byte[] 로 나오냐 입니다. 간단하게 생각하면 파일로 로그를 출력하는 FileAppender 를 구성할때 encoder 를 사용하면 됩니다.
Pattern 링크
<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOGS}/spring-boot-logger.log</file> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <Pattern>%d %p %C{1.} [%t] %m%n</Pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOGS}/archived/spring-boot-logger-%d{yyyy-MM-dd-HH-mm}.%i.log </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender>
XML
복사
RollingFileAppender 는 특정 기준에 따라 로그 파일을 생성, 보관, 회전 (특정 파일 수 이하로 유지)하는 Appender 입니다. 그래서 <rollingPolicy> 요소로 그 규칙을 전달하는 부분이 추가되어야 합니다.

Logger 설정

<root level="info"> <appender-ref ref="RollingFile" /> <appender-ref ref="Console" /> </root> <!-- <logger name="dev.aquashdw" level="trace" additivity="false">--> <!-- <appender-ref ref="RollingFile" />--> <!-- </logger>-->
XML
복사
Appender 를 만들면 해당 Appender 를 사용할 Logger 들을 정의해줘야 합니다. <root> 요소는 소스 코드 상의 모든 Logger 에 대한 설정, <logger> 는 특정 Logger 에 대한 설정입니다. 각 요소는 <appender-ref> 를 가지고 위에 정의한 Appender 를 지정해줄 수 있습니다.
<logger><root> 둘다 로그 레벨을 설정하기 위한 level 속성이 있으며, <logger>의 경우, 어떤 이름(패키지)을 가진 Logger 인지, <root>에서 출력한 내용에 덧붙여 출력할지에 대한 속성들이 추가로 존재합니다. name의 경우 저희가 Spring Boot 내에서 선언한 LoggerFactory.getLogger() 에 인자로 들어간 클래스 명을 기준으로, 클래스 전체 경로 또는 상위 패키지 이름을 전달할 수 있으며, 그 이름이 name과 동일할 경우 해당 <logger> 의 설정이 적용됩니다.
위의 설정을 기준으로 작동시키면, Spring Boot 내부의 모든 Loggerinfo 이상의 메시지를, 콘솔과 파일로 출력하게 되며, 주석된 내용을 해제하면 dev.aquashdw 패키지의 하위 패키지들은 trace 이상의 메시지를 파일로 출력하게 됩니다.
로그에 대한 간단한 지식과 함깨, Logback 을 설정하는 방법을 알아보았습니다.