상세 컨텐츠

본문 제목

Logging libraries - Facade

프로그래밍/JAVA

by 라제폰 2014. 5. 22. 13:59

본문

 프로그램 개발을 할때 가장 중요한 부분이 로그(log) 처리부분이 아닐까 생각한다. 신규 개발은 물론 유지/보수 할때에도 로깅을 얼마나 체계적으로 잘 사용하느냐에 따라서 작업하기가 한결 수월해질 수 있다.
 자바에서는 1.4부터 java.util.logging 패키지가 포함되어 자체적으로 지원을 하고 있지만, 뒤늦게 출현한 덕분인지, 아니면 모양새가 맘에 안들어서 그런지 잘 사용이 안되고 있다. 아마 대부분 log4j를 사용하고 있는것으로 알고 있다.(아닐수도 있다~)
 그런데 재미있는것은 이 로깅 라이브러리를 facade 하는 라이브러리도 존재한다는것이다. 간단히 말해서 기존 로깅 라이브러리를 wrapping해서 사용한다고 할 수 있는데, 로깅 요청을 기존에 존재하는 로깅 라이브러리(log4j같은)로 전달하는 역할만을 한다는것이다. logging의 특성상 프로그램 전체에 걸쳐 얇고 넓게 퍼져있기때문에 바꾸기 쉽지가 않는데, 이 facade 라이브러리를 사용하면 로깅 라이브러리를 손쉽게(?) 바꿀수 있다는 뜻이다.
 JCL(http://commons.apache.org/logging/)과 SLF4J(http://www.slf4j.org/)이 대표적인 Logging Facade 라이브러리이다. 



1. Logging Facade Libraries 

1.1. JCL(Apache Common Logging)
 - Common Logging, 즉 JCL은 로깅 요청을 기존에 존재하는 다양한 logging API implementations에 전달하는 역할을 한다. 즉, 로깅 요청이 왔을때, log4j나, jdk14Logger 등, 다른 로깅 라이브러리로 전달하여, 해당 라이브러리를 이용해서 log를 출력할 수 있게 해 주는 것이다. 이 JCL을 사용할 경우, 전달받는 logging API 구현체를 마음데로 바꿀 수 있어서,  어떠한 logging API implementations를 사용하던지에 상관없이 동일한 방법을로 개발을 할 수 있다는 것이다.
 - org.apache.commons.logging.Log, org.apache.commons.logging.LogFactory 두 클래스를 이용해서 사용할 수 있다.
 - Log는 로그를 출력하기 위한 인터페이스이고, LogFactory는 사용할 로깅 API 구현체를 Wrapping한 Log를 생성해주는 역할을 한다.
 - LogFactory는 다음과 같은 순서로 Log 구현체를 사용하게 된다.
  1. classpath에서 commons-logging.properties 파일을 찾아 존재한다면, 그 파일에 설정한 정보데로 로그 구현체를 선택한다.
  2. system property 에 org.apache.commons.logging.Log 이름으로 설정한 property가 있다면 그 이름을 사용한다.
  3. 어플레이션 클래스패스에 log4j 로깅 시스템을 이용할 수 있다면, lo4j구현체를 사용한다.
  4. 어플케이션이 JDK 1.4 시스템 위에서 동작하고 있다면 jdk14Logger를 사용한다.
  5. 기본 Wrapper인 SimpleLog를 사용한다.

 - 사용 예제

01import org.apache.commons.logging.Log;
02import org.apache.commons.logging.LogFactory;
03 
04 
05public class Hello {
06 
07    private Log log = LogFactory.getLog(Hello.class);
08     
09    public void testLog() {
10        String message = "안녕하세요.";
11        Throwable t = new Exception("에러입니다.");
12         
13        log.fatal(message);
14        log.fatal(message, t);
15        log.error(message);
16        log.error(message, t);
17        log.warn(message);
18        log.warn(message, t);
19        log.info(message);
20        log.info(message, t);
21         
22        if (log.isDebugEnabled()) {
23            log.debug(message);
24            log.debug(message, t);         
25        }
26         
27        if (log.isTraceEnabled()) {
28            log.trace(message);
29            log.trace(message, t);         
30        }
31 
32    }
33     
34    public static void main(String[] args) {
35        Hello hello = new Hello();
36        hello.testLog();
37    }
38}

사용법은 log4j와 비슷하다. 그리고 기존에 log4j를 사용하고 있다면 간단히 commons-logging.jar 파일만 복사해주면 잘(?) 작동한다.

 Commons Logging 로그레벨 Log4J의 로그레벨  자바 1.4의 로그 레벨
 TRACE TRACE FINEST
 DEBUG DEBUG FINE
 INFO INFO INFO
 WARN WARN WARNING
 ERROR ERROR SEVERE
 FATAL FATAL SEVERE


참고 : http://commons.apache.org/logging/commons-logging-1.1.1/guide.html



1.2. SLF4J(Simple Logging Facade for Java)
 - JCL처럼 다른 로깅 API 구현체에 로깅 요청을 전달하는 역할을 한다. 다중 클래스로더(ClassLoader)를 사용하는 환경에서 발생할 수도 있는 JCL의 문제점을 해결하기 위해 등장했다. (SLF4J는 로깅 API 구현체와의 맵핑(mapping)이 static하게 이루어진다. 그래서 SLF4j 라이브러리를 최상위(?) 클래스패스(classpath)에 넣어줄 필요가 있다. JCL은 dynamic하게 맵핑이되므로서 다중 클래스로더를 사용할때 문제가 발생하기도 한다.)
 - 로그 출력시 포맷팅(?) 기능을 지원한다. 
   예를들어 JCL일 경우
1 log.debug(name + "님 안녕하세요");
 이런식으로 출력할 경우 디버그(debug) 출력을 하지 않더라도, name 변수와 "님 안녕하세요" 상수의 연산을 하기 위해 자원이 소모된다. 이걸 방지하기 위해서
1 if (log.isDebugEnabled()) {
2  log.debug(name + "님 안녕하세요");
3 }
 log.isDebugEnabled() 메소드를 이용해서 한번 검사를 한다음 실행하게 하는데, 이것도 상당히 번거롭다.
 SLF4J는 포맷팅을 지원해서 한결 간단하게 만들수 있다.
1  logger.deubg("{}님 안녕하세요", name);
 "{}"을 이용해서 변수들을 바인딩할 수 있는것이다.

- 로깅 API 구현체를 찾는 순서는 멋진 그림이 있으므로, 무단 도용하겠다.
 - Java 1.5 이상에서 SLF4J와 log4j를 이용하기 위해서는 slf4j-api-xxx.jar와 slf4j-log4j12-xxx.jar만 있으면 된다. slf4j-api-xxx.jar은 기본 라이브러리이고, slf4j-log4j12-xxx.jar은 log4j를 랩핑한 구현체의 모음이다. 친절하게도(?) 각 로깅 API 구현체별로 라이브러리를 분리해놓으셨다. (JCL에서 SLF4J로 마이그레이션(migration)을 하기 위한 jcl-over-slf4j.jar, slf4j-jcl.jar도 존재한다.)
- 사용 예제
01import org.slf4j.Logger;
02import org.slf4j.LoggerFactory;
03 
04 
05public class Hello {
06 
07    private Logger logger = LoggerFactory.getLogger(Hello.class);
08     
09    public void testLog() {
10        String message = "안녕하세요.";
11        Throwable t = new Exception("에러입니다.");
12 
13        logger.error(message);
14        logger.error(message, t);
15        logger.warn(message);
16        logger.warn(message, t);
17        logger.info(message);
18        logger.info(message, t);
19         
20        if (logger.isDebugEnabled()) {
21            logger.debug(message);
22            logger.debug(message, t);
23            // 포맷팅 개념 지원
24            logger.debug("{}님  안녕하세요." + message, "강우");
25        }
26         
27        if (logger.isTraceEnabled()) {
28            logger.trace(message);
29            logger.trace(message, t);          
30        }
31 
32    }
33     
34    public static void main(String[] args) {
35        Hello hello = new Hello();
36        hello.testLog();
37    }
38}

참고 : http://www.slf4j.org/manual.html

1.3. JCL vs SLF4J
 - 둘중 어느것을 사용하는것은 사용자의 맘이다. 필자의 경우는 SLF4J를 사용하는데, 그 이유는 이름이 멋져보여서이다. --;


Posted by 랑우 剛宇


관련글 더보기