normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

log4jの設定ファイル読み込み方法

Javaで開発してるとlog4jの恩恵を受ける日々を送っています。log4j.xmlをクラスパス上に配置すると勝手に読み込んでくれるので、その部分の機能を確認してみようと。
まずは結論から入り、その後にソースコードの解析を。

設定ファイル読み込み 優先順位(結論)

  • 設定ファイル読み込みロジック
    1. log4j.jarがクラスローダに読み込まれた直後、staticフィールドに含まれたlog4jの設定ファイル読み込みロジックを処理される。
    2. 「読み込む設定ファイルの優先順位」に従って設定ファイルが存在するパスを検索し、最初に設定ファイルが見つかったパスのjava.net.URLオブジェクトを生成する。
    3. 生成したURLオブジェクトのファイルをstaticフィールドの最後で有効化している。
  • 読み込む設定ファイルの優先順位
    1. log4j.xml を Thread.currentThread().getContextClassLoader().getResource的に読み込む
    2. log4j.configuration を Thread.currentThread().getContextClassLoader().getResource的に読み込む
    3. log4j.defaultInitOverride ファイル System.getProperty を用いてパスを指定する
    4. log4j.configuratorClasse ファイル? System.getProperty を用いてパスを指定する

解析実施

  • まずはソースファイルのDL

http://logging.apache.org/
上記、オフィシャルサイトに行って log4j のソースファイルを落としましょう。今回私が落としたファイルは「apache-log4j-1.2.15.zip」です。

  • 設定ファイルの読み込み箇所を探す

どうせ決めうちだろうと妄想し、「log4j.xml」でソースプロジェクトを検索し、以下のコードを発見した。

package org.apache.log4j;
(中略)
public class LogManager {
(中略)
  static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";  
  static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";     
  static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";
  static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";
  public static final String DEFAULT_INIT_OVERRIDE_KEY = "log4j.defaultInitOverride";

上記の変数「DEFAULT_XML_CONFIGURATION_FILE」を使用している部分をさらに検索する。
設定ファイルの読み込み部分は、「org.apache.log4j.LogManager」クラスのstaticフィールドを利用していた。

 static {
    String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,null);
    if(override == null || "false".equalsIgnoreCase(override)) {
      String configurationOptionStr = OptionConverter.getSystemProperty(DEFAULT_CONFIGURATION_KEY, null);
      String configuratorClassName = OptionConverter.getSystemProperty(CONFIGURATOR_CLASS_KEY, null);

      URL url = null;
      if(configurationOptionStr == null) {	
	url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
	if(url == null) {
	  url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
	}
      }else{
        try {
          url = new URL(configurationOptionStr);
        } catch (MalformedURLException ex) {
          url = Loader.getResource(configurationOptionStr);
        }
      }
(中略)
 }

上記ソースコードを確認すると、クラスパス上 or システムプロパティ引数からのパスを指定してから log4j設定ファイルのパスを読み込んでいる。設定ファイルのパスを取得するため、それぞれ「Loader」、「OptionConverter」クラスを使用している。これら2クラスのコードで気になる部分だけ抜粋してみる。

 //Thread.currentThread().getContextClassLoader().getResourceをしてるだけ
 static public URL getResource(String resource) {
  ClassLoader classLoader = null;
  URL url = null;    
  try {
   if(!java1) {
    classLoader = getTCL();
    if(classLoader != null) {
     url = classLoader.getResource(resource);      
 (中略)
  }
  private static ClassLoader getTCL() throws IllegalAccessException, 
    InvocationTargetException {
    Method method = null;
    try {
      method = Thread.class.getMethod("getContextClassLoader", null);
    } catch (NoSuchMethodException e) {
      return null;
    }    
    return (ClassLoader) method.invoke(Thread.currentThread(), null);
  }
(中略)
 //どう見てもSystem.getPropertyにデリゲートしてるだけ。
  String getSystemProperty(String key, String def) {
    try {
      return System.getProperty(key, def);
(中略)