본문 바로가기

JAVA

Log4j 알아보기

1. Overview

로깅이란 무엇일까? 로깅이란 프로그램에서 발생한 이벤트들을 기록하는 것을 말한다. 실행중인 프로그램에서 문제가 발생하였을 때, 로그를 이용해 문제의 원인을 찾고 해결할 수 있다. 코드에 log를 심어두는 방식은 디버거를 사용할 수 없을 때, 유용하게 사용될 수 있다.

Java로 개발을 하면서 System.out.println 을 사용하여 디버깅을 해본 경험이 있을 것이다. 로깅을 할 때, System.out.println을 사용하지 않고, log4j, sfl4j, logback, log4j2와 같은 라이브러리에 구현된 logger를 사용하는 이유는 무엇일까? 바로 이들 logger가 제공해주는 기능들이 System.out.println 보다 더 유용하기 때문이다.

1996년 초 E.U. SEMPER라는 프로젝트에서 tracing API를 만드는 것을 결정하고, log4j가 탄생하게 되었다. 비록 log4j는 2015년 8월 5일을 마지막으로 더 이상 update를 진행하지 않게 되었고, 현재는 log4j2를 사용해야 한다.

log4j에서 사용할 수 있는 기능들을 알아보고, log4j2에서 변화된 점도 알아보고자 한다.

2. Log4j

2.1 Logger hierarchy

logger는Java의 package처럼 dot으로 구분되는 이름으로 계층화된다. 예를들어 logger의 이름이 "com.foo.Bar" 라면, "com.foo" 의 이름을 가진 logger가 부모 logger가 된다. 

root logger는 가장 상위 계층에 존재하는 logger이며, getLogger(name) 메소드를 이용해서는 반환되지 않는다. getRootLogger라는 메소드를 이용해 가져올 수 있다.

로거는 TRACE, DEBUG, INFO, WARN, ERROR, FATAL 6가지의 레벨을 할당할 수 있다. 만약 로거에 레벨이 할당되지 않으면 가장 가까운 조상의 레벨을 상속 받는다. 로거에 실제로 적용되는 level를 effective level이라고 한다.

현재 로거의 effective level에 따라서, log request level이 크거나 같은 경우에만 통과를 시키게 된다. 예를 들어 effective level이 INFO 인 경우 warn는 pass시키고, debug는 pass시키지 않는다.

2.2 Appenders and Layouts

다수의 목적지에 logging을 하는 것이 가능하다. 어펜더(appender)는 출력의 목적지를 말한다. 어펜더를 사용하여 콘솔이나 파일, 원격 서버에 출력하는 것이 가능하다. 로거에는 1개 이상의 어펜더를 부착하는 것이 가능하다. 

로깅 요청은 로거에 연결된 모든 어펜더에 전달이 되며, 부모 어펜더에게도 전달이 된다. additivity flag를 false로 세팅하면, 부모의 어펜더에게는 로깅 요청이 전달되지 않는다. additivity flag는 true로 초기값이 설정되어 있다.

출력의 포맷을 커스터마이즈할 수 있다.

3. Logback

logback은 log4j의 후속 library이다. logging시스템을 설계에서 얻은 10년간의 경험을 바탕으로 만들어졌다. logback은 기존에 있던 logging 시스템보다 더 빠르다.

3.1 Architecture

logback는 logback-core, logback-classic, logback-access 세가지 모듈로 구성되어있다. classic 모듈은 크게 개선된 log4j에 대응된다. logger hierarchy와 appender, layout은 log4j에 구현되어 있는 것과 동일하다.

3.2 Parameterized logging

logger.debug("My number is " + number);

위와 같은 logging 코드가 있고, logging level이 info로 설정되어서 debug는 출력되지 않는 상황이라고 가정하자. 출력되지 않는 메세지임에도 불구하고, + 연산이 실행되어 새로운 String을 만들어내게 된다. 이는 성능 저하로 이루어질 수 있기 때문에 아래와 같이 코드를 작성하면 성능을 향상시킬 수 있다.

if(logger.isDebugEnabled()) { 
    logger.debug("My number is " + number);
}

logback에서는 더 나은 대안을 제시한다. 메세지에 '{}' 를 작성하고, 파라미터로 {}에 치환될 변수를 적어주면 된다. 

logger.debug("My number is {}", number);

이렇게 작성하면 + 연산자를 이용해 출력하는 것보다 약 30배정도의 성능 향상이 된다.

3.3 Encoder

logback에서는 layout을 대체하는 encoder가 생겼다. 기존의 layout은 Event를 String으로 변환하는 역할밖에 하지 못하였지만, encoder는 event를 outputStream에 출력할 byte array로 변환하여 전달한다. layout보다 encoder가 더 큰 개념이 된다. PatternLayoutEncode에는 내부에 PatternLayout을 wraping한 구조로서 유용하게 사용되는 encoder이다.

UTF-8과 같은 charset의 경우, log4j에서는 appender에 encoding을 설정해주었지만, logback에서는 encoder에 charset을 설정할 수 있다.

 

반응형