0%

springboot에 log4j2 도입하기

springboot

java진영의 로깅 라이브러리는 log4j2가 굉장히 효율적입니다. (https://devscb.com/post/253)
그러나, 많이 사용되고 있는 springboot에서는 logback을 기본 로깅라이브러리로 사용하고 있습니다.
단순히 dependency 추가하면 되는것 아닌가 싶지만, 바로 빌드가 안되던 경험이 있어서 공유합니다.

maven을 사용할 경우

pom.xml의 dependencys 엘리먼트 하위에 아래 내용을 추가해줍니다.

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

그런데, 이렇게만 하면 spring boot 실행시 다음과 같은 붉은 메시지를 확인할 수 있습니다.

1
2
3
4
5
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/username/.m2/repository/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/username/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.17.2/log4j-slf4j-impl-2.17.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

이 메시지의 뜻은 log4j2와 logback 두 가지를 찾았으나, 실질적으로 사용하는것은 logback이라는 뜻입니다.
즉, log4j2를 사용하도록 정상적으로 반영이 안되었다는 뜻입니다.
이러한 메시지가 발생하는 이유는,
spring-boot-starter-logging에서 logback을 이미 채택하여 사용하고 있기때문에 정상동작이 안되는 것입니다.
이를 위해, spring-boot-starter-logging을 spring-boot-starter-web 프로젝트에서 아래와 같이 dependency에서 제외하도록(exclusion) 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--
스프링 부트에서 Log4j2를 사용하기위해선 내부로깅에서 쓰이는 의존성을 제외해주어야 합니다.
기본적으로 Spring은 Slf4j라는 로깅 프레임워크를 사용합니다.
구현체를 손쉽게 교체할 수 있도록 도와주는 프레임 워크입니다.
Slf4j는 인터페이스고 내부 구현체로 logback을 가지고 있는데,
Log4j2를 사용하기 위해 exclude 해야 합니다.
-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

springboot

gradle을 사용할 경우

build.gradle의 dependencies와 configurations 쪽에 아래와 같이 각각 내용을 입력해줍니다.
(log4j2 포함, spring-boot-starter-logging 제외)

1
2
3
4
5
6
7
8
9
dependencies {
implementation("org.springframework.boot:spring-boot-starter-log4j2")
}

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

설정파일 추가 - log4j2.xml

src/main/resources에 log4j2.xml 파일을 만들고,
아래와 같은 내용으로 작성해줍니다.
콘솔창으로는 모든 에러를 표시하고,
에러 로그가 발생하면 D:/spring_logs 경로에 파일로 남겨두며,
로그 파일 크기가 5MB이거나 1일 이후면 파일을 rolling 하며,
20개까지의 파일을 유지한다는 내용입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="UTF-8" ?>
<configuration status="INFO">
<Properties>
<Property name="LOG_LEVEL">info</Property>
<Property name="LOG_PATH">C:/spring_logs</Property>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} thr=%thread severity=%-5level logger=%c{1} %msg%n</Property>
</Properties>
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout disableAnsi="false" pattern="${LOG_PATTERN}"/>
</Console>

<RollingFile name="ErrorFileAppender"
fileName="${LOG_PATH}/spring.log"
filePattern="${LOG_PATH}/spring-%d{yyyy-MM-dd}-%i.log">
<!-- JsonLayout complete="false" compact="false" charset="UTF-8">
<KeyValuePair key="service" value="simple" />
</JsonLayout-->
<PatternLayout disableAnsi="false" pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" />
<SizeBasedTriggeringPolicy size="5MB" />
</Policies>
<DefaultRolloverStrategy max="20" fileIndex="min" />
</RollingFile>
</Appenders>


<Loggers>
<Root level="${LOG_LEVEL}">
<AppenderRef ref="ConsoleAppender" />
<AppenderRef ref="ErrorFileAppender" level="error" />
</Root>
</Loggers>
</configuration>

springboot

라이브러리 추가후, 로깅 코드 작성

sr/main/java 쪽에 아래와 같이 컨트롤러를 만들고,
Logger 클래스 객체를 만들어서 error와 info 로그를 출력하도록 코딩합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RequestMapping("/test")
public String test(){
logger.error("error_log");
logger.info("info_log");
return "test";
}
}

springboot

로깅확인

앞서 코딩한 내용을 브라우저에서 실행하면,
콘솔창에 로그가 찍한것을 볼 수 있고,
파일에는 에러 로그만 찍한것을 확인할 수 있습니다.
springboot