Techit 11th 3rd

Huisu·2023년 6월 29일
0

Techit

목록 보기
26/42
post-thumbnail

Logging

Logging

초기에 컴퓨터 프로그래밍을 배울 때, 코드가 어떤 데이터를 생성하고, 그 데이터를 어떻게 변환했는지에 대한 결과를 위해서 가장 많이 활용하던 것은 System.out.println 이다. 이는 저희가 코드를 실행한 검은 터미널 화면에 전달받은 인자를 출력하는 용도의 함수라고 볼 수 있다.

저희가 실제로 서비스를 구축하고 서비스하고 있다면, 이 검은 화면을 계속 쳐다볼 수는 없을 것이다. 24시간 컴퓨터에 붙어있을 수도 없기 때문이다. 그렇다면 이 검은 화면에 나오고 있는 내용을 나중에 확인할 수 있도록, 이왕이면 파일의 형태로 남겨두면 좋을 것 같다. 이때 프로그램에서 일어난 일을 정리해서 남긴 파일을 로그라고 부르며, 이 파일을 만드는 행위를 로깅이라 합니다. 그리고 일반적으로 저희가 프로그래밍을 하면서 로그를 남기게 해주는 객체를 로거라고 부릅니다.

Spring Boot Logging

Spring boot를 사용한다면 Logging 의존성이 기본적으로 다 포함되어 있다.

Logbak이라는 스프링 부트에서 기본적으로 제공하는 로깅 프레임워크이다. 이외에도 Sl4fj (Simple Logging Facade 4 Java)로 Java에서 로그를 남기는 방법을 통일해 주는 프레임워크도 사용할 수 있다. 다만 Sl4fj는 로그를 남기는 프레임워크가 아니라 다양한 로그 프레임워크를 사용하는 방법의 디자인 패턴으로, 다양하게 파생된 로깅 라이브러리를 일원화해 주는 것이다.

Facade 패턴
복잡한 단계를 거치거나, 여러 구성 요소를 사용해서 도달해야 하는 기능을 좀더 단순하게 사용할 수 있는 인터페이스를 만드는 디자인 패턴의 일종입니다.

Logging 동작

우선 컨트롤러를 만들고 로거 객체를 통해 로깅을 하는 코드를 작성해 준다.

//@Slf4j
@RestController
public class TestController {
    private static final Logger log
            = LoggerFactory.getLogger(TestController.class);

    @GetMapping("/log")
    public void logTest() {
        log.trace("A TRACE Message");
        log.debug("A DEBUG Message");
        log.info("A INFO Message");
        log.warn("A WARN Message");
        log.error("A ERROR Message");
    }
}
  • LoggerFactory.getLogger : 로그를 남길 수 있는 로거를 남겨주는 Slf4j의 기능이다. 어떤 클래스에서 로그를 남겼는지를 기록하기 위해 TestController.class 를 인자로 전달한다.
    • @Slf4j : private static final Logger log = = LoggerFactory.getLogger(TestController.class); 를 자동으로 추가해주는 lombok 어노테이션 입니다.

이후 localhost:8080/log로 이동해서 결과를 보자.

우리가 만든 로그가 잘 나오는 것을 확인할 수 있다. 이때 로그 다섯 개 중에 왜 세 개만 남았는지 생각해 볼 수 있다.

Log Level

로그를 남기는 행위는 어느 컴퓨터 작업과 마찬가지로 자원을 소모하는 행위이다. 그래서 개발자가 로그를 남길 때, 어느 정도로 중요한지를 나누어서 상황에 따라 실제로 남길 로그를 결정할 수 있도록 로그의 레벨을 설정해 줄 수 있습니다. 이 로그 레벨은 언어와 프레임워크에 따라 다를 수 있는데 지금은 다섯 단계로 나누어서 살펴보면,

  • TRACE: 가장 낮은 단계의 로그로 아주 작은 변화의 로그를 남기는 레벨이다.
  • DEBUG: TRACE 보다는 조금 덜 구체적인, 개발자의 디버깅을 도와주는 로그를 남기는 레벨이다.
  • INFO: 어플리케이션이 실행중일 때 정보 제공의 목적으로 로그를 남기는 레벨이다.
  • WARN: 어플리케이션이 실행중일 때 안좋은 영향을 미칠 수도 있는 로그를 남기는 레벨이다. 단 이 레벨의 로그가 남았다고 당장 어플리케이션에 문제가 생긴 것을 의미하지는 않는다.
  • ERROR: 어플리케이션이 정상적으로 작동하지 못하는 상황에 대한 로그를 남기는 레벨이다. 정상적으로 처리하지 못한 요청 등에 대한 로그를 남긴다.

등으로 나눌 수 있다. 그리고 어플리케이션을 실행하면서, 어느 레벨의 로그까지 남기는지를 결정할 수 있는데, 기본값은 INFO 입니다. 어떤 레벨로 설정을 하던, 기본적으로 남는 로그는 해당 로그 레벨 및 그보다 중요도가 높은 레벨의 로그를 남깁니다. 즉 TRACE로 설정하면 모든 로그를, WARN으로 설정하면 WARN과 ERROR 로그만 실제로 작성되게 됩니다.

특별한 설정 없이 Log Level 만 조정하고 싶다면, application.yaml 을 활용할 수 있습니다. 바꿔서 로그가 다 남는지 확인해 봅시다.

logging:
  level:
    root: trace

LogBack

특정 파일에 로그를 남기거나 특정 날짜까지의 기록만 남겨 두고 싶을 때 Spring Boot는 resources의 logback.xml 또는 logback-spring.xml 파일을 자동으로 사용한다.

resources 폴더 밑에 logback-spring.xml 파일을 만들어 준다.

  • logback-spring.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    
        <property name="LOGS" value="./logs" />
    
        <appender name="Console"
                  class="ch.qos.logback.core.ConsoleAppender">
            <layout class="ch.qos.logback.classic.PatternLayout">
                <Pattern>
                    %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1}): %msg%n%throwable
                </Pattern>
            </layout>
        </appender>
        <appender name="File" class="ch.qos.logback.core.FileAppender">
            <file>${LOGS}/file-log.log</file>
            <encoder
                    class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <Pattern>%d %p %C{1} [%t] %m%n</Pattern>
            </encoder>
    
        </appender>
    
        <appender name="RollingFile"
                  class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${LOGS}/rolling-file-log.log</file>
            <encoder
                    class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <Pattern>%d %p %C{1} [%t] %m%n</Pattern>
            </encoder>
    
            <rollingPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                <fileNamePattern>${LOGS}/archived/rolling-file-log-%d{yyyy-MM-dd_HH-mm-ss}.%i.log
                </fileNamePattern>
                <maxFileSize>100MB</maxFileSize>
                <maxHistory>10</maxHistory>
                <totalSizeCap>1GB</totalSizeCap>
            </rollingPolicy>
        </appender>
    
        <!-- LOG everything at INFO level -->
        <root level="info">
            <appender-ref ref="RollingFile" />
            <appender-ref ref="Console" />
        </root>
    
        <!-- LOG "org*" at WARN level -->
        <logger name="org" level="warn" additivity="false">
            <appender-ref ref="Console" />
            <appender-ref ref="File" />
        </logger>
    
        <!-- LOG "com.example.contents*" at TRACE level -->
        <logger name="com.example.contents" level="trace" additivity="false">
            <appender-ref ref="RollingFile" />
            <appender-ref ref="Console" />
            <appender-ref ref="File" />
        </logger>
    
    </configuration>

이후 앱을 실행시키면 지금과는 다른 로그 파일이 보이고, 로그 폴더가 새로 생성된 것을 볼 수 있다.

**<appender>**

Logback에서 제공하는 Appender 인터페이스를 설정하기 위한 요소이다. Logback에서는 Appender를 통해서 로그를 어떻게 어떤 형식으로 남길지 정의하는 것이다.

  • ConsoleAppender : 저희 터미널 화면에 로그를 남기기 위한 Appender
  • FileAppender : 특정 파일에 로그를 남기기 위한 Appender
  • RollingFileAppender : 특정 조건에 따라 파일의 갯수 및 크기를 유지하면서 로그를 남기기 위한 Appender
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
    ...
</appender>

<appender name="File" class="ch.qos.logback.core.FileAppender">
    ...
</appender>
<appender name="RollingFile"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
    ...
</appender>

**<layout>** & **<encoder>**

로그의 형식을 정의하기 위한 요소이다. 둘 다 그 역할은 비슷하지만 차이가 있다면 Layout 은 패턴의 요소를 해석해서 특정 문자열로 바꾸기 위해 사용해 콘솔 창에서 확인하기 위해, Encoder 는 패턴의 요소를 해석해서 파일에 작성 가능한 byte[] 형태로 바꾸기 위해 사용한다는 차이이다. 그리고 둘 다 <Pattern> 이라는 요소를 가지고 있는데, 이 부분이 실제 로그의 출력을 조정하기 위한 부분이다. 이때 String.format 메소드와 유사하게 %d 와 같은 방식으로 해당 부분에 변할 수 있는 값을 설정해 준다. 여기에서 사용된 몇 가지만 살펴보면,

  • %d : 로그가 작성된 날짜
  • %p : 로그 레벨
  • %C : 로그를 남긴 클래스
  • %t : 로그를 남긴 쓰레드
  • %m : 로그 메시지
  • %n : 개행 문자

등을 나타낸다. 또한 Layout 의 경우 콘솔 출력시 색상 조절을 위한 %black 등도 존재함을 확인할 수 있다.

**<file>**

FileAppenderRollingFileAppender 는 파일의 형태로 로그를 남기기 때문에, 어떤 파일에 로그를 남길지에 대한 설정이다.

**<rollingPolicy>**

실제 서비스의 경우 사용자의 요청에 따라 로그가 빈번하게 남게 된다. 그래서 파일에 로그를 저장하다 보면 지나치게 큰 로그 파일 들이 서버에 남게 되는데, 초기에는 문제가 없지만 나중에는 서버의 용량을 차지하는 주범이 된다. 그래서 로그를 일정 기간 또는 사이즈 까지만 유지하는 것을 log rotation 또는 log rolling이라고 부른다. 그리고 이 로그를 남기는 기준을 정의하기 위한 요소가 <rollingPolicy> 요소이다. 아래의 설정의 경우

<rollingPolicy
        class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <fileNamePattern>${LOGS}/archived/rolling-file-log-%d{yyyy-MM-dd_HH-mm-ss}.%i.log
    </fileNamePattern>
    <maxFileSize>100MB</maxFileSize>
    <maxHistory>10</maxHistory>
    <totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
  • 파일 하나당 크기: 100MB
  • 전체 로그 파일들 총 크기: 1GB
  • 유지되는 파일의 갯수: 10개

이때 유지되는 파일은 fileNamePattern 이 변동되는 주기에 따라 갯수를 세게 된다. %d 부분은 이전에 Layout 처럼 시간을 나타내게 되는데, %d{yyyy-MM-dd_HH-mm-ss} 처럼 시간의 년월일 시분초 중 어디까지 표현할지를 결정할 수 있다. 여기에서 파일 이름에 남길 시간이 초 단위로 변경되면 초마다, 분 단위로 변경되면 분마다, 월 단위로 변경되면 월마다 로그 파일 하나를 만든다는 의미라고 볼 수 있다. 즉 파일의 갯수를 10으로, 파일 이름의 날짜를 %d{yyyy-MM-dd} 로 설정하면 총 10일 분의 로그를 유지한다고 볼 수 있다.

**application.yaml 에서 설정파일 지정**

마지막으로 설정 파일은 반드시 resources 에 포함시키지 않고, 외부에 저장해도 상관없다. 이 경우 application.yaml 에 설정 값으로

logging:
  config: file:logback-spring.xml

와 같이 작성해 주면 된다. 이때 경로는 정적 파일 경로를 설정 했을 때와 유사하게 동작한다.

Profiles

Spring Profiles

다양한 설정을 Profile이라는 단위로 나누어서 사용할 설정을 어플리케이션 실행 시에 결정할 수 있게 해 주는 Spring의 기능이다. 개발 단계에서 사용할 데이터베이스와 테스트 코드 용도의 데이터 베이스를 나누거나 서비스할 때 로그를 줄이고 싶은 경우에 사용한다.

application-{profile}.yaml

사용하고 싶은 profile 이름을 정하고 그 이름이 포함된 파일을 만들면 profile 설정 파일이 만들어진다. 예를 들어 테스트와 개발의 설정 파일을 다르게 하고 싶다면 아래와 같이 작성할 수 있다.

이후 application-test.yaml 파일을 작성한다.

spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password: password
  jpa:
    database: h2
    database-platform: org.hibernate.dialect.H2Dialect

# test니까 로그 증가
logging:
  level:
    root: debug

다음에 application.yaml 파일에서 profile을 설정해 준다.

0개의 댓글