Programming/Spring Boot

Spring Boot Logging 이란? (log4j, logback, log4j2)

Jan92 2021. 8. 25. 00:41

logging

 

Log, Logging이란?

 

로깅(logging)이란 시스템 동작시 시스템의 상태와 작동 정보를 시간의 경과에 따라 기록하는 것을 말합니다. 그리고 그 기록을 로그라고 합니다.

로깅을 하는 이유는 소프트웨어의 동작 상태를 파악하고 문제가 발생했을 때, 그 동작을 파악해 소프트웨어의 문재를 찾아내고 해결하기 위해서 입니다. 즉, 소프트웨어의 디버깅이나 모니터링을 위하여 정보를 기록하는 곳에 사용되는데 기존의 Debugger나 println에 비해 로그가 가지는 장점은 아래와 같습니다.

 

  • 상황별 Level 지정하여 Level별 메시지를 선택 가능
  • 응용 프로그램의 실행에 대한 흐름과 에러 확인 가능
  • 프레임워크를 이용하여 간단하고 쉬운 사용 환경 조성 기능
  • 모듈 별로 유연하게 메세지 출력 가능
  • 자유로운 출력 위치 및 다양한 출력 형식 지원

 

 

< 2021.12.10 발견된 Log4j2 취약점 >

 

Apache Log4j2 치명적 취약점, 해결방안은? CVE-2021-44228

Log4j2 치명적 취약점 'CVE-2021-44228' Log4j2는 아파치 소프트웨어 재단에서 자바(Java) 언어로 제작된 로깅 라이브러리로, 서버와 프로그램의 유지 관리를 목적으로 동작 상태를 기록으로 남기기 위해

wildeveloperetrain.tistory.com

 


 

 

로깅 관련 프레임워크  log4j,  logback,  log4j2  그리고  slf4j

 

로깅 관련 프레임워크는 대표적으로 log4j, logback, log4j2 가 있습니다.

log4j -> logback -> log4j2 순서로 등장하였고, logback, log4j2는 둘 다 log4j를 기반으로 하고 있어 설정하는 방법이나 사용 방법이 유사합니다.

log4j는 2015년 개발이 중단되었기 때문에 제외하고 logback, log4j2에 대해서 알아보겠습니다.

 

 

 

logback

 

logback은 log4j와 유사하면서도 향상된 성능과 필터링 옵션을 제공하며, slf4j도 지원합니다. 자동 리로드 기능도 지원합니다.

 

* 자동 리로드

Linux 서버 내에서 log4j를 사용할 시 log level을 변경하게 되면, 서버를 재가동하여 변경 사항을 적용해줘야 하는 반면에 logback은 서버를 재가동할 필요 없이 즉각 자동 리로드를 지원해줍니다.

 

spring boot 환경의 경우 spring-boot-starter-web > spring-boot-starter-logging에 기본적으로 logback 구현체가 포함되어 있습니다. 그렇기 때문에 spring boot 환경에서 로깅 프레임워크를 따로 설정하지 않으면 logback이 기본으로 적용됩니다.

 

 

log4j2

 

log4j2는 logback 이후에 나온 만큼 logback과 마찬가지로 필터링 기능과 자동 리로드 기능을 가지고 있습니다.

logback과의 가장 큰 차이점은 Multi Thread 환경에서 비동기 로거(Async Logger)의 경우 log4j, logback 보다 처리량이 더 높고, 대기 시간이 훨씬 짧습니다. 

추가적으로 람다 표현식과 사용자 정의 로그 레벨도 지원합니다.

 

* spring boot에서 log4j2를 사용하기 위해서는 dependency에서 logback을 제거해주는 작업이 필요합니다.

스프링 부트는 기본 설정으로 logback을 사용하기 때문에 log4j2 의존성을 추가하더라도 기본 설정으로 잡힌 logback이 동작하게 됩니다.

 

 

 

slf4j (Simple Logging Facade For Java)

 

slf4j는 로깅에 대한 추상 레이어로 위에서 본 logback, log4j2 같은 로깅 프레임워크의 인터페이스 역할을 하며, slf4j를 이용하면 코드를 일정하게 유지하면서 구현체의 전환 (다른 프레임워크로의 전환)을 쉽고 간단하게 할 수 있습니다.

 

* logback, log4j2는 slf4j의 구현체

 

 

 


 

 

logback 설정

 

spring boot에서 기본으로 사용되는 logback의 설정에 대해 좀 더 알아보겠습니다.

 

<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>1.2.3</version>
</dependency>
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-core</artifactId>
	<version>1.2.3</version>
</dependency>

 

(spring boot가 아닌 경우)

 

Maven을 빌드툴으로 사용하는 프로젝트에서 logback 관련 dependency를 추가하려고 하면 logback-core, logback-classic 두 가지를 확인할 수 있습니다.

core의 경우 로깅 프레임워크로서의 핵심 기능이 포함되어 있고, classic의 경우 핵심 기능에 slf4j에 대한 지원 같은 추가 기능을 제공합니다.

 

 

	// 전체 레벨 지정
	logging.level.root=info

	// 패키지별로 로깅 레벨 지정
	logging.level.com.example.controller=info
	logging.level.com.example.service=debug

 

log에 대한 세부적인 설정을 하려면 logback.xml 파일을 통한 설정이 필요하고, 간단하게 콘솔 로그만 확인하기 위해서는 application.properties (또는 .yml) 파일에 로그 레벨을 설정하는 것만으로 로그를 확인할 수 있습니다.

 

 

 

logback.xml

 

application.properties 또는 application.yml 으로도 로깅 설정이 가능하지만 세부적인 설정을 위해서는 .xml 파일이 필요합니다.

 

* logback.xml,  logback-spring.xml,  logback.groovy,  logback-spring.grooby 

위 파일들 중 하나로 세부 설정을 할 수 있으며, 일반적으로는 logback.xml 파일을 사용, spring boot에서는 logback-spring.xml 파일을 사용합니다.

 

 

xml 파일의 경로는 src/main/resources 경로 아래이며, 참조되는 순서는 아래와 같습니다.

  1. classpath(src/main/resources 경로 아래)에 logback-spring.xml 등의 파일이 있으면 설정 파일을 읽습니다.
  2. logback-spring.xml 등의 파일이 없다면 .properties || .yml 파일의 설정을 읽습니다.
  3. .xml 파일과 .yml(.properties) 파일이 동시에 있을 경우 .yml 파일 적용 후 .xml 파일이 적용됩니다.

 

spring.profiles.active=local
logging.config=classpath:logback-${spring.profiles.active}.xml

 

.properties (또는 .yml) 의 위 설정을 통해 배포 환경에 따른 로깅 설정을 할 수도 있습니다.

 

 

 


 

.xml 파일 설정

 

먼저 로그 레벨은 TRACE  <  DEBUG  <  INFO  <  WARN  <  ERROR  총 5가지가 있으며, ERROR 부터 높은 레벨을 가집니다.

출력 레벨의 설정에 따라 설정 레벨 이상의 로그를 출력합니다. 예를 들어 로깅 레벨을 INFO로 설정했을 경우 TRACE, DEBUG 레벨의 로그는 무시됩니다.

 

 

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

  <!-- 변수값 설정 -->
  <property name="LOGS_PATH" value="/logs"/>
  <property name="LOGS_LEVEL" value="INFO"/>

  <!-- Console Appender -->
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- 출력 패턴 설정 -->
    <layout class="ch.qos.logback.classic.PatternLayout">
      <pattern>%d{HH:mm} %-5level %logger{36} - %msg%n</pattern>
    </layout>
  </appender>

  <!-- File Appender -->
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 파일명과 경로 설정 -->
    <file>${LOGS_PATH}/log_file.log</file>
    <!-- 출력 패턴 설정 -->
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n</pattern>
      <charset>UTF-8</charset>
    </encoder>
    <!-- Rolling 정책 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- .gz,.zip 등을 넣으면 자동 일자별 로그파일 압축 -->
      <fileNamePattern>${LOGS_PATH}/%d{yyyy-MM-dd}_%i.log</fileNamePattern>
      <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <!-- 파일당 최고 용량 -->
        <maxFileSize>10MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
      <!-- 일자별 로그파일 최대 보관주기(~일), 해당 설정일 이상된 파일은 자동으로 제거-->
      <maxHistory>60</maxHistory>
    </rollingPolicy>
  </appender>

  <!-- Error Appender -->
  <appender name="Error" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 파일명과 경로 설정 -->
    <file>${LOGS_PATH}/error_file.log</file>
    <!-- 출력 패턴 설정 -->
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n</pattern>
      <charset>UTF-8</charset>
    </encoder>
    <!-- Rolling 정책 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- .gz,.zip 등을 넣으면 자동 일자별 로그파일 압축 -->
      <fileNamePattern>${LOGS_PATH}/%d{yyyy-MM-dd}_error_%i.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>
  </appender>

  <!-- 지역 설정 -->
  <logger name="org.springframework.web" level="DEBUG" additivity="false">
    <appender-ref ref="STDOUT"/>
  </logger>

  <!-- 전역 설정 -->
  <root level="${LOGS_LEVEL}">
    <appender-ref ref="STDOUT"/>
    <appender-ref ref="File"/>
    <appender-ref ref="Error"/>
  </root>
  
</configuration>

* logback-spring.xml 설정 예시

 

 

 

.xml 설정은 크게 Appender, Logger 두 가지로 설정으로 나뉩니다.

 

Appender

: 이벤트마다 로그를 기록하는 기능을 처리하는 객체로 로그의 출력 위치, 출력 형식 등을 설정합니다.

  • ConsoleAppender : 로그를 콘솔에 출력
  • FileAppender : 로그를 지정 파일에 기록
  • RollingFileAppender : FileAppender을 상속받아 날짜, 용량 등을 설정하여 패턴에 따라 로그가 각기 다른 파일에 기록
    (해당 기능을 활용하여 대량의 로그를 효과적으로 기록할 수 있습니다.)
  • SMTPAppender : 로그를 메일로 발송
  • DBAppender : 로그를 Database에 기록

 

Logger

: 실제 로그 기능을 구현하는 객체입니다. 각 Logger 마다 name을 통해 구분합니다. 최상위 로거인 Root Logger를 설정하여 이를 계층적으로 활용할 수 있습니다.

 

 

 

 

다음은 세부적인 설정 옵션입니다.

 

property

: 설정 파일에서 사용될 변수 값

 

 

layout, encoder

: 시간과 내용을 제어하는 옵션으로 encoder가 layout에 비해 제어할 수 있는 범위가 넓습니다.

 

 

pattern

: 패턴에 사용되는 요소

 

 

file

: log를 기록할 파일명과 경로 설정

 

 

rollingPolicy

: ch.qos.logback.core.rolling.TimeBasedRollingPolicy - 일자별 적용

  ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP - 일자별 + 크기별 적용

 

 

fileNamePattern

: 파일 쓰기가 종료된 log 파일명의 패턴 지정 (.gz .zip 으로 설정 시 자동으로 압축됩니다.)

 

 

maxFileSize

: 최대 파일 용량 (log 내용의 크기도 성능에 영향을 줄 수 있기 때문에 10MB 이내로 저장하는 것이 권장됩니다.)

 

 

maxHistory

: 일자별 로그 파일 최대 보관 주기

  (SizeAndTimeBasedRollingPolicy에서 maxHistory가 동작하지 않는 이슈가 있다고 합니다. 1.2.3 버전)

 

 

root, logger

: root의 경우 전역 설정, logger의 경우 특정 패키지 로깅 레벨 설정 (지역 설정)

  (지역적으로 선언된 logger 설정이 있다면 해당 설정이 우선으로 적용됩니다.)

 

 

 

@RestController
public class TestController {

    private static Logger logger = LoggerFactory.getLogger(this.getClass());

    @GetMapping("/log")
    public logTest() {

        logger.trace("trace log");
        logger.debug("debug log");
        logger.info("info log");
        logger.warn("warn log");
        logger.error("error log");
    }
}

 

log 사용법

 

 

 

 

참고 사이트

https://www.sangkon.com/hands-on-springboot-logging/

https://goddaehee.tistory.com/206

https://velog.io/@ym1085/log4j-vs-logBack

https://romeoh.tistory.com/entry/Spring-Boot-Logback-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0