logbackのログレベルをTomcatを再起動しないで更新する方法

Tomcatを止めずにログレベルを変えたいときどうするか。
ドキュメントをざーっと見た感じだと以下の2つの方法があるみたいですね。

  • 設定ファイルのオートリロードを使って変更
  • JMXで変更

■設定ファイルのオートリロードを使って変更
logbackの設定ファイルのconfiguration要素のscan属性をtrueに設定すると設定ファイルを定期的に読み込んでくれるようになります。
読み込む頻度は、1分毎です。

<configuration scan="true" > 
  ...
</configuration>

読み込む頻度は、scanPeriod属性で変更できます。
単位として以下が指定可能です。単位を書かないとmillisecondsとして扱われます。

  • milliseconds
  • seconds
  • minutes
  • hours
<configuration scan="true" scanPeriod="30 seconds"> 
  ...
</configuration>

設定ファイルの再読み込みは、ReconfigureOnChangeFilterというTurboFilterの役目。
TurboFilterってことは、ログ出力の度にReconfigureOnChangeFilterが呼び出されることになります。
その都度、scanPeriodが経過したかどうかをチェックするのはコストが高すぎるので、対策がなされているようです。
毎回チェックするのではなく、ReconfigureOnChangeFilterがN回呼び出されたらチェックするようになっていてデフォルトでNは16、って書いてあるのかな。
英語がちゃんと読めるようになりたいなぁ。。。ドキュメントはこちら↓
http://logback.qos.ch/manual/configuration.html#autoScan
どっちにしろ、scanPeriodの度に再読み込みを行うわけなのでオーバーヘッドはありますね。


JMXで変更
もう1つの方法は、JMXを使う方法です。jconsoleなどで、ログレベルを変更するメソッドを実行できます。
TomcatJMXを利用できるようにしておいて、logbackの設定ファイルのconfigure要素の中にjmxConfigurator要素を記述します。

<configuration>
  <jmxConfigurator />
  ・・・
</configuration>

これでJMXを使ってログレベルを変更することが可能になりますが、このままだと問題が発生します。
logbackのJMXConfiguratorオブジェクトが、Systemクラスローダから参照されるようになり、GCで回収されなくなります。
Systemクラスローダから参照されるため、Wabアプリケーションを削除したり、再デプロイしても回収されないです。
この辺についてのドキュメントはこちら↓
http://logback.qos.ch/manual/jmxConfig.html#leak

これは、LoggerContextのreset()メソッドを呼び出すことで回避できるようになります。
javax.servlet.ServletContextListenerのcontextDestroyed()メソッド内に実装するといいって書いてありました。
ただ、ドキュメントのサンプルを見るとreset()メソッドじゃなくてstop()メソッドになってるんですよね。

ソースを見てみるとstop()メソッドの中でreset()メソッドを呼んでいました。
なので、サンプルにあるとおりcontextDestroyed()メソッド内で、stop()メソッドを呼ぶようにすれば問題なさそうですね。