のーずいだんぷ

主に自分用メモですが、もしかしたら誰かの役に立つかもしれません

Javaのloggingモジュールでログローテーション

Javaのログローテーション

仕事でjavaを多少触ることがあるが、先日ログローテーション周りでハマったのでメモしておく。 なお使用しているjavaはopenjdk 11 使用モジュールは標準のjava.util.logging

loggingモジュールの設定

本題とずれるので簡単な説明のみ 基本的にコード内で直接

  1. ロガーの呼び出し
  2. ハンドラーの追加

で設定できる。 レベルや他の設定は直接ハンドラーごとにメソッドで設定すればいいが、明示的に指定しない場合はデフォルトのlogging.propertyに記述された設定が使用される。

場所unix系では$JAVA_HOME/conf/logging.propertiesにグローバル設定があるが、今回は別途読み込んで設定をオーバライドした。

ローテションする際の設定と注意

jdk11のドキュメントによれば、ローテションする際のハンドラーは以下の流れで利用できる。

# サンプルコード
import java.util.logging.*

# existing code...

logger=Logger.getLogger(this.getClass().getName());
# logging.propertyで設定する場合、ローテーションに関係あるところのみ記載
handlers= java.util.logging.FileHandler
java.util.logging.FileHandler.limit = 1000
java.util.logging.FileHandler.count = 2
java.util.logging.FileHandler.pattern = %t/log%g

文で説明すると、

  • ローテーションする/しないにかかわらずFileHandlerを使用する。
  • ローテションする際は最低でも以下は設定する必要がある。
    • <handler-name>.limit ... ファイルの最大書き込み値、0は無制限=ローテーションしない なので0以上に設定する。単位はバイト。
    • <handler-name>.count ... ローテーションするファイルの最大数。デフォルトは1=ローテーションしない なので1以上に設定する。
    • <handler-name>.pettern ... 生成ファイルの命名規則。なお例の%tはシステムの一時ディレクトリ、%uはローテションする際の区別に番号を振り分けて使用する指定子。 今回の設定だとlinux(ubuntu)なら/var/tmp/内にlog0.txtlog1.txtの中に交互にハンドラが書き込みにいく。

注意点

上記の場合すべて設定ファイル上で問題なくローテーションは動作する。 が、実際のコード上でハンドラのインスタンスを定義する方法もあり、コンストラクタ引数の渡し方でローテーションできなかったりする。 私が失敗したのは以下のケースだ

logger=Logger.getLogger(this.getClass().getName());
FileHandler fh =  FileHandler<200b>(String pattern);
LogManager manager = LogManager.getLogManager();
InputStream fis_logging= new FileInputStream(this.LOGGING_PROPERTIES_PATH);
manager.readConfiguration(fis_logging);

上記のように、私は別途logging.propertyを作成し、それをreadConfigurationで読み込ませていた。 logging.propertyではもちろんローテーションに必要なパラメータを設定していたが、結果ローテーションはされなかった。

結論を言うと今回のコンストラクタの初期化方法では、countlimitがそれぞれローテーションされないデフォルト設定が入ってしまうようであった。(デフォルトのlogging.propertyを直接変更している場合は不明だが) コンストラクタの初期化には複数の方法が用意されており、

FileHandler()
FileHandler<200b>(String pattern)
FileHandler<200b>(String pattern,boolean append)
FileHandler<200b>(String pattern,int limit,int count)
FileHandler<200b>(String pattern,int limit,int count,boolean append)

5つ(exceptionの違いを含めると6つある)あり、

  1. この内countlimitが直接指定できるもの
  2. もしくは引数を何も渡さず、.readConfigurationで設定を更新する方法

でないといけないようである。 すべて確認していないが、私は2の方法に切り替えることで動作するようになった。

小ネタ

awsのCloudWatchAgentはログをCloudWatchLogsへ送信してくれるが、ローテーションしているファイルでもちゃんと送ってくれるようだ。 ただし、ローテンションの頻度が高すぎたりすると途中のログが飛んだりしてしまうっぽいので注意が必要。