SIFT Appender 를 사용하여 로그 분기처리

 

[설정]

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
46
<?xml version="1.0" encoding="UTF-8"?>
 
<configuration>
 
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}[%-5level] : %msg%n</Pattern>
        </encoder>
    </appender>
 
    <appender name="TST" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}[%-5level]-%msg%n</Pattern>
        </encoder>
    </appender>
 
    <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
        <discriminator>
            <key>discr</key>
            <defaultValue>type</defaultValue>
        </discriminator>
        <sift>
            <appender name="FILE-${discr}" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <file>/${discr}.log</file>
                <layout class="ch.qos.logback.classic.PatternLayout">
                    <Pattern>%d [%thread] %level %mdc %logger{35} SIFT- %msg%n</Pattern>
                </layout>
                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                    <fileNamePattern>/${discr}_%d{yyyy-MM-dd-HH-mm}.%i.log</fileNamePattern>
                </rollingPolicy>
            </appender>
        </sift>
    </appender>
 
 
    <logger name="jpabook.jpashop.service.OrderService" level="error" additivity="false">
        <!--<appender-ref ref="TST"/>-->
        <appender-ref ref="SIFT"/>
    </logger>
 
    <root level="debug">
        <appender-ref ref="CONSOLE"/>
    </root>
 
 
</configuration>
cs

 

[테스트]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.slf4j.MDC;
 
@Slf4j
public class Sample {
    public void testLog(){
        MDC.put("discr""TYP1");
        //log.
        log.trace("test trace");
        log.debug("test debug");
        log.info("test info");
        log.warn("test warn");
        log.error("test error");
 
        MDC.put("discr""TYP2");
        log.error("test error222");
    }
}
cs

 

[결과]

 

* ThreadPool 사용시 MDC key값을 전달받지 못함.

 : MDC.setContextMap 으로 key 값 전달가능

 참고 : https://stackoverflow.com/questions/6073019/how-to-use-mdc-with-thread-pools

 

* slf4j MDC 를 사용하지 않더라도, strategy pattern 과 같은 디자인 패턴을 사용하고, 분기처리할 구현체에 logger 를 지정하여 패키지 경로마다 별도 로그 파일 및 별도 경로의 로그파일에 로그 적재가 가능할 듯.

 

반응형

※ 들어가기에 앞서, Spring Framework, maven, jboss(wildfly) 환경에서 log4j설정하는 법은 이곳을 참고.

 

log4j.xml 파일을 아래와 같이 설정한다.

pom.xml 및 기타 설정은 되어있다 가정

 

[log4j.xml]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
 
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%-5p: %c - %m%n" />
        </Console>
    </Appenders>
    
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="console" />
        </Root>
    </Loggers>
 
</Configuration>
 
cs

 

위에 설정한 콘솔 로그를 출력하기 위해 아래와 같이 Sample.class 를 만들어준다.

[Sample.class]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.log;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class Sample {
    
    protected static final Logger logger = LoggerFactory.getLogger(Sample.class);
    protected static final Logger fileLogger = LoggerFactory.getLogger("fileLogger");
    
    public static void main(String[] args) {
        
        logger.info("Sample.class logger print with info level");
        
        fileLogger.info("fileLogger logger print with info level");
    }
 
}
 
cs

"fileLogger 를 name 으로 하는 logger 가 없는데?" 라는 생각이 들겠지만 일단 main 메소드를 실행시켜보자.

 

[Sample.class 실행결과]

INFO : com.log.Sample - Sample.class logger print with info level
INFO : fileLogger - fileLogger logger print with info level

Exception을 찍거나, 혹은 아무것도 찍지 않을 줄 알았던 fileLogger.info(~); 가 로그를 정상적으로 찍고 있다.

이를 이해하려면 log4j 의 위계구조 (hierarchy) 에 대한 이해가 필요하다.

 

[log4j 위계구조 (hierarchy)]

1. 모든 로거의 최상위 부모는 Root 로거이다.

2. class 에서 로그를 출력하는데 사용된 logger가 log4j.xml 에 존재하지 않는다면, 부모 로거를 찾는다.

: Sample.class 9번 라인의 fileLogger 는 "fileLogger" 라는 name을 갖는 로거를 log4j.xml 에서 찾았으나, 해당 이름의 로거가 존재하지 않으므로 부모인 Root 로거를 타게된 것. (마찬가지 이유로, Sample.class 에서 8번라인의 ~.getLogger(Sample.class) 부분을 ~.getLogger("") 과 같이 바꿔도 로거는 정상출력된다)

 

 

이번엔 log4j 를 다음과 같이 수정 후, 위의 Sample.class 메인메소드를 다시 실행해보자.

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
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%-5p: %c - %m%n" />
        </Console>
    </Appenders>
    
    <Loggers>
        <Logger name="com" level="INFO" >
            <AppenderRef ref="console" />
        </Logger>
        
        <Logger name="com.log" level="INFO" >
            <AppenderRef ref="console" />
        </Logger>
        
        <Logger name="com.log.Sample" level="INFO" >
            <AppenderRef ref="console" />
        </Logger>
        
        <Root level="INFO">
            <AppenderRef ref="console" />
        </Root>
    </Loggers>
    
</Configuration>
 
cs

 

[실행 결과]

INFO : com.log.Sample - Sample.class logger print with info level
INFO : com.log.Sample - Sample.class logger print with info level
INFO : com.log.Sample - Sample.class logger print with info level
INFO : com.log.Sample - Sample.class logger print with info level
INFO : fileLogger - fileLogger logger print with info level

com.log 패키지 경로에 있는 Sample.class (Sample.class 의 1번라인 참고)는 자신의 클래스명과 일치하는 name을 가진 Logger를 찾는다.

com.log.Sample 로거의 appender 로 로그가 찍히고, 

com.log 로거의 appender 로 로그가 찍히고,

com 로거의 appender 로 로그가 찍히고,

Root 로거의 appender 로 로그가 찍혀 총 4번의 로그가 찍혔다. (fileLogger 제외)

(부모 > Root > com > com.log > com.log.Sample > 자식)

 

이번엔 아래와 같이 com.log 로거에 additivity="false" 속성을 추가해보자

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
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%-5p: %c - %m%n" />
        </Console>
    </Appenders>
    
    <Loggers>
        <Logger name="com" level="INFO" >
            <AppenderRef ref="console" />
        </Logger>
        
        <Logger name="com.log" level="INFO" additivity="false">
            <AppenderRef ref="console" />
        </Logger>
        
        <Logger name="com.log.Sample" level="INFO" >
            <AppenderRef ref="console" />
        </Logger>
        
        <Root level="INFO">
            <AppenderRef ref="console" />
        </Root>
    </Loggers>
    
</Configuration>
cs

 

[실행결과]

INFO : com.log.Sample - Sample.class logger print with info level 
INFO : com.log.Sample - Sample.class logger print with info level 
INFO : fileLogger - fileLogger logger print with info level

com.log.Sample 로거의 appender 로 로그가 찍히고,

com.log 로거의 appender 로 로그가 찍히고 끝이난다.

additivity 값을 false 로 주면 부모 로거로의 전달을 막게된다. (default 값은 true)

 

 

[실제 응용]

1. 특정 레벨의 로그는 별도의 파일로 관리

콘솔로그는 INFO 레벨 이상(INFO < WARN < ERROR...)인 경우 출력,

ERROR(ERROR < FATAL) 레벨 이상의 로그는 별도의 파일에 작성하여 관리하고자 하는 경우

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
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%-5p: %c - %m%n" />
            <ThresholdFilter level="INFO"/>
        </Console>
        
        <RollingFile name="logFile" fileName="/logs/api.log" filePattern="/logs/$${date:yyyyMM}/app_%d{yyyyMMdd}-%i.log.gz">
            <PatternLayout pattern="%-5p: %m%n" />
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" />
                <SizeBasedTriggeringPolicy size="100MB"/>
            </Policies>
            <ThresholdFilter level="ERROR"/>    
        </RollingFile>    
    </Appenders>
    
    
    <Loggers>
        <Logger name="com" additivity="false">
            <AppenderRef ref="console" />
            <AppenderRef ref="logFile" />
        </Logger>
          
        <Root level="INFO">
            <AppenderRef ref="console" />
        </Root>
    </Loggers>
</Configuration>
 
cs

FileAppender 는 로그를 파일에 작성하기 위해,

RollingFileAppender 는 로그를 파일에 저장 + 롤아웃(백업) 하기 위해 사용한다.

이외에도 다양한 Appender 들이 지원되니 다른 appender 가 필요하다면 공식 document 를 참고하면된다.

 

TimeBasedTriggeringPolicy 는 시간에 의한 백업

SizeBasedTriggeringPolicy 는 로거 파일 용량에 의한 백업

filePattern 은 백업 파일형식

ThresholdFilter 는 appender 의 로그 레벨을 지정

 

위 설정은 아래와 같다.

com 밑의 모든 class 에서 출력하는 INFO 레벨 이상의 콘솔 로그를 %-5p: %c - %m%n 포맷으로 찍는다.

com 밑의 모든 class 에서 출력하는 ERROR 레벨 이상의 콘솔 로그를 %-5p: %m%n 포맷으로 /logs/api.log 파일에 기록한다.

용량이 100MB 초과할 경우, 혹은 하루가 지난 경우(매일) 로그 파일을 /logs/년월/app_년월일-백업시퀀스.log.gz 이름으로 압축한다.

 

 

※ logback에서의 설정은 아래와 같다

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
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- doc : http://logback.qos.ch/documentation.html -->
<!-- xml example : https://mkyong.com/logging/logback-xml-example/ -->
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
         <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
      </encoder>
   </appender>
 
   <appender name="FILE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>/boot_jpa_log/log_stats.log</file>
      <encoder>
         <pattern>%m%n</pattern>
      </encoder>
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <fileNamePattern>/boot_jpa_log/old/log_stats_%d{yyyyMMdd}.log</fileNamePattern>
      </rollingPolicy>   
   </appender>
   
   <logger name="com" level="DEBUG" additivity="false">
      <appender-ref ref="STDOUT" />
   </logger>
   
   <logger name="org.springframework.boot.autoconfigure" level="WARN">
      <appender-ref ref="STDOUT"/>
   </logger>
   
   <logger name="fileLogger" level="INFO" additivity="false">
      <appender-ref ref="FILE_APPENDER" />
   </logger>
   
   <root level="INFO">
      <appender-ref ref="STDOUT" />
   </root>
 
</configuration>
cs

 

 

[위와 같이 설정한 경우 Sample.class]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.sample.controller;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class Sample {
    
    protected static final Logger logger = LoggerFactory.getLogger(Sample.class);
    
    public static void main(String[] args) {
        
        logger.info("Sample.class logger print with info level");
        
        logger.error("fileLogger logger print with error level");
    }
 
}
 
cs

main 메소드를 실행시 logger.error 로 찍은 로그는 /logs/api.log 파일에 write 되어 있으며, 콘솔에선 찍히지 않는다.

 

[실행 결과 : 콘솔]

INFO : com.sample.controller.Sample - Sample.class logger print with info level

[실행 결과 : /logs/api.log 파일]

ERROR : fileLogger - fileLogger logger print with error level

 

2. 특정 로거에서 출력한 로그는 파일로 저장하기

기존의 console 로그 이외에 로거를 하나 추가로 두고,

추가한 로거를 사용하여 로그를 찍는 경우, 별도의 파일로 저장하고자 하는 경우

fileLogger 를 로거로 추가하고, 파일 어팬더를 주입.

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
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%-5p: %c - %m%n" />
        </Console>
        
        <RollingFile name="logFile" fileName="/logs/api.log" filePattern="/logs/$${date:yyyyMM}/app_%d{yyyyMMdd}-%i.log.gz">
            <PatternLayout pattern="%-5p: %c - %m%n" />
            <Policies>
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="100MB"/>
            </Policies>
        </RollingFile>
    </Appenders>
    
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="console" />
        </Root>
        
        <Logger name="fileLogger" level="INFO" additivity="false">
             <AppenderRef ref="logFile" />
        </Logger>
    </Loggers>
    
</Configuration>
 
cs

 

Sample.class는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.sample.controller;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class Sample {
    
    protected static final Logger logger = LoggerFactory.getLogger(Sample.class);
    protected static final Logger fileLogger = LoggerFactory.getLogger("fileLogger");
 
    public static void main(String[] args) {
        
        logger.info("Sample.class logger print with info level");
        
        fileLogger.info("fileLogger logger print with info level");
    }
 
}
 
cs

 

[실행결과 : 콘솔]

INFO : com.sample.controller.Sample - Sample.class logger print with info level

[실행결과 : /logs/api.log]

INFO : fileLogger - fileLogger logger print with info level

 

참고:

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

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

 

반응형

스프링프레임워크 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