우아한 테크코스/이것저것

Springboot Logging 적용 - logback

jamie. 2020. 7. 29. 13:10
반응형

Springboot에서의 Logging

 Springboot에서는 Logging 설정을 자동적으로 지원

 slf4j 로깅 Facade를 통해 logback을 기본적으로 지원하고 있음

slf4j란?

더보기

Simple Logging Facade for Java (SLF4J) LINK

 SLF4J는 다양한 로깅 프레임워크(java.util.logging / logback / log4j 등)에 대한 간단한 Facade* 또는 추상화 역할을 하여 사용자가 설정(deployment)하는 경우 원하는 로깅 프레임워크를 플러그인할 수 있도록 함

 로깅 API를 분리하면 애플리케이션과 특정 로깅 프레임워크간의 관계가 느슨해지고, 이를 통해 기존 또는 다른 코드와 쉽게 통합하거나 이미 다른 로깅을 사용한 프로젝트에 코드를 제공할 수 있음

Facade 패턴
 - 어떤 서브시스템의 일련의 인터페이스에 대해 통합된 인터페이스를 제공
 - Facade에서 고수준 인터페이스를 정의하기 때문에 서브 시스템을 더 쉽게 사용할 수 있음

기본 logging 해보기

// BoardApplication

import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BoardApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(BoardApplication.class);
        // WepApplication 사용 안함 설정 - NONE
        application.setWebApplicationType(WebApplicationType.NONE);
        application.run(args);
    }
}
// AppRunner

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
// ApplicationRunner - 애플리케이션 실행 후 추가로 실행하고 싶은 것 구현할 때 사용
public class AppRunner implements ApplicationRunner {

    // Logger 생성 - LoggerFactory.getLogger(클래스명)
    // lombok을 이용한다면, 클래스 위에 @Slf4j 애너테이션을 다는 것으로 대체할 수 있음
    // - @Slf4j 사용시 log라는 필드가 생겨서, log.info("") 이런 식으로 사용
    private Logger logger = LoggerFactory.getLogger(AppRunner.class);

    @Override
    public void run(ApplicationArguments args) {
        /* logging - 레벨별로 설정 가능
        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");
        */
        logger.info("=======================");
        logger.info("Jamie's Spring Boot App");
        logger.info("=======================");
    }
}

결과 - Application 실행시, 로깅한 내용 확인됨

Logging 설정하기 - application.properties

# 콘솔 창에 출력되는 로깅 메세지를 색으로 구분해서 출력
spring.output.ansi.enabled=always
# 로그 메세지가 저장되는 디렉터리 (절대경로/상대경로 모두 가능)
# 이렇게 설정하면, logs/spring.log로 LOG_FILE이 잡히고, LOG_PATH로는 
logging.file.path=logs
# 로그 레벨 - logging.level.{패키지 경로}를 통해 설정
logging.level.com.github.jamie9504.board=DEBUG

 

Logging Extentions(확장)

Springboot에서는 기본적으로 logback 모듈을 제공, logback 모듈의 설정 정보를 logback-spring.xml 파일로 따로 관리할 수 있음

Logback 확장이 가능한 이유

 Web Application 시작하면 classpath 내에서 환경 파일(logback.xml)을 검색해서 logback을 초기화시킴
=> Spring 구동 전의 시점
 Springboot의 경우 logback-spring.xml을 사용해 Spring이 logback을 구동할 수 있도록 지원해줌
=> profile이나 application.properties에 설정된 properties들을 읽어올 수 있음

application.properties

logging.level info를 전체에 적용

profile 설정을 다중으로 할 수 있게 설정 적용 - 추후 application.properties를 환경별로 분리한다면 다양하게 적용할 수 있도록

# 콘솔 창에 출력되는 로깅 메세지를 색으로 구분해서 출력
spring.output.ansi.enabled=always
# 로그 메세지가 저장되는 디렉터리 (절대경로/상대경로 모두 가능)
logging.file.path=logs
# 로그 레벨 - logging.level.{패키지 경로}를 통해 설정
logging.level.root=DEBUG
# profile 설정
spring.profiles.include=file-logging,console-logging

logback-spring.xml

다중 profile을 위해 console-logging, file-logging 분리

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
    <property name="LOG_PATH" value="${LOG_PATH}"/>
    <property name="LOG_FILE_NAME" value="spring"/>
    <property name="ERR_LOG_FILE_NAME" value="error"/>
    <property name="LOG_PATTERN"
        value="%-5level %d{yy-MM-dd HH:mm:ss}[%thread] [%logger{0}:%line] - %msg%n"/>
    <property name="LOG_CONSOLE_PATTERN"
        value="%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable"/>

    <springProfile name="console-logging">
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${LOG_CONSOLE_PATTERN}</pattern>
            </encoder>
        </appender>
    </springProfile>
    <springProfile name="file-logging">
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${LOG_PATH}/${LOG_FILE_NAME}.log</file>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${LOG_PATTERN}</pattern>
            </encoder>
            <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_PATH}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}_%i.log
                </fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>10MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <maxHistory>30</maxHistory>
            </rollingPolicy>
        </appender>
        <appender name="Error" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>error</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <file>${LOG_PATH}/${ERR_LOG_FILE_NAME}.log</file>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${LOG_PATTERN}</pattern>
            </encoder>
            <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_PATH}/${ERR_LOG_FILE_NAME}.%d{yyyy-MM-dd}_%i.log
                </fileNamePattern>
                <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>10MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
                <maxHistory>60</maxHistory>
            </rollingPolicy>
        </appender>
    </springProfile>
    <root>
        <springProfile name="console-logging">
            <appender-ref ref="CONSOLE"/>
        </springProfile>

        <springProfile name="file-logging">
            <appender-ref ref="FILE"/>
        </springProfile>

        <springProfile name="remote-logging">
            <appender-ref ref="REMOTE_LOG_SERVER"/>
        </springProfile>
    </root>
</configuration>

적용 결과

logback이 아닌 다른 로깅 모듈로 바꾸고 싶다면?

 의존성 파일(build.gradle / pom.xml)에서 logback을 제거한 후, 다른 로깅 모듈 의존성을 추가

Gradle

// 제외
configurations {
    all {
        compile.exclude module: 'spring-boot-starter-logging'
    }
}

// 추가 - 예. log4j2
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-log4j2'
}

Maven

<dependency>
<!-- 제거 -->
<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
	<!-- 추가 - 예: log4j2 -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

참고하면 좋을 글

https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-logging - 공식 문서

https://meetup.toast.com/posts/149 - Springboot + logback 설명이 상세히 잘 나와있음

https://www.baeldung.com/spring-boot-logging - Springboot logging 설명이 나와있음(영어)

https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#core-properties

- application.properties 관련 설정 공식 문서

반응형