스프링프레임워크 log4j2 설정 : Spring Framework + log4j 2 + slf4j + jboss/wildfly(ver 9)

 

*  jdk : 1.7

*  framework : spring

*  was : jboss/wildfly 9

 

#기본개념

slf4j 는 interface, 

log4j 는 구현체

 

slf4j 사용시 소스에서 interface , imple 사용하듯 구현체만 바꾸면 돼서 

log4j 를 나중에 걷어내고 다른 log lib을 사용해도 소스레벨에서 수정할게 없음. 그래서 slf4j 사용.

 

log4j 2는 log4j 1랑 다른거 없이 log4j 2.x 대 버전을 의미.

(log4j 1.x 는 log4j 라고부르고 log4j 2 는 log4j 2.x 를 말하는 듯)

* log4j2 사용시 slf4j는 1.7.x 이상 사용

 

참고 : https://goddaehee.tistory.com/45

(위 고수님의 블로그에 log4j, slf4j, logback 에 관한 내용이 상세히 기술되어 있음)

 

[ # log4j 2 및 slf4j maven dependency 설정 ]

log4j-slf4j-impl jar(actifactId) 사용시 1.7.x 이하 version 사용

log4j-slf4j18-impl jar(actifactId) 사용시 1.8.x 이상 version 사용

참고 : https://logging.apache.org/log4j/2.x/log4j-slf4j-impl/index.html

 

[ pom.xml ]

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
39
40
41
42
43
44
45
<modelVersion>4.0.0</modelVersion>
    <groupId>com.sample</groupId>
    <name>SAMPLE</name>
    <packaging>war</packaging>
    <version>0.1</version>
    <properties>
        <!-- 생략 -->
        <org.slf4j-version>1.7.5</org.slf4j-version>
        <org.log4j-version>2.9.0</org.log4j-version>
    </properties>
 
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${org.springframework-version}</version>
    <exclusions>
        <!-- Exclude Commons Logging in favor of slf4j -->
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
         </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>${org.slf4j-version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${org.log4j-version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>${org.log4j-version}</version>
    <exclusions>
         <!-- Exclude Commons Logging in favor of log4j-core -->
         <exclusion>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
         </exclusion>
    </exclusions>
</dependency>
cs

* spring 의 경우 default 로 jcl(commons-logging)사용하므로 이를 slf4j 로 대체하기 위해 jcl-over-slf4j 사용

* jcl(commons-logging) 대신 slf4j 를 사용하므로 spring-context 에서 commons-logging 제거(exclude)

* jcl-over-slf4j 내부적으로 slf4j-api dependency 를 포함하고 있으므로 slf4j-api 는 별도의 dependency 로 추가 하지 않음

* log4j-core 내에 log4j-api dependency 포함하므로 log4j-slf4j-impl 에서 해당 의존성 제거

 

[ #log4j2.xml 설정 ]

src/main/resources/ 경로에 생성(/WEB-INF/classes/).

해당 위치에 파일을 위치시킬 경우 log4j 가 초기화 될 때 알아서 해당 파일을 읽어들임

 

* src/main/resource/ 밑이 아닌 기타 경로에 해당 파일을 위치시킬 경우

web.xml 에 아래와 같이 추가

참고 : https://okky.kr/article/282263

 

[ web.xml ]

1
2
3
4
5
6
7
8
9
  <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>classpath:~~~/log4j2.xml</param-value>
  </context-param>
  
  <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>
 
cs

 

[ log4j2.xml ]

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
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>    
    <Appenders>
        <Console name="console_root" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %5p %m%n" />
        </Console>
         <Console name="console_com" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %5p [%c] %m%n" />
        </Console>       
    </Appenders>
    
    
    <Loggers>
         <Logger name="java.sql" level="INFO" additivity="false">
            <AppenderRef ref="console_com" />
        </Logger>
        <Logger name="jdbc.sqltiming" level="INFO" additivity="false">
            <AppenderRef ref="console_com" />
        </Logger>
        <Logger name="egovframework" level="INFO" additivity="false">
            <AppenderRef ref="console_com" />
        </Logger>
        <Logger name="com" level="INFO" additivity="false">
            <AppenderRef ref="console_com" />
        </Logger>
        <Logger name="org.springframework" level="INFO" additivity="false">
            <AppenderRef ref="console_com" />
        </Logger>
        <Root level="INFO">
            <AppenderRef ref="console_root" />
        </Root>
    </Loggers>
</Configuration>
 
cs

 

[* 어펜더 (Appender) ]

어펜더는 로그이벤트를 목적지에 전달하는 역할을 한다.(타겟 목적지에 이벤트 데이터를 쓰는 역할)

어펜더는 Appender interface 를 구현한다.

name 속성을 가지며 이를 통해 로거에서 참조한다.

아래와 같은 어펜더가 존재.

ConsoleAppender : Sysout 을 찍는 용도로 사용되는 어펜더

FileAppender : 로그를 파일로 저장할 용도로 사용되는 어펜더

RollingFileAppender : FileAppender 에 Rollover 기능(파일 백업)을 추가한 어펜더

 

[* 로거 (Logger) ]

로거의 위계구조(hierarchy)에 대한 이해가 필요하다. 여기를 읽어보길 바란다.

아래는 로거 위계구조의 예이다.

com.sample.sampleController 클래스 내에서
protected Logger logger = LoggerFactory.getLogger(this.getClass());
logger.info("샘플로깅!");
과 같이 로그를 출력할 경우,
this.getClass()com.sample.sampleController를 반환하고,
해당 클래스는 com 패키지 하위의 클래스(com.*) 이므로 "com"이란 이름(name)으로 명명된 logger설정을 따른다.

* 만약 23~25line 의 "com" logger 를 제거한다면 com 패키지 하위 소스내(com.sample.sampleController)에서 찍은 로그는 Root 로거의 console_root 어펜더에 의해 출력된다. ("com" logger 있을 경우 : console_com(%d %5p [%c] %m%n) appender 에 의해 출력, 없을 경우 root logger인 console_root(%d %5p %m%n)  에 의해 출력

* 이와 같은 위계구조를 활용하여 라이브러리 내부에서 불필요 혹은 원치않는 로그를 출력하고 있는 경우, 해당 라이브러리 패키지 경로를 별도의 logger 로 잡아 로그 출력을 제거 할 수 있다.

* Root 로거는 매핑되는 logger 를 찾지 못하는 경우 가장 마지막에 사용되는 최상위 로거이며, Root 로거는 반드시 설정해주어야 한다.

 

[* 패턴 (PatternLayout) ]

%d 날짜 년월일시

%c : 클래스명

%5p : 로그레벨(5자리 길이 맞춰서 출력(5자리 이하일경우 공백열로 채워넣음))

%m : 메시지

%n : 줄바꿈

%t : 스레드명

 

[ # jboss 에서 log4j 사용시 필요한 설정 ]

: jboss 내부적으로 slf4j, log4j 라이브러리를 내장하고 있기 때문에

해당 부분을 exclude 하여 충돌요소를 제거

 

[ jboss-deployment-structure.xml ]

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
    <deployment>
        <exclusions>
            <module name="org.apache.log4j" />
            <module name="org.apache.commons.logging" />
            <module name="org.slf4j"/>
        </exclusions>
    </deployment>
</jboss-deployment-structure>
cs

참고 : http://blog.naver.com/PostView.nhn?blogId=djawl_2&logNo=220665045226&redirect=Dlog&widgetTypeCall=true
(위 고수님의 블로그에 jboss 환경변수를 이용하여 충돌을 막는 방법도 기재되어 있음)

 

[ # jboss 에서 log4j 2.10 버전 이상 사용시 발생하는 문제 ]

jboss 에서 log4j 2 2.10 이상 버전 사용시 발생하는 warn 로그 :

WARN  [org.jboss.as.server.deployment] (MSC service thread 1-5) WFLYSRV0003: Could not index class META-INF/versions/9/module-info.class at /content/example.war/WEB-INF/lib/log4j-api-2.11.1.jar: java.lang.IllegalStateException: Unknown tag! pos=4 poolCount = 32

서버동작에 문제는 없으나 was 기동시 WARN 로그 찍히는게 보기가 싫으니,  log4j 버전을 살짝 내려서 사용.

참고 : https://issues.jboss.org/browse/JBEAP-15261

(module-info.class 가 log4j 2.10 이상 버전에 존재하므로 해당 경고가 발생)

 

참고 : log4j 2 user guide

반응형

+ Recent posts