JDK8からあるちょっと嬉しいGCログオプション

JDK8およびJDK8u20では、GCログに関連する2つの便利な機能が追加されている。いずれの機能も2014/8現在最新のJDK7 update 67 には含まれていないが、JDK7u80にてバックポートされる予定。

GCログにpidと日付を含める (JDK8より)

JAVA_OPTS="$JAVA_OPTS -Xloggc:/var/log/wildfly/gc_%p_%t.log"
  => 実際のファイル名例 : gc_pid31455_2014-08-31_14-20-16.log.0

GCログのフォーマットに%pを入れるとpid形式のプロセスIDが付与される。また%tを付与すると"_2014-08-31_14-20-16"のようにGCログファイルを作成した日付時分秒が追加される。かつてGCログはJavaを再起動すると同じファイルが上書きされて消えてしまうため、出力先を-Xloggc:gc.log.`date +%Y%m%d%H%M%S`のようにOSコマンドによってファイル名に日付を付与していたが、この機能の追加によりOSコマンドへの依存がなくなるので便利。

jcmd GC.rotate_logによるローテーション (JDK8u20より)

JDK8u20よりjcmdにGCログをローテーションさせるコマンドが追加されている。

jcmd <pid> GC.rotate_log

以前よりGCログにはサイズローテーション機能が付与されていたが、Javaの場合ログのリロード機能がないため、logrotate.dなどによる日付ローテーションが困難であった。GC.rotate_logの導入により、以下の起動オプションと組み合わせると日付契機のログローテーションが実現できる。

-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=0

UseGCLogFileRotationおよびNumberOfGCLogFilesが設定されていない状態でjcmd GC.rotate_logを実行すると、GCログローテーションが有効となっていないことを示すエラー(Target VM does not support GC log file rotation.)となる。また、GCLogFilzeSize=0を設定し、ファイルサイズ契機のローテーションを止めている。

NumberOfGCLogFilesの指定がGC.rotate_logの実行に必須であるため、 ログの世代数管理をlogrotate.dに任せるのは難しい。またファイルのコピーや世代数を超えたファイルの削除はJVMが行ってくれるため、logrotate.dを使わずにまずはお試しとして直接cron.dailyに入れてみた。

# touch /etc/cron.d/cron.daily/gclog_rotate
# vim /etc/cron.d/cron.daily/gclog_rotate

#!/bin/sh
sudo -u wildfly /usr/java/jdk1.8.0_20/bin/jcmd `cat /var/run/wildfly/wildfly.pid` GC.rotate_log

/var/run/wildfly/wildfly.pidより起動中のWildFlyのプロセスIDを確認している。WildFlyでなくても、/etc/rc.d/init.dに登録している場合は/var/run配下に現状のプロセスIDを示すファイルが出力されると思う。

まとめ

  • JDK8よりGCログフォーマットに%p(pid)や%t(時間)が含められる
  • JDK8u20よりjcmd GC.rotate_logGCログローテションできる
  • いずれも現状はJDK7に含まれていないが、JDK7u80 にバックポート予定