Javaのログローテーション
仕事でjavaを多少触ることがあるが、先日ログローテーション周りでハマったのでメモしておく。
なお使用しているjavaはopenjdk 11
使用モジュールは標準のjava.util.logging
loggingモジュールの設定
本題とずれるので簡単な説明のみ 基本的にコード内で直接
- ロガーの呼び出し
- ハンドラーの追加
で設定できる。
レベルや他の設定は直接ハンドラーごとにメソッドで設定すればいいが、明示的に指定しない場合はデフォルトの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.txt
とlog1.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
ではもちろんローテーションに必要なパラメータを設定していたが、結果ローテーションはされなかった。
結論を言うと今回のコンストラクタの初期化方法では、count
、limit
がそれぞれローテーションされないデフォルト設定が入ってしまうようであった。(デフォルトの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つある)あり、
- この内
count
とlimit
が直接指定できるもの - もしくは引数を何も渡さず、
.readConfiguration
で設定を更新する方法
でないといけないようである。 すべて確認していないが、私は2の方法に切り替えることで動作するようになった。
小ネタ
awsのCloudWatchAgent
はログをCloudWatchLogs
へ送信してくれるが、ローテーションしているファイルでもちゃんと送ってくれるようだ。
ただし、ローテンションの頻度が高すぎたりすると途中のログが飛んだりしてしまうっぽいので注意が必要。