우아한테크코스

Logging 전략 수립(with Logback)

1. 상황

우아한테크코스 Lv3 3차 데모데이 필수 요구사항에 '디버깅할 수 있는 로그 파일 출력' 요구사항이 추가되었다. 따라서 로컬, 개발, 운영 서버에 맞는 각기 다른 로깅 전략이 필요했다.

 

2. Logging 전략

Logback vs Log4j2

Logback, Log4j2 중 어떤 로깅 프레임워크를 사용할 지 고민했다. Log4j1의 경우 2015년 8월 아파치 측에서 더이상 지원하지 않는다고 발표했기 때문에 고려하지 않았다.(https://blogs.apache.org/foundation/entry/apache_logging_services_project_announces)

 

팀 내에서 로깅을 경험한 사람이 없었기에, 우선은 Logback을 사용하기로 결정했다. Logback은 Spring boot에서 기본적으로 모듈을 제공하기 있기 때문에 따로 의존성을 추가할 필요가 없다. 대신 Log4j2에 비해 성능이 굉장히 낮다는 단점이 있어 나중에는 Log4j2로 변경해야할 것 같다. Log4j2는 Logback에서 제공하는 대부분의 기능을 제공하며, 기존에 Logback이 갖고있던 문제를 개선했다.

 

 

로컬, 개발, 운영 서버에 따른 로깅전략

가장 고민이 많았던 부분이다. 결론부터 먼저 말하면 우리 팀은 다음과 같은 로깅전략을 취하기로 결정했다.

  • 로컬(local)  INFO 레벨로 콘솔에 출력
  • 개발(dev) info.log에는 HTTP 요청, 응답 / warn.log에는 400번대 에러, 500번대 에러, DB 에러
  • 운영(prod) ➔ info.log에는 HTTP 요청, 응답 / warn.log에는 400번대 에러 / error.log에는 500번대 에러

현재 개발 서버를 프론트엔드와 백엔드 연동 테스트하는데 사용하고 있다. 그래서 BadRequestException를 포함한 모든 에러를 warn.log에 담았다. appender를 모두 분리했으며 profile로 로깅전략을 선택하도록 설정했다. profile은 각 서버에서 스프링부트를 실행할 때 '-Dspring.profiles.active=' 로 설정한다.

nohup java -jar -Dspring.profiles.active=prod teatime-0.0.1-SNAPSHOT.jar 1>stdout.txt 2>err.txt &

 

3. 코드

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <timestamp key="BY_DATE" datePattern="yyyy-MM-dd"/>
    <property name="BASE_LOG_PATTERN"
              value="[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{36} - %msg%n"/>
    <property name="ERROR_LOG_PATTERN"
              value="[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{36} - %msg%n"/>

    <springProfile name="local">
        <include resource="console-appender.xml"/>
        <root level="INFO">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>

    <springProfile name="dev">
        <include resource="file-info-appender.xml"/>
        <include resource="dev-warn-appender.xml"/>

        <logger name="com.woowacourse.teatime" level="INFO">
            <appender-ref ref="FILE-INFO"/>
            <appender-ref ref="DEV-WARN"/>
        </logger>

        <logger name="org.springframework" level="INFO">
            <appender-ref ref="FILE-INFO"/>
            <appender-ref ref="DEV-WARN"/>
        </logger>
    </springProfile>


    <springProfile name="prod">
        <include resource="file-info-appender.xml"/>
        <include resource="prod-warn-appender.xml"/>
        <include resource="file-error-appender.xml"/>

        <logger name="com.woowacourse.teatime" level="INFO">
            <appender-ref ref="FILE-INFO"/>
            <appender-ref ref="PROD-WARN"/>
            <appender-ref ref="FILE-ERROR"/>
        </logger>

        <logger name="org.springframework" level="INFO">
            <appender-ref ref="FILE-INFO"/>
            <appender-ref ref="PROD-WARN"/>
            <appender-ref ref="FILE-ERROR"/>
        </logger>
    </springProfile>
</configuration>

console-appender.xml

<included>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${BASE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
</included>

dev-warn-appender.xml

<included>
    <appender name="DEV-WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>./logs/warn.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <encoder>
            <pattern>${ERROR_LOG_PATTERN}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>./backup/warn/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
    </appender>
</included>

file-info-appender.xml

<included>
    <appender name="FILE-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>./logs/info.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>${BASE_LOG_PATTERN}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>./backup/info/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
    </appender>
</included>

prod-warn-appender.xml

<included>
    <appender name="PROD-WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>./logs/warn.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>${ERROR_LOG_PATTERN}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>./backup/warn/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
    </appender>
</included>

file-error-appender.xml

<included>
    <appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>./logs/error.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder>
            <pattern>${ERROR_LOG_PATTERN}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>./backup/error/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
    </appender>
</included>