log4jを検索して情報を集めていると、設定ファイルに「log4j.logger.xxx」となっていたり、「log4j.category.xxx」となっていたりして、どっちが正しいのか混乱したので、まとめてみました。
前提
- 検証したのは、log4j-1.2.17.jar
設定ファイルに記述は、loggerとcategoryどっちで書いても同じ。
log4j.properties
# どっちでも同じ log4j.rootLogger=INFO, A log4j.logger.xxx=INFO, B log4j.rootCategory=INFO, A log4j.category.xxx=INFO, B
org.apache.log4j.PropertyConfigrator.java (Line:102)
static final String CATEGORY_PREFIX = "log4j.category."; static final String LOGGER_PREFIX = "log4j.logger.";
org.apache.log4j.PropertyConfigrator.java (Line:654)
/** Parse non-root elements, such non-root categories and renderers. */ protected void parseCatsAndRenderers(Properties props, LoggerRepository hierarchy) { Enumeration enumeration = props.propertyNames(); while(enumeration.hasMoreElements()) { String key = (String) enumeration.nextElement(); if(key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) { String loggerName = null; if(key.startsWith(CATEGORY_PREFIX)) { loggerName = key.substring(CATEGORY_PREFIX.length()); } else if(key.startsWith(LOGGER_PREFIX)) { loggerName = key.substring(LOGGER_PREFIX.length()); } String value = OptionConverter.findAndSubst(key, props); Logger logger = hierarchy.getLogger(loggerName, loggerFactory); // loggerでもcategoryでもLoggerを生成している。
Javaの記述は、Loggerを使う。
Loggerクラスは、Categoryクラスを継承している。
/** This is the central class in the log4j package. Most logging operations, except configuration, are done through this class. @since log4j 1.2 @author Ceki Gülcü */ public class Logger extends Category {
「@since log4j 1.2」とあるので、1.1系ではCategoryクラスを利用していたと推測できます。なので、Categoryクラスで説明されているサイトは1.1系を前提に説明しているのだと思います。
CategoryクラスのgetInstance("xx")は非推奨メソッド
org.apache.log4j.Category.java (Line:516)
/** * @deprecated Make sure to use {@link Logger#getLogger(String)} instead. */ public static Category getInstance(String name) { return LogManager.getLogger(name); } /** * @deprecated Please make sure to use {@link Logger#getLogger(Class)} instead. */ public static Category getInstance(Class clazz) { return LogManager.getLogger(clazz); }
コメントに Logger#getLoggerを使ってくれって書いてます。
Loggerは、ログレベルTRACEが利用可能
org.apache.log4j.Logger.java (Line:158)
/** * Log a message object with the {@link org.apache.log4j.Level#TRACE TRACE} level. * * @param message the message object to log. * @see #debug(Object) for an explanation of the logic applied. * @since 1.2.12 */ public void trace(Object message) { if (repository.isDisabled(Level.TRACE_INT)) { return; } if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel())) { forcedLog(FQCN, Level.TRACE, message, null); } } /** * Log a message object with the <code>TRACE</code> level including the * stack trace of the {@link Throwable}<code>t</code> passed as parameter. * * <p> * See {@link #debug(Object)} form for more detailed information. * </p> * * @param message the message object to log. * @param t the exception to log, including its stack trace. * @since 1.2.12 */ public void trace(Object message, Throwable t) { if (repository.isDisabled(Level.TRACE_INT)) { return; } if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel())) { forcedLog(FQCN, Level.TRACE, message, t); } }
このメソッドは、Loggerで実装されているのでCategoryクラスでは利用できません。また、「@since 1.2.12」とあるので1.2.11以前は、traceはなかったのかな。きっと。
まとめ
log4j 1.2.17を見る限りでは、下位互換のためCategoryクラスを継承したLoggerクラスを準備し、Categoryクラスを非推奨にしたと推測できます。これにより、1.1系で利用していた設定ファイルにある「log4j.category.xx」も問題なく動作することができます。
ここで混乱が生じます。
1.2系を利用し、設定ファイル内で「log4j.category.xx」を記述するよう説明されているサイトを参考にしているとします。
すると、Java側ではLoggerクラスのインスタンスを使うため、設定ファイルとLoggerクラスの関連が見えなくなります。さらに、Logger(Category)は階層構造を構築できるため、この階層構造=Categoryの関連性を見出し腑に落ちたように思うのですが、「log4j.logger.xx」の存在が宙に浮きます。
この混乱がないよう上で検証したつもりですので、参考にして下さい。