Logback-spring.xml을 Java 코드로 작성하기

wooSim·2023년 7월 13일
1

Logback-spring.xml을 Java 코드로


Springboot에서 로깅을 할 때 Slf4j의 구현체인 logback 또는 log4j2를 사용하며 만약 logback을 사용할 경우 Logback-spring.xml 파일을 만들어 상세한 설정을 구성합니다.

log에 대한 설명은 이전 글인 Springboot에서 Logback 설정하기을 참고 부탁드립니다.

Springboot에서는 xml 기반 설정파일 보다는 어노테이션 기반 코드로 많은 설정을 하고 있습니다. 그래서 아래 클래스 다이어그램을 참고하여 logback-spring.xml도 한번 java 코드로 만들어보고자 합니다.

○ logback-spring.xml

먼저 저번 글에서 만든 logback-spring.xml 설정파일입니다.

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>

    <property name="CONSOLE_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %magenta([%thread]) %highlight([%-3level]) %logger{5} - %msg %n" />
    <property name="ROLLING_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS}  %logger{5} - %msg %n" />
    <property name="FILE_NAME" value="D:\\logs\\application.log" />
    <property name="LOG_NAME_PATTERN" value="./logs/application-%d{yyyy-MM-dd-HH-mm}.%i.log" />
    <property name="MAX_FILE_SIZE" value="10MB" />
    <property name="TOTAL_SIZE" value="30MB" />
    <property name="MAX_HISTORY" value="2" />


    <!-- Console appender 설정 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>${CONSOLE_PATTERN}</Pattern>
        </encoder>
    </appender>

	<!-- Rolling File appender 설정 -->
    <appender name="ROLLING_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${ROLLING_PATTERN}</pattern>
        </encoder>
        <file>${FILE_NAME}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_NAME_PATTERN}</fileNamePattern>
            <maxHistory>${MAX_HISTORY}</maxHistory>
            <maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
            <totalSizeCap>${TOTAL_SIZE}</totalSizeCap>
        </rollingPolicy>
    </appender>

    <logger name="jdbc" level="OFF" additive="false">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ROLLING_LOG_FILE"/>
    </logger>
    <logger name="jdbc.sqlonly" level="DEBUG" additive="false" >
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ROLLING_LOG_FILE"/>
    </logger>
    <logger name="jdbc.sqltiming" level="OFF" additive="false" >
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ROLLING_LOG_FILE"/>
    </logger>
    <logger name="org.hibernate.SQL" level="DEBUG" additive="false">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ROLLING_LOG_FILE"/>
    </logger>
    <logger name="com.example.todolist.controller" level="INFO" additive="true" >
        <appender-ref ref="STDOUT"/>
    </logger>
    <logger name="com.example.todolist.service" level="DEBUG" additive="false" >
        <appender-ref ref="STDOUT"/>
    </logger>
    <logger name="com.example.todolist.domain" level="DEBUG" additive="false" >
        <appender-ref ref="STDOUT"/>
    </logger>


    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

appender로 ConsoleAppender 와 RollingFileAppender를 사용하였습니다.

그럼 해당 logback-spring.xml 파일을 Java 코드로 구현해보도록 하겠습니다.


○ Java 코드로..

저의 경우 ConsoleAppender와 RollingFileAppender 설정 class를 분리하였습니다. 하나의 class 파일로 만들어도 무방하지만 너무 지저분해지는 것 같아서...

  • LogbackConsole.java : ConsoleAppender 설정
public class LogbackConsole{
    
    private final LoggerContext logCtx = (LoggerContext) LoggerFactory.getILoggerFactory();

    private final String CONSOLE_PATTERN = "%d{yyyy-MM-dd HH:mm:ss.SSS} %magenta([%thread]) %highlight([%-3level]) %logger{5} - %msg %n";
    
    private ConsoleAppender<ILoggingEvent> consoleAppender;
    
    public void logConfig(){
        logCtx.reset();
        consoleAppender = getLogAppender();
        createLoggers();
    }

    private void createLoggers(){
        // 로거 이름, 로깅 레벨, 상위 로깅 설정 상속 여부 설정
        createLogger("root", INFO, true);
        createLogger("jdbc", OFF, false);
        createLogger("jdbc.sqlonly", DEBUG, false);
        createLogger("jdbc.sqltiming", OFF, false);
        createLogger("org.hibernate.SQL", DEBUG, false);
        createLogger("com.example.todolist.controller", DEBUG, false);
        createLogger("com.example.todolist.service", DEBUG, false);
        createLogger("com.example.todolist.domain", DEBUG, false);
    }

    private void createLogger(String loggerName, Level logLevel, Boolean additive) {

        Logger logger = logCtx.getLogger(loggerName);
        logger.setAdditive(additive);
        logger.setLevel(logLevel);

        logger.addAppender(consoleAppender);
    }

    private ConsoleAppender<ILoggingEvent> getLogAppender() {
        final String appendName = "STDOUT";
        PatternLayoutEncoder consoleLogEncoder = createLogEncoder(CONSOLE_PATTERN);
        ConsoleAppender<ILoggingEvent> logConsoleAppender = createLogAppender(appendName, consoleLogEncoder);
        logConsoleAppender.start();

        return logConsoleAppender;
    }

    private PatternLayoutEncoder createLogEncoder(String pattern) {
        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(logCtx);
        encoder.setPattern(pattern);
        encoder.start();
        return encoder;
    }

    private ConsoleAppender<ILoggingEvent> createLogAppender(String appendName, PatternLayoutEncoder consoleLogEncoder) {
        ConsoleAppender<ILoggingEvent> logConsoleAppender = new ConsoleAppender<>();
        logConsoleAppender.setName(appendName);
        logConsoleAppender.setContext(logCtx);
        logConsoleAppender.setEncoder(consoleLogEncoder);

        return logConsoleAppender;
    }
}

  • LogbackRolling.java : RollingFileAppender 설정

public class LogbackRolling {

    private final LoggerContext logCtx = (LoggerContext) LoggerFactory.getILoggerFactory();

    private final String ROLLING_PATTERN = "%d{yyyy-MM-dd HH:mm:ss.SSS}  %logger{5} - %msg %n";
    private final String FILE_NAME = "D:\\logs\\application.log";
    private final String LOG_NAME_PATTERN = "./logs/application-%d{yyyy-MM-dd-HH-mm}.%i.log";
    private final String MAX_FILE_SIZE = "10MB";
    private final int MAX_HISTORY = 2;

    private RollingFileAppender<ILoggingEvent> rollingAppender;

    public void logConfig(){
        rollingAppender = getLogAppender();
        createLoggers();
    }

    private void createLoggers(){
        createLogger("jdbc", OFF, false);
        createLogger("jdbc.sqlonly", DEBUG, false);
        createLogger("jdbc.sqltiming", OFF, false);
        createLogger("org.hibernate.SQL", DEBUG, false);
    }

    private void createLogger(String loggerName, Level logLevel, Boolean additive) {
        Logger logger = logCtx.getLogger(loggerName);
        logger.setAdditive(additive);
        logger.setLevel(logLevel);
        logger.addAppender(rollingAppender);
    }

    private RollingFileAppender<ILoggingEvent> getLogAppender() {
        final String appendName = "ROLLING_LOG_FILE";
        PatternLayoutEncoder rollingLogEncoder = createLogEncoder(ROLLING_PATTERN);
        RollingFileAppender<ILoggingEvent> rollingFileAppender = createLogAppender(appendName, rollingLogEncoder);
        SizeAndTimeBasedRollingPolicy rollingPolicy = createLogRollingPolicy(rollingFileAppender);

        rollingFileAppender.setRollingPolicy(rollingPolicy);
        rollingFileAppender.start();

        return rollingFileAppender;
    }

    private SizeAndTimeBasedRollingPolicy<RollingPolicy> createLogRollingPolicy(RollingFileAppender<ILoggingEvent> rollingLogAppender) {
        SizeAndTimeBasedRollingPolicy<RollingPolicy> policy = new SizeAndTimeBasedRollingPolicy<>();
        policy.setContext(logCtx);
        policy.setParent(rollingLogAppender);
        policy.setFileNamePattern(LOG_NAME_PATTERN);  
        policy.setMaxHistory(MAX_HISTORY);       
        policy.setTotalSizeCap(FileSize.valueOf(MAX_FILE_SIZE));
        policy.setMaxFileSize(FileSize.valueOf(MAX_FILE_SIZE));
        policy.start();
        return policy;
    }

    private PatternLayoutEncoder createLogEncoder(String pattern) {
        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(logCtx);
        encoder.setPattern(pattern);
        encoder.start();
        return encoder;
    }

    private RollingFileAppender<ILoggingEvent> createLogAppender(String appendName, PatternLayoutEncoder rollingLogEncoder) {
        RollingFileAppender<ILoggingEvent> logRollingAppender = new RollingFileAppender<>();
        logRollingAppender.setName(appendName);
        logRollingAppender.setContext(logCtx);
        logRollingAppender.setFile(FILE_NAME);
        logRollingAppender.setEncoder(rollingLogEncoder);

        return logRollingAppender;
    }
}

이제 두 설정 설정 파일을 Bean 등록해주면 됩니다. 추가로 @Profile 어노테이션을 사용하여 적용할 profile도 지정해주었습니다.
@Profile("local")
@Configuration
public class LogbackConfig {

    @Bean
    public LogbackConsole logbackConsole(){
        LogbackConsole logbackConsole = new LogbackConsole();
        logbackConsole.logConfig();
        return logbackConsole;
    }

    @Bean
    public LogbackRolling logbackRolling(){
        LogbackRolling logbackRolling = new LogbackRolling();
        logbackRolling.logConfig();
        return logbackRolling;
    }
}

참고하실 사항으로 LogbackConsole.java에 logConfig 함수 안에는 logCtx.reset() 코드가 있습니다. 저 함수를 제거하면 처음 어플리케이션이 기동할 때 따로 log 설정파일이 없다면 기본 ConsoleAppender가 root 로거에 적용됩니다. 이때 LogbackConsole.java이 bean 등록되어서 root 로거에 ConsoleAppender를 추가하면 root 에는 2개의 console 로거가 등록되어 같은 내용이 2번씩 Console에 찍히게 됩니다.

logCtx.reset()는 기존 설정 정보를 리셋하고 새로 등록할 root 로거만 사용하기 위해 사용하였습니다.

profile
daily study

0개의 댓글