백앤드(스프링)

로깅 남바 투

유승혁 2022. 8. 22. 02:00

 서버 배포를 앞두고 유지 보수를 위한 필수 정보인 로그를 파일로서 저장할 방법을 알아보았다. 로깅 레벨이나 설정 같은 것은 지난 번에 다루었으니 그보다 큰 틀인 파일 관리 특징들에 대해 다루겠다. 예를 들면 error 같은 로그는 따로 모은 다거나, 날짜 별로 로그를 모으게 끔 하고 일정 용량이 벗어나면 zip 파일로 묶게 하고 기준 날짜 지나면 자동 삭제되는 이러한 일련의 과정을 하는 법을 보여주겠다.

 

0. 기본 설정 

resources 폴더 밑에 logback-local.properties 파일을 만들고 아래와 같은 코드를 입력해야 한다.

log.config.path=/Users/yuseunghyeog/desktop
log.config.filename=local_log

저장할 위치와 파일 이름이다. 만약에 경로를 현재 프로젝트 밑에 하고 싶다면 ./logs와 같은 방식으로 하면 가장 상위 폴더인 프로젝트 이름 바로 하위에 생긴다. 아래 사진 처럼.

 

 당연히도 application.properties에 아래와 같이 정의해준다.

logging.level.root=info
spring.profiles.active=local

 

[logback-spring.xml]

resources 밑에 이 xml 파일을 만들어서 설정해 주면 된다. 최종 코드는 맨 밑에 올릴테니 복붙해서 쓰면 되고, 이전에 조각조각내어 하나씩 확인해보자.

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
 ...
 모든 설정 정보
 ...
</configuration>

 위 코드로 모든 설정 정보를 감싸면 된다. configuration tag의 경우 scanPeriod를 통해 60초마다 설정 파일이 변경되어 있다면 확인하 고 적용하게끔 한다.

<springProfile name="local">
    <property resource="logback-local.properties"/>
</springProfile>
<springProfile name="dev">
    <property resource="logback-dev.properties"/>
</springProfile>
<springProperty scope="context" name="LOG_LEVEL" source="logging.level.root"/>

<springProfile> 태그를 통해 log설정했던 properties에 있는 정보를 통해 resource이름으로 개발 버전에 맞는 로그 레벨을 선택할 수 있다. 

<springProperty>태그는 Logback 안에서 사용을 위해 스프링 Environment 으로부터 속성을 드러나도록(expose) 한다.

 

<!-- log file path -->
<property name="LOG_PATH" value="${log.config.path}"/>
<!-- log file name -->
<property name="LOG_FILE_NAME" value="${log.config.filename}"/>
<!-- err log file name -->
<property name="ERR_LOG_FILE_NAME" value="err_log"/>
<!-- pattern -->
<property name="LOG_PATTERN" value="%-5level %d{yy-MM-dd HH:mm:ss}[%thread] [%logger{0}:%line] - %msg%n"/>

 property에서는 file 경로와 file 이름, log pattern 등을 지정 할 수 있다. logback-local.properties에 정의되어 있던 이름들을 사용하는 모습들을 볼 수 있다.

 패턴찍어주는 암호문을 하나씩 뜯어 보자.

 - %-5level은 로그 레벨을 출력하라는 것이다. -5는 출력을 5글자로 고정한다는 것.

 - %d는 로그 기록 시간이고 yy-MM-dd 뭐 이부분은 유명하니 넘어가자

 - %thread는 스레드 이름!

 - %logger{0}:%line은 최대 0 자리수로 logger 이름을 축약하게끔 한건데, 0으로 출력을 생략하고 :%line을 통해 해당 class의 몇번째 줄이었는지 나오게끔 한다.

 - %msg를 통해 로그 메시지가 나오게끔 하였고

 - %n으로 줄바꿈을 적용했다.

뿐만 아니라 다양한 패턴을 더욱 적용할 수 있다. 

 

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

위에서 정의한 패턴 대로 console 로그에 적용했당. ConsoleAppender를 통해 class를 지정하고 encoder 타입도 지정했다.

 

<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>

    <!-- 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>

 위 콘솔과 비슷하게 file로그도 정의해준다. 사실 우린 이거 하려고 여기까지 왔다 크크.

 Rolling 정책의 경우 로그 파일에 대해 정의하는 거다. 주석에도 자세히 다루었듯이 일자별로 로그 파일을 묶을 것이고 해당 일자에 로그가 많이 찍힌다면 용량 제한을 걸어 분리하고 압축하게끔 했다. 

 fileNamePattern으로 파일 이름 형식도 지정할 수 있고 maxFileSize로 용량도 지정하고 maxHistory를 통해 보관 주기 또한 지정해따.

 

 마지막으로는 error 전용 로그를 찍어보는 것이다.

<!-- 에러의 경우 파일에 로그 처리 -->
<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>
    ...
    이전 코드와 같음
    ...
</appender>

 <level>을 통해 레벨을 설정하고 <onMatch>와 <onMismatch>를 통해 저장 여부를 지정한다.

 

 또한 이 xml파일에서도 루트 레벨, 패키지 레벨 별로 로그 레벨을 지정할 수 있다.

<!-- root레벨 설정 -->
<root level="${LOG_LEVEL}">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/>
    <appender-ref ref="Error"/>
</root>

<!-- 특정패키지 로깅레벨 설정 -->
<logger name="org.apache.ibatis" level="DEBUG" additivity="false">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/>
    <appender-ref ref="Error"/>
</logger>

 

전체 코드는 아래와 같다. 주석 달아놓은 버전으로 올리겠당. 아마 여기 블로그 말고도 다른 블로그에서 많이 볼 수 있는 코드이다. 굳이 올리지 말까 ㅎㅎ 그래야징