오늘은 어디로 갈까...

Logging libraries : log4j 3부 본문

낙서

Logging libraries : log4j 3부

剛宇 2009. 3. 23. 11:55

 오늘은 log4j의 Filter 기능과 설정파일 직접(?) 지정하기에 대해서 알아보겠다.

 필터(Filter)기능이란 로그 이벤트가 합당한 조건에 일치하는가를 판단하는 기능이다. Appender에 Filter를 설정해서 사용할 수 있다. 자세한 사항은 이전에 끄적였던 글(http://blog.kangwoo.kr/40)로 대체한다. ^^;

log4j는 기본적으로 클래스패스(classpath)에서 log4j.xml나 log4j.properties 파일을 찾아서 설정 정보를 읽어온다.  이 설정정보 파일을 명시적으로 지정하려면 어떻게 해야할까?
모르겠다. 삽을 들자. --;

일반적으로 Logger.getLogger(String) 메소드를 이용해서 로거를 할당 받는다.

public class Logger extends Category {

    public static Logger getLogger(String name) {
        return LogManager.getLogger(name);
    }
}

이 Logger.getLogger(String)메소드는 LogManager로 부터 Logger를 받게 된다.
public class LogManager {
    static {
        Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));
        repositorySelector = new DefaultRepositorySelector(h);
        String override = OptionConverter.getSystemProperty("log4j.defaultInitOverride", null);
        if(override == null || "false".equalsIgnoreCase(override))  {
            String configurationOptionStr = OptionConverter.getSystemProperty("log4j.configuration", null);
            String configuratorClassName = OptionConverter.getSystemProperty("log4j.configuratorClass", null);
            URL url = null;
            if(configurationOptionStr == null) {
                url = Loader.getResource("log4j.xml");
                if(url == null)
                    url = Loader.getResource("log4j.properties");
            } else {
                try {
                    url = new URL(configurationOptionStr);
                } catch(MalformedURLException ex) {
                    url = Loader.getResource(configurationOptionStr);
                }
            }
            if(url != null) {
                LogLog.debug("Using URL [" + url + "] for automatic log4j configuration.");
                try {
                    OptionConverter.selectAndConfigure(url, configuratorClassName, getLoggerRepository());
                } catch(NoClassDefFoundError e) {
                    LogLog.warn("Error during default initialization", e);
                }
            } else {
                LogLog.debug("Could not find resource: [" + configurationOptionStr + "].");
            }
        }
    }

    public static Logger getLogger(String name) {
        return getLoggerRepository().getLogger(name);
    }
}

LogManager 클래스를 살펴보자. 어려운 부분(?)은 생략하고, 7번째 줄을 보면 System Property에서 log4j.configuration 값을 읽어오는것을 알 수있다.(log4j.configuratorClass을 사용해서 Configurator 클래스를 지정할 수있는것도 알 수 있다.)
이 설정한 값이 없을 경우, 앞에서 설명한것처럼 "log4j.xml", "log4j.properties" 파일을 찾는것을 알 수 있다.
그리고 24번째 줄에서 OptionConverter.selectAndConfigure(URL, String, LoggerRepository) 메소드를 이용해서 해당 설정 파일을 초기화 하는 것을 알 수 있다.
public class OptionConverter {
    public static void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
        Configurator configurator = null;
        String filename = url.getFile();
        if(clazz == null && filename != null && filename.endsWith(".xml"))
            clazz = "org.apache.log4j.xml.DOMConfigurator";
        if(clazz != null) {
            LogLog.debug("Preferred configurator class: " + clazz);
            configurator = (Configurator)instantiateByClassName(clazz, org.apache.log4j.spi.Configurator.class, null);
            if(configurator == null) {
                LogLog.error("Could not instantiate configurator [" + clazz + "].");
                return;
            }
        } else {
            configurator = new PropertyConfigurator();
        }
        configurator.doConfigure(url, hierarchy);
    } 
}

OptionConverter.selectAndConfigure(URL, String, LoggerRepository) 메소드를 살펴보면, Configurator 클래스를 지정하면, 지정한놈을 사용하고, 지정한게 없다면 파일확장자자 xml이면 DOMConfigurator을 아니면 PropertyConfigurator을 사용하는것을 알 수 있다.


간단하게 정리하자면 두가지 방법으로 설정 파일을 지정해줄 수 있는것이다.

첫번째는, System Property에 log4j.configuration 을 설정해주는것이다.
즉, 아래처럼 프로그램을 실행시킬때 -D옵션에 log4j.configuration=/app/log4j.xml 을 추가해주면 된다.
java -Dlog4j.configuration=/app/log4j.xml com.kangwoo.app.MyApp

두번째는, PropertyConfigurator, DOMConfigurator 두 클래스를 이용하면 된다. 클래스 이름에서 알 수 있듯이, log4j.properties파일을 지정할 경우는 PropertyConfigurator 클래스를, log4j.xml파일을 지정할 경우는 DOMConfigurator 클래스를 사용하면 된다.
(뭐, 심심하다면 org.apache.log4j.spi.Configurator 인터페이스를 구현해 나만의 구성자(Configurator)를 만들 수도 있다.)
// log4j.properties
PropertyConfigurator.configure("/app/log4j.properties");
// log4j.xml
DOMConfigurator.configure("/app/log4j.xml");

이 Configurator에는 유용한 메소드가 하나 더 있다. 바로 configureAndWatch(String, long) 이다. 지정한 주기(delay)마다, log4j 설정 파일이 변경되었는지를 판단하여 자동으로 갱신(reload)해준다.
    public static void configureAndWatch(String configFilename) {
        configureAndWatch(configFilename, 60000L);
    }
    public static void configureAndWatch(String configFilename, long delay) {
        // 생략
    }

즉, 아래처럼 설정파일을 지정해주면 자동적으로 1분에 한번씩 변경 여부를 검사하여 반영한다는 것이다.

        DOMConfigurator.configureAndWatch("/app/log4j.xml, 60000L);

이상으로 log4j에 대해서 간단하게 알아봤다. 현재 log4j 안정화버젼은 1.2.x 버전이다. 1.3 버전대는 2.0 버전개발로 인해서 개발이 중지된 상태인거 같다. 2.0버전도 소식이 없구.. 하루 빨리 나왔으면 좋겠다. 아마 2.0이 나오면 JDK 1.5 부터 지원되는 포맷팅 메소드 printf(String formmat, Object... args)가 지원되지 않을까?
    double pi = Math.PI;
    System.out.printf ("pi = %5.3f%n", pi);

* 출력 결과
pi = 3.142


믿거나~ 말거나~~~~