[Spring] 스프링의 로깅

이멀젼씨

·

2021. 6. 20. 21:34

목적

로깅에 대한 지식과 사용방법을 익혀 개발에 도움이 되게 하기 위함

목차

  1. 스프링의 로깅 프레임워크
  2. Lombok의 로거 애노테이션
  3. 로그 레벨
  4. 로그 메시지에 파라미터 넣기
  5. 로깅 Layout
  6. 로그 출력하기
  7. logback-spring.xml

1. 스프링의 로깅 프레임워크

스프링은 기본적으로 로깅프레임워크를 의존성을 갖고 있다.

Log4J, SLF4J, Logback 세 가지 이다.

Logback은 로깅 프레임워크 중 하나이다.

SLF4j는 로깅 프레임워크의 구현이 아니고, Log4J와 유사한 Java의 모든 로깅 프레임 워크에 대한 추상화이다.

추상화라함은 공통된 개념은 뽑아내고 자세한 구현은 감춘다는 얘기로, SLF4J는 로깅 프레임워크들의 공통된 API를 제공하고, 그에 대한 구현은 프레임워크에서 각각 구현한 코드를 사용하겠다는 말이다.

2. Lombok의 로거 애노테이션

로거를 사용하기 위해 간단하게 애노테이션 하나만 붙여주면 애노테이션 아래의 코드들이 자동으로 생성된다.

아래는 Lombok에서 제공해주는 애노테이션이고, 사용하고자 하는 애노테이션을 사용하면 된다.

@CommonsLog

private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@Log

private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());

@Log4j2

private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

@Slf4j

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

3. 로그 레벨

레벨 설명
TRACE DEBUG보다 더 세분화 된 정보 이벤트를 지정합니다.
DEBUG 애플리케이션을 디버그하는 데 가장 유용한 세분화 된 정보 이벤트를 지정합니다.
INFO 대략적인 수준에서 응용 프로그램의 진행 상황을 강조하는 정보 메시지를 지정합니다.
WARN 잠재적으로 유해한 상황을 지정합니다.
ERROR 애플리케이션이 계속 실행되도록 허용 할 수있는 오류 이벤트를 지정합니다.

위에서 아래순으로 보면 된고, 선택한 로그 레벨을 포함하여 해당 로그 레벨 아래쪽에 있는 레벨의 로그까지 다 보여준다.

INFO를 선택한 경우 INFO, WARN, ERROR의 로그를 보여준다.

4. 로그 메시지에 파라미터 넣기

'{}'를 사용하여 출력할 메시지를 담을 수 있다.

Integer age =  23;  
//Logging the information 
logger.info("At the age of {} ramu got his first job", age);

출력결과는 아래와 같이 나오게 된다.

INFO: At the age of 23 Ramu got his first job

5. 로깅 Layout

로깅 Pattern Layout

로그를 사용자가 지정한 형식으로도 출력이 가능하다.

일반적으로 사용되는 몇가지만 짚어보겠다.

  • %d : 날짜를 출력한다.

    %d - 2006-10-20 14:06:49,812
    %date - 2006-10-20 14:06:49,812
    %date{ISO8601} - 2006-10-20 14:06:49,812
    %date{HH:mm:ss.SSS} - 14:06:49.812
    %date{dd MMM yyyy;HH:mm:ss.SSS} - 20 oct. 2006;14:06:49.812

  • p / le / level : 레벨을 출력한다.

  • t / thread : 로그를 발생시키는 쓰레드를 출력한다.

  • c{length}, lo{length}, logger{length} : 로깅 이벤트의 오리지날 로거 이름을 출력한다.

    length는 몇자로 축약할 것인지 길이를 적는 공간이다.

  • m / msg / message : 로깅 메시지를 출력한다.

로깅 Format modifiers

로깅 pattern layout 앞에 숫자들이 붙은걸 본 적이 있을 것이다.

이 숫자들은 메시지의 포맷을 정해준다.

포맷 설명
%20logger 로거 이름이 20 자 미만인 경우 공백으로 왼쪽을 채운다.
%-20logger 로거 이름이 20 자 미만인 경우 공백으로 오른쪽 채운다
%.30logger 로거 이름이 30 자보다 길면 앞에서부터 자른다.
%20.30logger 로거 이름이 20 자 미만인 경우 공백으로 왼쪽을 채운다. 그러나 로거 이름이 30 자보다 길면 앞에서부터 자른다.
%.-30logger 로거 이름이 30 자보다 길면 끝에서부터 자른다.

더욱 자세한 내용을 알고 싶다면 아래 링크를 참조하자.
https://logback.qos.ch/manual/layouts.html#writingYourOwnLayout

6. 로그 출력하기

Appenders

Appender란 한마디로 로그출력 방식을 의미한다.

자주 사용되는 Appender위주로 설명하겠다.

  • ConsoleAppender : 콘솔에 로그를 출력한다. 아래는 속성들이다.
    • encoder : 로그가 출력되는 방식을 결정한다. pattern 속성을 사용하여 패턴을 지정한다.
    • target : 문자열 값 System.out 또는 System.err 중 하나입니다. 기본 설정은 System.out입니다.
    • withJansi : 기본값은 false로 설정된다. true로 설정하면 Windows 시스템에서 ANSI 색상 코드를 지원하는 Jansi 라이브러리가 활성화된다.
  • FileAppender : 파일에 로그를 출력한다.
    • append : 기본값은 true로 기존 파일 끝에 로그가 추가된다.
    • encoder : 로그가 출력되는 방식을 결정한다. pattern 속성을 사용하여 패턴을 지정한다.
    • file : 파일의 위치와 이름을 지정한다.
      파일이 없으면 새로 생성된다.
      경로 설정 시 백슬래시를 사용할때 escape문자를 사용하여야 한다.(C:/temp 또는 C:\\temp와 같이 사용해야한다.)
    • prudent : true일 경우 다른 FileAppender 인스턴스가있을때 지정된 파일에 안전하게 기록합니다. 기본은 false이다.
  • RollingFileAppender : 조건 충족 시 로그 출력 대상을 다른 파일로 변경할 수 있다.
    • append : 기본값은 true로 기존 파일 끝에 로그가 추가된다.
    • encoder : 로그가 출력되는 방식을 결정한다. pattern 속성을 사용하여 패턴을 지정한다.
    • file : 파일의 위치와 이름을 지정한다.
      파일이 없으면 새로 생성된다.
      경로 설정 시 백슬래시를 사용할때 escape문자를 사용하여야 한다.(C:/temp 또는 C:\\temp와 같이 사용해야한다.)
    • prudent : true일 경우 다른 FileAppender 인스턴스가있을때 지정된 파일에 안전하게 기록합니다. 기본은 false이다.
    • rollingPolicy : 조건을 만족시켰을때 RollingFileAppender의 동작을 설정한다.
    • triggeringPolicy : RollingFileAppender에게 롤오버 절차를 활성화 할시기를 설정한다.

7. logback-spring.xml

클래스패스에 아래와 같은 파일 이름이 있다면 스프링부트가 자동으로 파일을 로드한다

  • logback-spring.xml
  • logback.xml
  • logback-spring.groovy
  • logback.groovy

아래는 필자가 작성한 logback-spring.xml이다.

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

    <property name="LOG_PATTERN" value="%d{yy-MM-dd HH:mm:ss} %-5level [%thread]  [%logger.%method:%line] - %msg%n"/>

    <springProperty scope="context" name="LOG_PATH" source="log.config.path"/>
    <springProperty scope="context" name="LOG_FILE_NAME" source="log.config.fileName"/>
    <springProperty scope="context" name="LOG_ERROR_FILE_NAME" source="log.config.errorFileName"/>
    <springProperty scope="context" name="LOG_LEVEL" source="logging.level.root"/>

    <!-- Console Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- RollingFile Appender -->
    <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>
            <charset>UTF-8</charset>
        </encoder>
        <!-- Rolling 정책 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- .gz,.zip 등을 넣으면 자동 일자별 로그파일 압축 -->
            <fileNamePattern>${LOG_PATH}/${LOG_FILE_NAME}.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 파일당 최고 용량 kb, mb, gb -->
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- 일자별 로그파일 최대 보관주기(~일), 해당 설정일 이상된 파일은 자동으로 제거-->
            <maxHistory>30</maxHistory>
            <!--<MinIndex>1</MinIndex>-->
            <!--<MaxIndex>10</MaxIndex>-->
        </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}/${LOG_ERROR_FILE_NAME}.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>${LOG_PATTERN}</Pattern>
            <charset>UTF-8</charset>
        </encoder>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${LOG_ERROR_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>

    <root level="${LOG_LEVEL}">
        <appender-ref ref="FILE"/>
        <appender-ref ref="CONSOLE"/>
    </root>

</configuration>