티스토리 뷰

다소 사설이 길었다. 그럼 바로 자바 어플리케이션에서 Log4j 2를 사용하는 방법에 대해서 알아보겠다. 

Log4j를 사용하기 위한 순서는 다음과 같다.


- log4j 2.7 라이브러리를 개발할 자바 어플리케이션에 적용한다. (이 포스팅에서는 Gradle을 이용하였다.)

- log4j2.xml 을 작성한다. 

- 자바 어플리케이션을 개발한다.

- 테스트하여 제대로 로그가 남는지 확인한다.


필자의 경우 Gradle 기반으로 사용하였으며 build.gradle 정보는 다음과 같다.


<소스1> build.gradle


apply plugin: 'java'


repositories {

jcenter()

}


dependencies {

testCompile 'junit:junit:4.12'

compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.7'

compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.7'

}



build.gradle에는 앞서 포스팅한 Gradle의 디펜던시 부분에 log4j-api와 log4j-core를 추가하였다.


다음으로 로깅을 위한 설정 정보를 다음과 같이 작성하였다. 작성한 파일은 자바 프로젝트의 클래스패스가 잡혀 있는 곳이면 아무데나 위치시켜도 상관 없다. 만일 별도의 configuration 폴더에 관리하고 싶다면 해당 디렉토리를 만든 후 클래스패스에 추가해 주면 된다. 클래스패스에 파일을 저장하는 것만으로도 설정이 적용되는 이유는 Log4j가 클래스패스에서 파일 정보를 스캔하고 로깅과 관련된 파일이면 이를 바로 사용하게 되는 구조를 가지고 있기 때문이다. 이 부분에 대해서는 로깅 설정 정보를 살펴보면서 좀 더 자세히 알아보겠다.


<소스2> log4j2.xml


<?xml version="1.0" encoding="UTF-8"?>

<Configuration status="WARN">

  <Appenders>

    <Console name="Console" target="SYSTEM_OUT">

      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>

    </Console>

  </Appenders>

  <Loggers>

    <Root level="trace">

      <AppenderRef ref="Console"/>

    </Root>

  </Loggers>

</Configuration>



Log4j의 로깅 설정 부분은 매우 다양하고 많다. 여기서는 우선 Log4j2의 동작 형태를 이해하기 위해서 가장 단순한 설정 파일을 만들었다.

Log4j2의 설정 파일 구조는 크게 다음 3가지를 가지고 있다.


- Configuration : 설정의 가장 상위 root 태그이다.

- Appenders : 로그를 실제로 남기는 역할을 한다. 기본적으로 파일과 콘솔을 지원하고 있으며 여기서는 <Console> 태그를 이용해서 STDOUT으로 출력시켰다. 프로젝트에서 사용할 Appender를 기술하면 된다.

- Loggers : Appender를 조합한 묶음으로 자바 어플리케이션의 동작과 연관된다. Logger의 이름에 다라 패키지별로 로깅 방법을 달리 지정할 수 있다. 여기서는 오직 하나의 Root 로거를 가지고 있다. 프로젝트 규모가 크다면 Root 로거를 사용하지 말고 여러개로 분할 하는 것이 유리할 때가 있다.


이제 다음으로 할일은 자바 코드를 작성하는 것이다. 자바 어플리케이션에서 API를 이용하여 세부적으로 로깅 작업을 제어할 요구가 없다면 Logger와 LoggerManager 클래스 2개만 있으면 충분하다.


<소스3> Main.java


package com.pju.log4jtest;


import org.apache.logging.log4j.Logger;

import org.apache.logging.log4j.LogManager;


public class Main {

private final Logger logger = LogManager.getRootLogger();


public void doIt(String inputValue) {

logger.trace("Entering application.");

logger.info("Input Message : {}", inputValue);

logger.trace("Exiting application.");

}


public static void main(final String... args) {

Main main = new Main();

main.doIt("Hello Log4J 2");

}

}



모든 것이 작성된 다음 위의 Main.java 프로그램을 실행시키면 다음과 같은 결과가 나온다.


23:31:36.309 [main] TRACE com.pju.log4jtest.Main - Entering application.

23:31:36.315 [main] INFO  com.pju.log4jtest.Main - Input Message : Hello Log4J 2

23:31:36.315 [main] TRACE com.pju.log4jtest.Main - Exiting application.


Log4j 1.x 버전대와 거의 유사하며 다른 로깅 프레임워크와도 크게 차이가 나지 않는다. 위의 소스 코드를 보면 기존 버전을 사용하던 개발자들의 경우 몇가지 의문을 품을 것이다. 로깅의 성능 향상을 위해서 다음과 같은 코드 패턴을 추천하였기 하였었다.

if(logger.isInfoEnabled()) {
logger.info("Input Message : " + inputValue);
}

이러한 isInfoEnabled, isDebugEnabled 와 같은 명령얼 이용해서 확인을 한 이유는 로깅을 하기 위한 문자열 연산 작업이 큰 부담이 되기 때문이다. 그래서 문자열 연산을 최소화 시키기 위해서 if 문으로 체크하는 방식을 사용하였는데 소스 코드 작성시 매우 불편하고 if 에서 한번 설정 상태를 확인하고 logger API 내부에서 로깅을 남기기 전에 한번 더 체크하는 이중 체크의 문제도 존재하였다.
하지만 Log4j2에서는 다음과 같은 형태를 이용해서 if 문으로 확인하지 않더라도 문자열 연산을 최소화 하도록 구성하였다. 실제로 공개된 내부 소스 코드를 살펴보면 문자열 연산을 하기 전에 내부적으로 로깅 레벨을 체크해서 처리한다.

logger.info("Input Message : {}", inputValue);

만일 필요한 문자열이 여러 개라면 다음과 같이 작업하면 된다.

logger.info("Input Message : {}, {}, {}, {}", inputValue1, inputValue2, inputValue3, inputValue4);

이클립스 프로젝트를 포스트에 첨부하였으니 참조하면 된다.


다음 포스팅에서는 로깅 설정 기능에 대해서 좀 더 자세히 알아보겠다.


이클립스 프로젝트를 export 해서 본 포스팅에 첨부하였다.


== 참고 ==========================================================================

1. Practical 자바 유틸리티, 인사이트 장윤기 (2016) 책의 내용을 보완하기 위한 용도로 작성한 문서이다.

2. 책에 지면 관계상 넣지 않은 부분, 추가 기능 설명이 필요한 부분을 중심으로 기술하였다.

================================================================================


log4jsample.zip
0.16MB