개발환경

  • SpringBoot v3.3.3
  • AWS EC2 (ubuntu)
  • RDS
  • Docker Compose
  • GithubActions

 

로그를 파일로 저장하기(환경 분리 포함)

스프링부트에서 local 환경과 prod 환경을 분리하여 로그를 남기는 방법은 아래의 글에서 참고하였다.

https://blog.pium.life/server-logging/

 

Logback을 이용해 운영 환경 별 로그 남기기

이 글은 우테코 피움팀 크루 '그레이'가 작성했습니다. 로깅이란 ? 우리가 처음 개발을 할 때 System.out.println(), cout << "hello world" << endl, print() 등으로 원하는 대로 동작하고 있는지 출력하곤 했을

blog.pium.life

 

이 글은 local 환경에서는 콘솔에서 로그를 확인할 수 있고 prod환경에선 info 로그와 error 로그 파일을 분리할 수 있는 설명이 담겨있다.

 

먼저 application.yml에서 프로필을 분리해주어야 한다.

  • application-local.yml
spring:
  config:
    activate:
      on-profile: local

 

  • application-prod.yml
spring:
  config:
    activate:
      on-profile: prod

 

 

이후 /src/main/resources 에 아래의 파일을 정의한다.

이 파일들은 로그 내용을 파일로 저장할 때 쓰는 파일이다.(Logback)

  • console-appender.xml
<included>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
</included>

 

  • file-info-appender.xml
<included>
    <appender name="FILE-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>./log/info-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
            <maxFileSize>50MB</maxFileSize>
            <maxHistory>60</maxHistory>
            <totalSizeCap>5GB</totalSizeCap>
        </rollingPolicy>
    </appender>
</included>

 

  • file-error-appender.xml
<included>
    <appender name="FILE-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>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>./log/error-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
            <maxFileSize>50MB</maxFileSize>
            <maxHistory>60</maxHistory>
            <totalSizeCap>5GB</totalSizeCap>
        </rollingPolicy>
    </appender>
</included>

 

  • logback-spring.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>

    <property name="CONSOLE_LOG_PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %clr(%5level) %cyan(%logger) - %msg%n"/>
    <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger - %msg%n"/>

    <!--local-->
    <springProfile name="local">
        <include resource="console-appender.xml"/>

        <root level="INFO">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>

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

        <root level="INFO">
            <appender-ref ref="FILE-INFO"/>
            <appender-ref ref="FILE-ERROR"/>
        </root>
    </springProfile>

</configuration>

 

이렇게 설정하면 local  환경에서는 콘솔로 로그를 확인할 수 있고, prod 환경에서는 ./log 폴더에 날짜별로 info와 error 로그 내용을 저장할 수 있다.

날짜 뒤에 숫자는 같은 날짜의 로그파일을 구분하는 숫자이고, 로그 파일이 50MB를 넘었을 때 새로운 파일에 로그를 저장하고 숫자가 1 증가하여 저장된다.

  • 예를들어 error-2024-10-11.0.log의 파일 용량이 50mb가 넘었을 시에 error-2024-10-11.1.log이 생성되고 여기에 로그를 마저 저장하는 것이다.

또한 error-2024-10-11.0.log의 파일 용량이 50mb가 넘었을경우 gz라는 확장자로 압축하여 저장하게 된다.

이를 통해 로그 파일의 용량을 최소화하여 저장할 수 있다.

마지막으로 error를 저장하는 로그와 info를 저장하는 로그 파일  각각 60개가 넘었을 시에 가장 오래된 로그파일을 삭제하도록 되어있다.

 

이 로그파일은 ./log 폴더에 저장되는데 내 프로젝트는 도커 환경에서 실행되므로 도커 볼륨을 통하여 도커 컨테이너 외부에 저장할 필요가 있다.

 

Docker Volume 을 이용하여 로그파일을 컨테이너 외부에 저장

먼저 dockerfile은 아래와 같다.

  • dockerfile
# 베이스 이미지로 OpenJDK 17 사용
FROM openjdk:17-jdk

# 애플리케이션을 위한 작업 디렉토리 설정
WORKDIR /spring-boot

# 빌드된 JAR 파일을 컨테이너로 복사
COPY build/libs/*SNAPSHOT.jar promise.jar

# 애플리케이션 실행
ENTRYPOINT ["java", "-jar", "/spring-boot/promise.jar"]

WORKDIR 이 /spring-boot로 설정되어있다.

그래서 log 폴더는 컨테이너 내부의 spring-boot/log에 생성된다.

 

  • compose.yml
services:
  ...
    volumes:
      - /home/ubuntu/promise/log:/spring-boot/log
  ...

이 옵션을 통해서 컨테이너에 존재하고 있던 log 폴더를 외부로 빼낼 수 있다.

즉, 도커 컨테이너 내부의 spring-boot/log 폴더를 ec2 인스턴스의 /home/ubuntu/promise/log 폴더와 공유하게 된다.

이렇게 하면 도커 컨테이너가 종료되거나 삭제되어도 로그 파일을 유지할 수 있다.