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

반응형

jboss/wildfly 는 설치시 bin 디렉토리 밑에

서버 시작 스크립트(standalone.sh)가 존재하나, 서버 종료 스크립트가 없다.

 

jboss home directory/bin/standalone.sh 로 서버 실행 후 ctrl+c 로 서버 종료가 가능하나,

특별한 경우가 아니라면 standalone.sh & 와 같은 옵션을 주어 백그라운드에서 서버를 실행시킨다.

이 경우, 서버를 어떻게 죽여야 할까?

 

[1. 프로세스 죽이기]

ps -ef | grep wildfly 

로 프로세스 찾은 후

 

kill -9 프로세스No.

와 같이 서버를 죽일 수 있다..

하지만 뭔가 찜찜하니 매뉴얼을 읽어본다.

 

[2. jboss/wildfly 매뉴얼 따라하기]

jboss/wildfly 매뉴얼에 따르면

 

The first thing to do after the CLI has started is to connect to a managed WildFly instance. This is done using the command connect, e.g.

./bin/jboss-cli.sh
You are disconnected at the moment. Type 'connect' to connect to the server
or 'help' for the list of supported commands.
[disconnected /]
 
[disconnected /] connect
[domain@localhost:9990 /]
 
[domain@localhost:9990 /] quit
Closed connection to localhost:9990

localhost:9990

 is the default host and port combination for the WildFly CLI client.

The host and the port of the server can be provided as an optional parameter, if the server is not listening on localhost:9990.

./bin/jboss-cli.sh
You are disconnected at the moment. Type 'connect' to connect to the server
[disconnected /] connect 192.168.0.10:9990
Connected to standalone controller at 192.168.0.1:9990

The :9990 is not required as the CLI will use port 9990 by default. The port needs to be provided if the server is listening on some other port.

 To terminate the session type quit.

 

The jboss-cli script accepts a --connect parameter: ./jboss-cli.sh --connect

The --controller parameter can be used to specify the host and port of the server: ./jboss-cli.sh --connect --controller=192.168.0.1:9990

Help is also available:

[domain@localhost:9990 /] help --commands
Commands available in the current context:
batch               connection-factory  deployment-overlay  if                  patch               reload              try
cd                  connection-info     echo                jdbc-driver-info    pwd                 rollout-plan        undeploy
clear               data-source         echo-dmr            jms-queue           quit                run-batch           unset
command             deploy              help                jms-topic           read-attribute      set                 version
connect             deployment-info     history             ls                  read-operation      shutdown            xa-data-source
To read a description of a specific command execute 'command_name --help'.

해석&정리하자면 

 

1. jboss-cli.sh 스크립트 실행

> jboss home directory/bin/jboss-cli.sh 실행

 

2. 관리자 접속

기본 아이피:포트 사용하고 있는 경우

> connect

 

connect 시 기본 아이피:포트 를 사용하지 않는 경우 

> connect 할당한 아이피:포트 

 

* 여기서 아이피와 포트는 관리자 포트와 아이피를 적어주어야 한다. 

(jboss home dir/standalone/configuration/standalone.xml 파일의 제일 밑에 쪽에 위치한 management-http 참고. (vi 모드에서 파일 끝으로 이동은 :$ (깨알팁))

<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9992}"/>  )

(domain으로 관리하고 있을 경우 domain.xml 을 참고하면 될 것같고, https 사용하는 경우 management-https 에 할당된 아이피 및 포트를 확인하면 될 것 같다)

3. shutdown 명령어로 서버 죽이기.

 

> ./jboss-cli.sh --connect --controller=localhost:port shutdown 와 같이 한 줄로 서버를 죽일 수도 있다.

매번 쓰기 힘드니 stop.sh 이름으로 쉘스크립트를 작성하여 사용하면 편하다..

 

 

[ stop.sh 작성 ]

#!/bin/bash
./jboss-cli.sh --connect --controller=localhost:port shutdown

 

반응형

+ Recent posts