728x90

Log4j에서 LOGBack으로 마이그레이션 하기 ( migrate from log4j to logback)

몇년전 부터 프로젝트에서 로그 라이브러리로 “LOGBack“를 사용하고 있습니다.

혹시나 모르시는 분을 위해서 간략하게 설명하면 “LOGBack“은
Log4J“, “Apache Common Logging“, “Java Logging” 같은 “Logger” 라이브러리 입니다.
또한 “Log4J“를 만든 개발자가 만들어서 “Post Log4J“라고도 합니다.

보다 자세한 내용은 예전에 제가 포스팅 했던

logback을 사용해야 하는 이유 (Reasons to prefer logback over log4j)

을 참고 하시기 바랍니다.

프로젝트를 신규로 만들때는 “LOGBack” 라이브러리 와
logback.xml (log4j.xml와 비슷한 설정 파일)” 파일 두 가지만 있으면
쉽게 적용이 가능 합니다.

하지만 대부분 기존 시스템들은 “Log4J“를 이미 사용하고 있거나 또는 본인 의지와 상관 없이
3rd 라이브러리들이 내부적으로 사용하고 있는 경우 일 것입니다.
이럴 경우 몇가지 주의해야 할 사항에 대해서 말씀 드리겠습니다.

# SLF4J

마이그레이션에 대한 설명을 드리기 전에 “SLF4J“에 대한 이해가 필요 합니다.
SLF4J의 핵심은 다양한 Logger 구현체들을 추상화를 통해서 언제든지 교체 가능 할수 있도록 하는 것입니다.
즉,  “Logger Facade” 라이브러리 입니다.

concrete-bindings

(이미지 출처 : http://www.slf4j.org/images/concrete-bindings.png)

위의 그림을 보게되면 모든 “어플리케이션“은 구현체를 직접 호출하는 것이
아니라 “SLF4J API를 호출하게 됩니다.

SLF4J는 전달받은 메세지 정보를 실제 구현체로 전달 합니다.

pseudocode 코드로 표현 하면

1
2
3
4
5
6
7
8
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
private static final Logger LOGGER = LoggerFactory
            .getLogger(Dummy.class);
public void echo () {
   LOGGER.info("hello SLF4J");
}

어플리케이션을 개발하는 사람은 “SLF4J API를 사용하며, 여기에는 실제
구현체에 대해서 명시하지 않습니다.

이렇게 API로 랩핑하기 때문에 “Logger 구현체“를 쉽게 교체할수 있도록 합니다.

Bridge Log4J

Migration“을 가장 쉽게 하는 방법은 단지 “Log4J” 라이브러리를  제거하고 “LOGBack“라이브러리를
추가 하는 것입니다.

하지만 문제는 3rd (외부 라이브러리)가 직접 구현체 “Logger”를 호출한다는 것입니다.

pseudocode 코드로 표현 하면

1
2
3
import org.apache.log4j.Logger;
...
private static Logger logger=Logger.getLogger("LoggingExample");

직접 작성한 소스인 경우는 요새 워낙 IDE가 제공하는 “refactoring” 기능이 좋아서
금방 작업을 할 수 있지만, 외부 라이브러리 같은 경우는 “어플리케이션 제어권 밖”
이기 때문에  난처한 상황이 발생 합니다.

혹시나 해서 본인의 어플리케이션을 구동해서 에러가 없다 하더라도
논리적으로 이러한 “Issue“는 잠재적으로 발생한다는 것입니다.

저 같은 경우는 Junit을 실행할때는 문제가 없다가 전체 어플리케이션을
구동할때 “ClassNotFoundException“가 발생했던 기억이 나며, 생각보다
해당 “Issue“를 디버깅하기는 쉽지 않습니다.

제가 말씀드리고 싶은건  마이글이션시 SLF4J를 사용하던, Log4J 구현체를 사용하건
어플리케이션을 다쳐서는 안된다는 것입니다.

SLF4J“에서는 다행히 이러한 이슈를 해결하기 위해서 “extend” 라이브러리를 제공 합니다.

slf4j-with-jcl-and-log4j

(이미지 출처 : http://espenberntsen.files.wordpress.com/2010/06/slf4j-with-jcl-and-log4j.png)
log4j-over-slf4j.jar” 파일을 압축해제하면 “log4j.jar” 와
동일한 패키지, 클래스가 존재 합니다.
즉, 패키지, 클래스를 동일하게 해서 구현체 클래스를 fake하는 것입니다.

그렇게 호출된 로그정보(메세지, 로그레벨…) 는 SLF4J에게 전달하고 바인딩된
LOGBack“이 실제로 로그를 Write하는 것입니다.

Maven (pom.xml)

Migration“에서 필요한 라이브러리를 아래와 같이 추가 합니다.

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
36
37
38
...
 
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.0.13</version>
 </dependency>
 <dependency>
<groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.0.13</version>
 </dependency>
 <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.0.13</version>
 </dependency>
 <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.5</version>
 </dependency>
 <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.5</version>
 </dependency>
 <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.5</version>
 </dependency>
 <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jcl</artifactId>
    <version>1.7.5</version>
 </dependency>
...

logback.xml

logback.xml (설정 파일)”을 “classpath“경로에 생성 합니다.

이미지 2--

기본 설정을 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
 
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
 
<root level="debug">
<appender-ref ref="STDOUT" />
 </root>
</configuration>

multiple SLF4J bindings

모든 설치/설정이 끝나고 “어플리케이션”를 구동하면 에러 없이 정상적으로 기동이 되는데
LOGBack” 설정이 안되는 경우가 있습니다.

그런 이유는 “SLF4J” 인터페이스를 구현한 구현체가 아직까지 존재하기 때문입니다.
아래 그림을 보면 SLF4J가 구동하면서 binding 대상을 scan
합니다.
내부적으로는 깊게 봐야하겠지만 현상으로 보면 여러 구현체 중에서 첫번째 것을
채택을 합니다.

이미지 3

그래서 “Log4J” 라이브러리를 혹시 참조하는 것이 있는지 확인을 하고, 혹시 있다면
exclude를 해야 합니다.

※ Log4J 관련된 라이브러리들만 exculde 해야 합니다.

라이브러리 관계 와 Exclude를 하는 것은 쉽지가 않습니다. 하지만 Eclipse에서 제공하는
Maven 플러그인을 사용하면 좀더 쉽게 수정 할 수 있습니다.

이미지 5

오른쪽 에디터에서 중복된 라이브러리를 체크 후 exclude를 하면서
왼쪽 라이브러리 path에서 빠져있는지 동시에 확인 합니다.

Migration“이 정상적으로 되었다면 아래와 같이 “LOGBack” 메세지를 확인 할수 있습니다.
이미지 6

conclusion

지금까지 “Log4J“에서 “LOGBack“로 “migration” 하는 방법에 대해서 설명 드렸습니다.
Logger 코드”는 소스 대부분에 많이 삽입이 되어 있어서 반드시 꼼꼼하게 확인이 필요하며
“과연 마이그레이션을 해야하는 것인가?”에 대한 충분한 팀 협의가 필요하고
만약 마이그레이션을 한다면 본 포스팅이 조금이나 도움이 되었으면 합니다.


반응형

'BigData > LogBack' 카테고리의 다른 글

1. logback 사용해야 하는 이유  (0) 2016.01.20

+ Recent posts