log4jのLoggerの階層構造とadditivityの振舞について

Loggerの階層構造について

Loggerは階層構造を作ることができます。例えば、

#---------------------------------------------------------------------------------------
# Logger
#---------------------------------------------------------------------------------------
# rootLogger
log4j.rootLogger=DEBUG, ROOT

# logger.x
log4j.logger.x=DEBUG, ROOT

# logger.x.y
log4j.logger.x.y=DEBUG, ROOT

# logger.x.y.z
log4j.logger.x.y.z=DEBUG, ROOT

とした場合、rootLoggerを始祖として、
[rootLogger] -> [logger.x] -> [logger.x.y] -> [logger.x.y.z] という親子関係が構築されます。
この親子関係には、子Loggerのログ出力が親Loggerに伝搬する仕様があります。これによって、[logger.x.y.z]に、ログレベルDEBUG以上の出力を行うと、そのログ出力は祖先に伝搬し[Appender.ROOT]により、4回のログ出力が実行されることになります。

伝搬を止める属性 - additivity

親Loggerへの伝搬を止めるためには、additivityという属性にfalseを設定します。(初期値ははtrue)

#---------------------------------------------------------------------------------------
# Logger
#---------------------------------------------------------------------------------------
# rootLogger
log4j.rootLogger=DEBUG, ROOT

# logger.x
log4j.logger.x=DEBUG, ROOT
log4j.additivity.x=false

# logger.x.y
log4j.logger.x.y=DEBUG, ROOT
log4j.additivity.x.y=false

# logger.x.y.z
log4j.logger.x.y.z=DEBUG, ROOT
log4j.additivity.x.y.z=false

このようにした場合、
[logger.x.y.z]に、ログレベルDEBUG以上の出力を行うと、そのログは祖先に伝搬せず1回の出力に留まります。

additivityの仕様

では、中間の[logger.x.y]のみadditivityをfalseとして、[logger.x.y.x]に、ログレベルDEBUG以上の出力を行うとログの出力は何回になるでしょう。

#---------------------------------------------------------------------------------------
# Logger
#---------------------------------------------------------------------------------------
# rootLogger
log4j.rootLogger=DEBUG, ROOT

# logger.x
log4j.logger.x=DEBUG, ROOT
log4j.additivity.x=true

# logger.x.y
log4j.logger.x.y=DEBUG, ROOT
log4j.additivity.x.y=false

# logger.x.y.z
log4j.logger.x.y.z=DEBUG, ROOT
log4j.additivity.x.y.z=true

このようにした場合、ログの出力は2回となります。
これは、additivityの判定仕様が以下のようになっているためです。

  1. 指定されたLoggerのログ出力
  2. 指定されたLoggerのadditivityの判定
    1. trueの場合、親Loggerに処理を委譲(1.に戻る)
    2. falseの場合、処理を終了

このため、中間のLoggerでadditivityをfalseとした場合は、falseとしたLoggerではログ出力され、それより祖先のLoggerにログ出力が伝搬しないので注意が必要です。

ログレベルは、起点となるLoggerの設定が適用される

Loggerに設定されているログレベルについて検証します。
additivity初期値trueを適用しログ出力が伝搬する設定としていますが、[logger.x.y.x]より祖先のLoggerに、ログレベルINFOを設定しています。
[logger.x.y.x]に、ログレベルDEBUGの出力を行うとログの出力は何回になるでしょう。

#---------------------------------------------------------------------------------------
# Logger
#---------------------------------------------------------------------------------------
# rootLogger
log4j.rootLogger=INFO, ROOT

# logger.x
log4j.logger.x=INFO, ROOT

# logger.x.y
log4j.logger.x.y=INFO, ROOT

# logger.x.y.z
log4j.logger.x.y.z=DEBUG, ROOT

このようにした場合、ログの出力は4回となります。
これは、ログ出力のログレベル判定には、起点(この例の場合、[logger.x.y.x])のログレベルDEBUGが適用されるためです。

このため、rootLoggerのログレベルをTRACEまで下げたとしても、子Loggerのログレベルが適用されるため伝搬してログ出力されるので注意が必要です。

まとめ

  • additivityとfalseとした場合、それより祖先のLoggerには伝搬しない。(falseを設定したLoggerの出力は実行される)
  • 出力されるログレベルは、起点となるLoggerのログレベルが適用される。