8.1 Log4J

작성자 : 진은영 ( 2004-07-29)

[메인] [목록]

목차

8.1.1 Log4J

① Log4J란
프로그램을 개발하는 사람이라면 누구나 로그(log)를 남기게 마련이다. 어떠한 형태로던지 로그를 남겨서 자신이 작성한 프로그램이 정상적으로 작동하는지, 혹은 실행 도중에 문제가 생겼을 때에도 로그를 참고해서 어느 부분에 문제가 있는지 찾아보곤 한다.

개발자가 아닌 시스템을 관리하는 경우에도 로그는 매우 중요하다. 보안 담당자의 경우 누가 시스템에 불법적(?)으로 접근하는지 못된 짓(?)을 하는지 감시할 때에도 로그가 중요한 역할을 한다. 이렇게 다양한 사람들과 용도로 사용하는 로그를 여러분은 어떻게 생성하고 관리하고 있을까? System.out.println 을 사용할 수 있다. 단순한 로그라면 상관 없겠지만 로그의 형태도 다양하고 여러 조건이 주어져야 한다면 이런 단순한 방법을 사용해서는 원하는 목표를 달성하기 힘들 것이다.

로그를 남기는 방법에 좀 더 편하고 다양한 기능과 성능까지 보장하는 방법이 있다면? 그렇다. 바로 log4j 를 사용하는 것이다. Log4j는 이런 시대의 다양한 욕구를 충족시키기 위해 등장한 것이다. 이미 log4j 프로젝트가 시작 된지 몇 년이 지났고 그 동안 충분히 검증되었으며 업계에서도 표준처럼 굳어져 있어서 많은 상용 제품에도 포함되어 있다. JDK 1.4 버전부터는 일부 로깅 API가 추가되었지만 log4j 처럼 막강하지는 않는 듯 하다.

② Log4J API의 기능
Log4j 는 기본적으로 다섯개의 우선권(이하 Priority) 등급으로 메세지를 로깅할 수 있다.

  • 완성된 어플리케이션에서는 출력되지 않아야 할 디버깅 메세지들을 쓰기위해 debug 를 사용하라.
  • 어플리케이션의 verbose 모드에서 출력될만한 메세지들을 로깅하기 위해 info 를 사용하라.
  • 어플리케이션이 이상없이 계속 실행될 수 있는 정도의 경고메세지를 로깅하기 위해 warn 을 사용하라.
  • 어플리케이션이 그럭저럭 돌아갈만한 정도의 에러메세지를 로깅하기 위해 error 를 사용하라.
    예를들어 관리자에 의해 주어진 설정인자가 올바르지 않아 하드코딩된 기본값을 사용해야 할 경우.
  • 로깅후에 애플리케이션이 비정상적으로 종료될 치명적인 메세지를 로깅하기 위해 fatal 을 사용하라.

프로그래머 수준에서 DEBUG 레벨이 필요하다면 운영자 수준에서는 INFO레벨이 필요하다.


8.1.2 Log4J 설치

아래의 위치에서 파일을 다운로드 받는다.
위치 : http://logging.apache.org/site/binindex.cgi 파일 : jakarta-log4j-1.2.8.zip

원하는 장소에 압축을 풀면 아래와 같은 폴더가 나타난다.

Log4J를 사용하기 위해서는, 클래스 패스에 log4j-1.2.8을 포함해야 한다. 아래의 내용을 확인하면 추가하는 방법을 알 수 있다.



8.1.3 Log4J 사용

① 간단한 예제
역시나 처음 프로그램을 시작할 때 빠지지 않는 단골인 Hello 프로그램으로 시작하자.
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;

public class SimpleLog {

  // Logger 클래스의 인스턴스를 받아온다.
  static Logger logger = Logger.getLogger(SimpleLog.class);

  public SimpleLog() {}

  public static void main(String[] args) {

	/* 
    콘솔로 로그 출력 위한 간단한 설정,
    이 설정이 없다면 경고 메세지가 출력되면서 실행이 중단된다.
    */
    BasicConfigurator.configure();

      logger.debug("Hello log4j.");
      logger.info("Hello log4j.");
      logger.warn("Hello log4j.");
      logger.error("Hello log4j.");
      logger.fatal("Hello log4j.");
      //loger.log( Level.DEBUG , "debug") 와 동일하다.
  }
}
실행
---------- java ----------
0 [main] DEBUG SimpleLog - Hello log4j.
10 [main] INFO SimpleLog - Hello log4j.
10 [main] WARN SimpleLog - Hello log4j.
10 [main] ERROR SimpleLog - Hello log4j.
10 [main] FATAL SimpleLog - Hello log4j.
출력 완료 (1초 경과) - 정상 종료

맨 앞에 등장하는 숫자는 로깅 호출로부터 얼마만큼의 시간이 지났는지를 밀리세컨드 단위로 보여준다. 이 정보는 별로 유용할 것 같지는 않다. 다음에 보이는 [main] 은 호출한 쓰레드의 이름을 나타낸다. 다음에 나타나는 DEBUG , INFO , WARN 등은 로그 레벨이다. 소스 코드에서 지정한 레벨을 그대로 출력해주고 있다. 그 뒤에 나오는 것은 보시다시피 클래스의 이름과 실제 로그 메시지를 보여준다. 특별히 유용한 예제는 아니지만 사용하는 방법에 따라 System.out.println 보다는 그럴 듯 해 보인다. 예제에는 포함되어 있지 않지만 로그를 출력할지를 결정하는 플래그 값을 사용하거나 레벨로 제한을 하도록 수정하면 금상첨화일 것이다.


② Log4J의 컴포넌트
Log4J는 아래와 같이 중요한 컴포넌트가 있다.

  • logger : 로그의 주체이다. 애플리케이션을 작성할 때 로깅을 시작하기 전에 어떤 로거를 사용할지를 결정하다.
    static Logger logger = Logger.getLogger(SimpleLog.class);

  • appender : 로그를 출력하는 위치이다. 콘솔에 출력할 수 있으며, 텍스트 파일에 기록할 수도 있다.
  • layout : 로그를 출력하기 위한 레이아웃이다. 일자,시간,클래스명등 여러가지를 지정할 수 있다.


③ Appender
Log4J API문서를 보면 기본적으로 XXXAppender로 끝나는 클래스들 있다. 어펜더는 클래스 이름만으로 사용 용도를 집작할 수 있을만한 것이 많다. 여기에서는 몇몇개만 다뤄보자.
어펜더의 출력포맷을 결정하는 레이아웃은 DateLayout, HTMLLayout, PatternLayout, SimpleLayout, XMLLayout 의 5개가 있다. 일반적으로 PatternLayout을 사용하는 것이 디버깅에는 가장 적합하다.
자세한 패턴은 아래의 클래스를 살펴본다.

import java.io.IOException;

import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

public class DailyLog {
  
  static Logger logger = Logger.getLogger(DailyLog.class);
  
  public static void main(String[] args) {
    String pattern = "[%d{yyyy-MM-dd HH:mm:ss}] %-5p [%l] - %m%n";
    PatternLayout layout = new PatternLayout(pattern);
    
    // 처음 생성될 로그 파일의 이름
    String filename = "DailyLog.log";
    
    // 날짜 패턴에 따라 추가될 파일 이름
    String datePattern = ".yyyy-MM-dd";
    
    DailyRollingFileAppender appender = null;
    try {
      appender = new DailyRollingFileAppender(layout, filename, datePattern);
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
    
    logger.addAppender(appender);
    
    logger.debug("Hello log4j.");
  }
}
실행
---------- java ----------
출력 완료 (1초 경과) - 정상 종료

DailyLog.log 파일을 열어보면 아래와 같은 내용이 추가된것을 알 수 있다.
[2004-07-29 17:36:05] DEBUG [DailyLog.main(DailyLog.java:30)] - Hello log4j.

파일의 내용은 소스 코드에서 정의된 패턴인 "[%d{yyyy-MM-dd HH:mm:ss}] %-5p [%l] - %m%n" 에 따라 생성된 것이다. 출력된 것과 대조해보면 대충 어떤 의미인지 유추가 가능하다. 첫번째 내용은 날짜를 나타낸다. 날짜를 나타내는 형태도 SimpleDateFormat 을 사용하는 것처럼 원하는 형태로 가능하다. 다음에 보이는 것은 로그 레벨이며 다음에 보이는 것은 [패키지 이름.클래스 이름.메소드 이름(소스 파일 이름:소스 라인 넘버)] 이다. 그리고 마지막으로 실제 로그 내용을 보여준다. 출력 패턴은 이외에도 많은 것들이 있는데 자세한 사항은 log4j API 문서를 참고하도록 하자.


④ properties 파일 이용하기
애플리케이션에서 각 클래스는 각각의 로거를 가지거나 공통의 로거를 가질 수 있다. Log4j는 모든 로거가 상속할 수 있는 루트 로거를 제공한다. log4j.properties를 만들때도 맨 위에 필요한 것이 루트로거에 대한 내용이다.

#log4j.rootLogger=DEBUG, A1
log4j.rootLogger=OFF, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n

아래 문서는 log를 출력할 자바문서이다.
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class LogProperty {
  
  static Logger logger = Logger.getLogger(LogProperty.class);
  
  public static void main(String[] args) {
    logger.debug("Hello log4j.");
  }
}
실행
---------- java ----------
출력 완료 (1초 경과) - 정상 종료

화면에 출력되는 로그는 없다. 아래와 같이 변경한 후 다시 LogProperty를 실행한다.
log4j.rootLogger=DEBUG, A1
#log4j.rootLogger=OFF, A1

아래와 같이 결과가 나타날 것이다.
---------- java ----------
[2004-07-29 18:10:33] - Hello log4j.
출력 완료 (3초 경과) - 정상 종료


또 다른 예를 들어보자. log4j.properties 를 아래와 같이 수정한다.
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=test.log
log4j.appender.A1.DatePattern='.'yyyy-mm-dd
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] %-5p [%l] - %m%n

LogProperty.java 문서를 다시 실행하면 같은 폴더에 test.log 파일이 생성된다. test.log파일을 열어본다.
[2004-07-29 18:17:35] DEBUG [LogProperty.main(LogProperty.java:16)] - Hello log4j.
참고문헌