Java Logger 역사

# log4j slf4j logback log4j 뭘 써야 하지?

이 소스 저 소스 보다 보면 여러 로그 라이브러리를 보게 된다. 어떤 것이 제일 좋을까? maven이나 gradle에 로그 라이브러리를 추가할때 왜 여러 로그를 설정하는 걸까? 그 놈이 그 놈아닌가? 이 참에 정리해 보자.

# Legacy Logging Libraries

# java.util.logging(JUL)

  • 언어차원에서 지원하는 로거
  • java 1.4버전(2002년) 부터 지원
java.util.logging.Logger logger =  java.util.logging.Logger.getLogger(this.getClass().getName());
logger.info("This is an info message");
logger.severe("This is an error message"); // ERROR
logger.fine("Here is a debug message"); // DEBUG
1
2
3
4
  • server와 find은 생소해 보이지만 지금의 error, debug에 해당한다.
  • File과 Console Handler를 지원.
    • File은 직접 핸들링, Console은 System.err사용
FileHandler fileHandler = new FileHandler("status.log");
logger.addHandler(fileHandler);
1
2
  • 일관성 문제, 느린 성능, 부족하지만 복잡한 설정, 구린 문서화로 불만 (opens new window)이 많았다.

# Log4j

  • 오랜 시간 사랑받아온 기념비적인 로거
  • 최초 만든 사람은 Ceki Gülcü (opens new window)
  • 2001년부터 시작해서 2015년까지 아파치 재단 하에 유지 보수 되었다.
org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(MyClass.getClass().getName());
logger.info("This is an info message");
logger.error("This is an error message");
logger.debug("Here is a debug message");
1
2
3
4
바로 이 분!
세키님

# Apache Commons Logging (JCL)

  • 비슷한 시기 2002년 태어난 로거
  • Jakarta Commons Logging(JCL)이라고도 불린다.
  • 구현없는 오직 인터페이스 덩어리. 따라서 구현체 필요
org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(MyApp.class);
log.info("This is an info message");
log.error("This is an error message");
log.debug("Here is a debug message");
1
2
3
4
  • 기냥 바로 log4j쓰면 안되나? 왜 필요할까?
    • 다른 사용자를 위한 라이브러리를 작성한다고 가정해보자. 나는 log4j를 사용했는데, 다른 사용자는 다른 로거를 사용중에 있다면 충돌이 일어날 것이다. 인터페이스로만 참고하면 사용자마다 다른 구현체를 사용해도 문제없다.
    • 레거시 코드를 유지보수할때 로거 변경이 힘들 경우, 인터페이스 로거로 브릿지해서 종속성을 끊는다.
  • 문제점
    • runtime에 로거 구현체가 로딩되는데, 구현체를 찾는 과정에서 classloader와 의존문제가 발생(자세한건 세키가 직접 작성한 여기 (opens new window)서 확인)

# Modern Logging Libraries

# SLF4J & Logback

  • log4j를 만든 세키가 뛰쳐나와 자체적으로 새로운 로깅 프로젝트를 착수한다. 대략 2005년쯤 인듯

  • 이름하야 Logback

  • QOS.sh (opens new window)에서 유지 보수

  • 더 강려크한 성능, 더 다양한 기능, test에 친화적, 문서 보강, 자동 설정, 우아한 오류처리등(자세한건 여기 (opens new window))

  • 동시에 JCL 같은 Facade(혹은 Bridge) 인터페이스 덩어리 SLF4j 도 개발

    • 따라서 구현체 필요
    • logger.isDebugEnabled 사용할 필요가 없음
    • 컴파일 시점에 구현체 로거 선택됨
  • 한 프로젝트에 여러 모듈이 다른 로거 사용 혹은 3rd파티 라이브러리들이 각각 다른 로거를 사용해도, 하나의 추상 로거 레이어로 감쌀 수 있다. xxx-over-slf4j로 끝나는 라이브러리가 이 용도(기존 로거는 exclude 해야함)

  • 따라서 실제 자주 보게 되는 로거 구조는

    • SLF4J
    • 구현체(Logback, Log4j등)
    • 한 프로젝트에 여러 로거를 통일 한다면 xxx-over-slf4j(log4j-over-slf4j, jul-to-slf4j등)

    # Log4j2

    • Log4j의 공식 후속작. 2014년 릴리즈
    • 완전 새로 쓰여짐
    • 인터페이스 api와 실 구현체 core로 구성
// Bridge api
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.2</version>
</dependency>

// 구현체 core
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
  • core는 slf4j와도 같이 쓸 수 있다.
  • slf4j보다 개선된 점
    • 비동기 로깅
    • 람다식 가능
    • 향상된 가비지 컬렉션
    • String외 타입 지원
    • 자세한 사항은 여기 (opens new window)참조
  • 사실 일반적인 어플리케이션에서는 성능 향상 체감이 어렵다. 아주 복잡하고 큰 어플리케이션에서는 약간의 성능향상이 있다고 함

# Jbos Logging

  • RedHat에서 유지보수
  • Bridge 로거. 실 구현체 필요
  • 하이버네이트에서 사용(하이버네이트도 RedHat에서 관리)

# 성능 비교


출처

환경에 따라 다르겠지만, Log4j2가 logback보다 수치로는 두배정도 빠르다. 비동기 시에는 압도적으로 빠르다.

# 그래서 무엇을 쓸까

slf4j와 logback 조합이 가장 무난. 로그를 많이 남긴다 생각되면 log4j2