logbackを使う

今まではJavaでログ出力といえば、log4jだったが、最近ではlogbackも使いやすくなっている。
[追記]
logbackはintra-martで採用されたりしているので既にかなりメジャーであると言える。
http://www.intra-mart.jp/apilist/v70/doclet/im_commons/jp/co/intra_mart/common/platform/log/rolling/ExtendedTimeBasedRollingPolicy.html
[追記-終]

logbackでログをファイル出力する場合は下記のAppenderクラスを使う。

詳細はリンクを参照。

logbackではログローテーションを実現する際に、RollingPolicyクラスとTriggeringPolicyクラスというものを使うことになる。
簡単にいうと、RollingPolicyはローテ時のバックアップファイル名についての規定を提供。
TriggeringPolicyはログローテーションのローテタイミングについての規定と機能を提供、という感じ。
ローテーションを実現するにはRollingPolicyとTriggeringPolicyの2つを定義する必要がありそう、とここでイメージできる。

主なRollingPolicyクラスは以下

日次ローテ、毎時ローテなどを提供する。
TimeBasedRollingPolicyはTriggeringPolicyとRollingPolicyが同居する。(つまり定義一つでOK)

バックアップファイル名をlog.1,log.2の形で作成できる。
別にSizeBasedTriggeringPolicyを定義する必要がある。

日時ローテとサイズローテを組み合わせたい場合に使う。
使いたい場合は、TimeBasedRollingPolicyの中に組み込む形で定義するようだ。
詳細はリンクを参照。(サンプル有り)

主なTriggeringPolicyクラスは以下

言わずもがなサイズローテーション用TriggeringPolicy。
FixedWindowRollingPolicyと併用。

logbacklog4jより良い点として、"複数JVMによる同じログファイルへの書き込みをサポートしている"というところだろう。
FileAppenderに"prudent"(boolean)という設定項目がある。
デフォルトではfalseだが、trueにすることで、複数プロセスで同じログファイルへの出力を保証するモードを利用できる。
log4jでは複数プロセス(マルチJVM)で同じログファイルへ出力するとログが消えるなどしてしまう。

ちなみにprudent=trueの場合は通常ログ書き出しメソッド(OutputStreamAppender#writeOut)でなく、
独自のFileAppender#safeWriteメソッドを使う。
safeWriteはこれだ。

final private void safeWrite(E event) throws IOException {
  ResilientFileOutputStream resilientFOS = (ResilientFileOutputStream) getOutputStream();
  FileChannel fileChannel = resilientFOS.getChannel();
  if (fileChannel == null) {
      return;
  }
  FileLock fileLock = null;
  try {
      fileLock = fileChannel.lock();
      long position = fileChannel.position();
      long size = fileChannel.size();
      if (size != position) {
          fileChannel.position(size);
      }
      super.writeOut(event);
  } finally {
      if (fileLock != null) {
          fileLock.release();
      }
  }
}

つまりFileChannelで排他ロックを取りながらログ出力をする。
処理速度にいちゃもんが付きそうだが、正確にログが取りたい場合は使いたいところだ。


また、logbackslf4jというライブラリとセットで利用する。
ほとんどslf4jを使うことを意識する必要はないが、introductionを参照して理解しておくと良い。
また日本語サイトでは、ここもslf4jのロガー実装切替アルゴリズムが理解できる。