본문 바로가기

Tech/Spring | SpringBoot

[SpringBoot] Logging - 3 (log4j2)

반응형

이전에 springboot 의 로깅 프레임워크를 공부하면서 logback 까지만 공부하고 사용했었다. 보다 최신 로깅 프레임워크인 log4j2 를 한번 들여다보고 싶었는데 기회가 없다가 이번에 개인 공부를 하면서 로그 환경을 설정할 기회가 있어서 log4j2 에 대해서 알아보았다.

1. log4j2

log4j2 는 자바 로깅 프레임워크 중 하나로 log4j 의 최신버전이다. 비동기 로깅을 통해서 logback 이나 이전버전의 log4j 보다 성능을 향상시킨 버전이다.

Log4j2 기능

Async Logger

log4j2 는 비동기 로깅 기능이 추가되었다. 비동기 로깅은 I/O 작업을 별개의 스레드에서 실행하도록 하여 애플리케이션의 성능을 향상시킨다. 이를 통해서 logger 가 처리할 수 있는 처리량이 늘어나고, log 함수의 응답시간이 짧아진다. log4j2 에서는 모든 로거를 비동기로 구성할 수도 있고 비동기와 동기를 섞어서 구성할 수도 있다.

 

비동기 로깅의 단점도 있는데, 예외처리가 어렵다는 것이다. 로깅과정에서 예외가 발생하는 경우 애플리케이션으로 에러에 대한 정보를 알리기 어렵다. 이때문에 비즈니스 로직의 중요한 로그인 경우에는 동기 방식으로 해당 정보를 로깅하는 것을 추천한다.

Garbage-free

log4j 의 이전 버전을 비롯한 대부분의 로깅 라이브러리들은 로그 이벤트 객체, 문자열, 문자 배열 이나 바이트 배열 등등의 임시 객체들을 할당하여 사용하였다. 이러한 방식은 garbage collector 에 부하를 주어서 GC pause 가 더 자주 일어나게 된다. GC pause 가 자주 일어나면 일어날수록 요청의 대기시간이 늘어나고 애플리케이션의 성능이 떨어지게 된다.

 

log4j2 에서는 garbage free 모드를 기본으로 제공해준다. 이들은 임시 객체를 생성해서 사용하는 것이 아닌 이전의 객체와 버퍼들을 재사용함으로써 GC 의 부하를 줄인다.

 

이외에도 람다식 사용이나 메시지, 필터 등등의 기능이 개선된 부분이 있는데 자세한 사항은 공식문서에서 확인할 수 있다.

 

Log4j – Overview

Copyright © 1999-2023 The Apache Software Foundation. All Rights Reserved. Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, and the Apache Logging project logo are trademarks of The Apache Software Foundation.

logging.apache.org

2. springboot log4j2 적용

springboot 에서 log4j2 를 사용하기 위한 환경 설정을 하는 과정이다.

1) 라이브러리 설정

우선 log4j2 라이브러리를 추가해주어야 한다. gradle 프로젝트 이기 때문에 아래와 같이 build.gradle 파일의 dependencies 에 log4j2 라이브러리를 추가해준다.

 

dependencies {
	implementation "org.springframework.boot:spring-boot-starter-log4j2";
}

 

만약 spring-boot-starter-web 라이브러리를 사용하고 있다면 spring-boot-starter-logging 라이브러리를 dependencies 에서 제외해주어야 한다. springboot 는 기본 로깅 프레임워크로 logback 을 사용하고 있는데, log4j2 를 사용하기 위해서는 라이브러리 설정에서 logback 을 사용하는 부분을 제외시켜야 한다. 아래와 같이 build.gradle 에서 설정해준다.

 

configurations {
	all {
		exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
	}
}

2) properties 파일 설정

springboot 프로젝트의 resources 아래에 application.properties 파일에서 logging 설정 파일을 추가한다. 이때 경로는 실제 설정 파일이 위치하는 경로로 지정해준다.

 

logging.config=classpath:logger/log4j2.xml

3) 로그 설정 파일 작성

application.properties 에서 지정해준 경로에 로그 설정 파일을 작성한다. springboot 프로젝트의 src/main/resources/ 아래에 해당 경로 대로 파일을 추가한다. 예제의 경우에는 "src/main/resources/logger/log4j2.xml" 파일을 추가한다.

 

로그 설정 파일의 형식과 예제에 대해서는 아래에서 자세하게 설명한다.

3. log4j2 configuration

log4j2 xml, json, yaml 그리고 properties 형식으로 설정 파일을 작성할 수 있다. 또한 ConfigurationFactory 와 Configuration 을 구현하여 프로그래밍 적으로도 설정할 수 있다. 보통은 configuration file 을 작성하는 방식을 많이 사용하고 공식 문서에서도 설정 파일 작성을 기반으로 설명하기 때문에 xml 형식의 configuration 파일 작성을 기반으로 log4j2 의 설정 파일 형식을 적용하였다.

 

log4j2 설정은 xml 형식부터 시작됐기 때문에 트리 형식으로 구성된다. 트리구조의 각 요소들을 설정하면 이를 통해서 log4j2 의 로거에 반영된다. 여러가지 요소들이 많아서 전부를 다룰 수는 없고 자주 사용되는 요소들만 정리한다. 실제 로거를 설정할 때에는 필요한 요소를 찾아보고 사용하면 된다.

xml configuration 예제

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Properties>
        <Property name="logPath">./logs/test/</Property>
        <Property name="consoleLayoutPattern">%style{%date{UTF-8}}{black} %highlight{%level} [%style{%thread}{bright,blue}] %style{%class}{bright,yellow}: %message %throwable%n
        </Property>
        <Property name="fileLayoutPattern">%date %level %class{1.} [%thread] %message%n</Property>
    </Properties>

    <Appenders>
        <Console name="ConsoleAppender" target="SYSTEM_OUT">
            <PatternLayout pattern="${consoleLayoutPattern}"/>
        </Console>

        <File name="FileAppender" fileName="${logPath}/file.log">
            <PatternLayout pattern="${fileLayoutPattern}"/>
            <Filters>
                <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
        </File>

        <Async>
            <AppenderRef ref="FileAppender"/>
        </Async>


        <RollingFile name="FileDebugAppender"
            fileName="${logPath}/debug.log" filePattern="${logPath}/debug.log.%d{yyyy-MM-dd}">
            <PatternLayout pattern="${fileLayoutPattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy modulate="true" interval="1" />
            </Policies>
            <DefaultRolloverStrategy max="500" fileIndex="min" />
        </RollingFile>

        <RollingFile name="FileInfoAppender"
            fileName="${logPath}/info.log" filePattern="${logPath}/info.log.%d{yyyy-MM-dd}"
            immediateFlush="false">
            <PatternLayout pattern="${fileLayoutPattern}"/>
            <LevelRangeFilter maxLevel="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <Policies>
                <TimeBasedTriggeringPolicy modulate="true" interval="1" />
            </Policies>
            <DefaultRolloverStrategy max="500" fileIndex="min" />
        </RollingFile>
    </Appenders>

    <Loggers>
        <Logger name="org.springframework" additivity="false" level="INFO">
            <AppenderRef ref="ConsoleAppender"/>
            <AppenderRef ref="FileDebugAppender"/>
            <AppenderRef ref="FileInfoAppender"/>
        </Logger>

        <Logger name="com.project" additivity="false" level="DEBUG">
            <AppenderRef ref="ConsoleAppender"/>
            <AppenderRef ref="FileDebugAppender"/>
            <AppenderRef ref="FileInfoAppender"/>
        </Logger>

        <Root additivity="false" level="OFF">
            <AppenderRef ref="ConsoleAppender"/>
        </Root>
    </Loggers>
</Configuration>

1) Configuration

xml 설정 파일의 최상위 요소이다. 하위 요소로 Properties, Loggers, Appenders 등을 가지고 있다.

2) Properties

xml 파일 안에서 사용할 변수를 정의할 때 사용한다. Properties 요소 안에 하위 요소로 여러 Property 를 사용하여 이후의 설정에 사용한다. 예제에서는 "logPath", "consoleLayoutPattern", "fileLayoutPattern" 3가지 property 를 정의하고 있다.

3) Appenders

Appenders 는 로그가 출력되는 곳을 정의할 때 사용한다. Appenders 에 정의된 Appender 들은 Logger 에서 AppenderRef 로 참조하여 사용된다.

Console

ConsoleAppender 는 System.out 또는 System.error 를 사용하여 화면에 로그를 출력한다. 로그 형식을 설정하기 위한 layout 을 반드시 설정해야 하는데, 이 예제에서는 PatternLayout 을 사용하여 로그 형식을 지정하였다. PatternLayout 의 자세한 형식은 아래 링크를 통해서 확인할 수 있다.

 

 

Log4j – Log4j 2 Layouts

facility String The facility is used to try to classify the message. The facility option must be set to one of "KERN", "USER", "MAIL", "DAEMON", "AUTH", "SYSLOG", "LPR", "NEWS", "UUCP", "CRON", "AUTHPRIV", "FTP", "NTP", "AUDIT", "ALERT", "CLOCK", "LOCAL0",

logging.apache.org

File

FileAppender 는 fileName 에 지정된 파일에 로그가 기록된다. layout 으로는 PatternLayout 을 사용하였고, 그 아래에 Filters 라는 요소가 추가되어 있다.

 

Filters 는 이름 그대로 로그의 필터링을 설정하는 태그로 Filter 의 조건에 따라서 로그가 해당 Appender 의 목적지에 출력될지 안될지를 결정한다. Filter 는 지정된 기준을 비교하여 해당 로그에 대한 처리 여부를 반환하는데, 이 값은 Enum 으로 선언된 ACCEPT, DENY, NEUTRAL 3가지 중 하나의 값으로 반환된다.

 

위의 예제에는 ThresholdFilter 와 LevelRangeFilter 두가지가 사용되고 있다.

ThresholdFilter 는 특정한 loglevel 을 기준으로 로그를 필터링 한다. 로그의 레벨이 level 에 지정된 값과 같은 경우 onMatch 의 값을 반환하고 값이 다른 경우에는 onMismatch 의 값을 반환하여 로깅을 수행하도록 한다.

LevelRangeFilter 는 특정 레벨이 아닌 minLevel 과 maxLevel 을 포함한 구간의 레벨을 기준으로 필터링을 수행한다. 이때 minLevel 의 기본값은 OFF, maxLevel 의 ALL 이다.

Async

AsyncAppender 는 다른 Appender 를 참조하여 실행되는데, 해당 설정으로 로그를 작성할 때 별개의 로깅 스레드를 생성하여 해당 스레드로 로깅이 수행되도록 한다. 별개의 스레드에서 실행되기 때문에 로깅시에 발생된 예외는 애플리케이션으로 전달되지 않는다.

 

AsyncAppender 는 내부적으로 java.util.concurrent.ArrayBlockingQueue 를 사용한다. 이는 멀티스레드 애플리케이션에서 여러 스레드가 병령적으로 로깅을 수행할 때 성능이 저하될 수 있다. 이때문에 멀티스레드 애플리케이션인 경우에는 Async loggers 를 통한 성능 최적화를 고려해야한다.

RollingFile

RollingFileAppender 는 FileAppender 와 같이 fileName 에 지정된 로그 파일에 로그를 기록한다. 다른점은 TriggeringPolicy 또는 RolloverPolicy 등의 태그로 정의된 조건에 따라서 로그 파일을 rollover 해서 설정된 파일 이름으로 저장하고 새로운 로그 파일을 생성하여 사용한다.

 

fileName 은 로그 파일의 이름에 대한 설정이고 filePattern 은 rollover 에 의해서 생성되는 파일의 이름에 대한 설정이다. immediateFlush log4j2 의 비동기 로거와 관련되 설정인데, log 가 입력되는 데로 바로바로 출력할 것인지를 설정하는 속성이다. log4j2 는 성능 향상을 위해서 로그의 출력을 배치로 작업하도록 할 수 있는데, immediateFlush True 로 설정하면 로그가 생성될때 바로 flush 되는 것이 아니라 배치로 수행하여 flush 된다. 이 방식이 성능적으로는 효율적이지만 때로는 아직 배치 단위가 채워지지 않은 경우에는 로깅이 되지 않아서 로그 파일에서 내용을 확인할 수 없기 때문에 유의해야 한다.

 

예제에서는 Policies 아래의 TimeBasedTriggeringPolicy 와 DefaultRolloverStrategy 를 통해서 rollover 를 지정하고 있다. TimeBasedTriggeringPolicy 는 interval 로 지정된 시간에 따라서 rollover 를 수행합니다. 이때 interval 의 시간 단위는 filePattern 에 따라서 결정됩니다. filePattern 이 "yyyy-MM-dd" 이면 일 단위, "yyyy-MM-dd-hh-mm" 이면 분 단위가 됩니다. 예제의 경우 일자까지만 지정했기 때문에 interval 의 1은 1일이 되고 매일 일자가 바뀔때마다 rollover 가 수행되게 됩니다.

 

DefaultRolloverStrategy 는 rollover 된 로그파일들을 관리하는 기준을 설정하는 요소이다. 예제에서는 max 를 사용하고 있는데, max 는 rollover 파일의 최대 개수를 의미한다. max 넘어서게 되면 가장 오래된 파일부터 삭제된다.

Loggers

Loggers 는 로깅을 수행하는 로거를 설정하는 요소이다. 하위 요소는 Logger 와 Root 가 존재한다.

 

Logger 는 프로그래밍에서 사용할 로거를 정의하는 것으로 name 을 통해서 로거 설정이 적용된 패키지 범위를 설정할 수 있다. 예제에서는 각각 "org.springframework" 패키지와 "org.project" 라는 패키지에 대해서 각각 로깅하는 Logger 를 정의했다. additivity 는 중복 로깅의 여부를 설정하는 요소로 여러 로거가 동일한 파일에 로깅하는 경우 로그를 중복으로 로깅할 지에 대한 여부를 설정한다. level 은 로그의 레벨을 의미하는 속성으로 지정된 레벨 이상의 로그들만 로깅한다.

 

Root 는 일반적인 로그 정책에 대한 정의를 하는 요소이다. Root Logger 는 반드시 하나가 정의되어야 한다.

[Reference]

- https://adjh54.tistory.com/74

 

[Java/Library] Slf4j - Log4j2 이해하고 설정하기

해당 글에서는 로깅 라이브러리에 대해 이해를 하고 개발환경을 구성하는 것을 목적으로 작성하였습니다 1) 개발 환경 💡 해당 글은 Spring Boot 내에 로깅 라이브러리를 적용한 개발 환경입니다.

adjh54.tistory.com

- https://logging.apache.org/log4j/2.x/manual/configuration.html

 

Log4j – Configuring Log4j 2

Configuration Inserting log requests into the application code requires a fair amount of planning and effort. Observation shows that approximately 4 percent of code is dedicated to logging. Consequently, even moderately sized applications will have thousan

logging.apache.org

- https://pakss328.medium.com/log4j2-xml-%EC%84%A4%EC%A0%95-a3aa0d1bea2f

 

log4j2 xml 설정

log4j2에서 xml설정 간 제일 중요한것은 xml 설정이라 생각된다.  그래서 실제 사용하는 xml을 기반(살짝 편집한)으로 하나하나 뜯어보도록 하자.

pakss328.medium.com

- https://velog.io/@byeongju/Log4j2-AsyncLogger%EC%99%80-%ED%95%A8%EA%BB%98-%ED%95%98%EB%8A%94-Logging-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95#logback%EA%B3%BC-log4j2

 

Log4j2 AsyncLogger와 함께 하는 Logging 환경 구축

2023 글로벌미디어학부 졸업 작품 프로젝트 Dandi 에서 Logging 환경을 구축한 과정

velog.io

 

반응형

'Tech > Spring | SpringBoot' 카테고리의 다른 글

[Spring] JaCoCo  (0) 2023.02.23
[Spring] lombok - @Builder  (0) 2023.01.30
[Spring] MapStruct  (1) 2023.01.08
[Spring] ResponseEntity  (0) 2022.12.31
[SpringBoot] 예외처리 - 3 (@ExceptionHandler, @ResponseStatus, @ControllerAdvice)  (0) 2022.12.20