log4j2を使用してログファイルを生成するJavaアプリケーションがあり、他のスクリプトを使用してプロセスを再起動する前にプロセスを停止するスクリプトがあります。毎日の真夜中に停止して再起動するまでに5分間の一時停止があります。起動スクリプトで "mv"コマンドを使用して、ログファイルの名前を拡張子としてtimstampに変更します。問題は、ログファイルの1つのファイルの先頭(数MB)にNULL文字が含まれ、ログファイルがバイナリファイルになることです。問題に追加のコンテキストを提供するためのいくつかの観察注意事項:1. - 同じバージョンのJavaアプリケーションを使用する別のホストで同じ起動スクリプトが使用されます。この問題はまったく存在しません。 2.- 時々。つまり、1 週間は 5 つのログファイルがすべて破損し、もう 1 週間はログファイルが正常です。 3.- 同様の開発者 Linux ホストでは再現できません。本番Linuxホストでのみ可能です。 4. - ログファイルのサイズは通常1日あたり約4〜6GBです。 5. - アプリケーションは毎日の深夜に停止+ 5分間一時停止+スクリプトを介して起動します。 6.- hexdump を使用してバイナリログファイルの内容を表示します。数MBのヌル文字で始まり、通常の一般的なASCIIコンテンツで始まります。
どんなアドバイスも本当にありがとうございます。ありがとうございます!
答え1
「バイナリ」ログファイルのサイズを見て、ls -l
取得できるサイズと比較するとdu -k
興味深い点が見つかります。ファイルがディスクで占めるスペースよりも大きいようです!
Javaアプリケーションプロセスの2番目のコピーが実行されているか、本番アプリケーションがシャットダウンを完了するのに5分以上かかることがあります。
したがって、NULL文字が発生した場合、ログファイルが以前に記録された場所を記憶しているアプリケーションプロセスはまだ実行中です。書き込み用にファイルを開き、seek()
その場所に書き込み、ログメッセージを書き込みます。いつものように。
しかし、ファイルが以前に存在しなかった場合(mv
削除されたため)、これはまさにこれが生成されることです。スパースファイル。これは非常に古いUnixファイルシステム機能です。
スパースファイルは本質的にデータ圧縮の最も簡単なプロトタイプです。ヌルバイトのみを含むディスクブロック全体は実際にはディスクにデータとして保存されませんが、ファイルブロックがどこにあるかをシステムに伝えるファイルシステムメタデータは効果的に特別なタグを取得します。 「このファイルの場所に X ヌルバイトブロックを挿入します」を意味します。
書き込み用のファイルを開いてスパースファイルを作成し、実際に何も書かずに現在のファイルの終わりを超えてコンテンツを探します。それから何かを書いてください。ほとんどのUnixスタイルのファイルシステムは、ヌルで埋められた中間書き込みブロックをディスクに明示的に書き込むのではなく、古いEOFと新しく作成されたデータの間にブロックをスパースブロックとして自動的に追加します。ファイルを読み取るとき、ファイルシステムドライバは空のバイトブロックでスパースブロックを自動的に埋めるので、アプリケーションはそれをまったく認識する必要はありません。
fuser
ログファイルが開いていることを確認して開いている場合は、エラーメッセージで停止するテストをアプリケーション起動スクリプトに追加できます。このような:
LOGFILE=/some/where/log4j2.log
if fuser -s $LOGFILE; then
echo "ERROR: $LOGFILE is still in use. Maybe the app is still running. Make it stop." >&2
exit 1
fi
# add here your commands to rotate the logs and start the application.
log4j2
実際には、独自のログファイルの回転機能があります。最善の解決策は、おそらく外部スクリプトを使用するのではなく、これらの機能を使用することです。