Stdoutに多くの出力を生成する長時間実行コマンドがあります。たとえば、最後の3日間または最後のギビバイト(途中で線が切れるのを避けます)だけを保持し、可能であれば20 MiB以下のファイルチャンクに保持したいです。各ファイルチャンクには、数値のサフィックスまたはタイムスタンプが付けられます。
何かのようなもの:
my-cmd | magic-command --output-file-template=my-cmd-%t \
--keep-bytes=1G \
--keep-time=3d \
--max-chunk-size=20M \
--compress=xz
書くでしょう:
my-cmd-2014-09-05T10:04:23Z
20Mに達すると、圧縮して新しいファイルを開く、などのようになり、しばらくすると最も古いファイルの削除を開始します。
そのようなコマンドは存在しますか?
私はlogrotate
と他のアプリケーションによって書き込まれたファイルを管理するその機能を知っていますが、cronジョブの設定、ルールの指定、プロセスの中断を必要としない、より簡単なものを探しています。等.
pipelog を使用して、必要なものの一部を取得できます。これにより、「実行中のプロセスのログを、外部信号に応答する中間体を介してパイプすることで、ログを回転またはクリアできます」。例:
spewstuff | pipelog spew.log -p /tmp/spewpipe.pid -x "gzip spew.log.1"
次に、/tmp/spewpipe.pid
からpidを取得できます。
kill -s USR1 $(</tmp/spewpipe.pid)
しかし、cronか何かで設定する必要があるでしょう。ただし、これには1つの問題があります。 I gzip spew.log.1
に注意してください-これは、ログがローテーションされた後に-x
コマンドが実行されるためです。したがって、gzipを実行して後でファイルを移動する短いスクリプトを作成し、それをspew.log.1.gz
コマンドとして使用しない限り、毎回-x
を上書きするというさらなる問題があります。
完全な開示:私はこれを書いたので、もちろんそれは機能します完全に機能します。 ;)バージョン0.2の場合、圧縮オプション、またはそれをより容易にするものを念頭に置きます(-x
の使用目的は多少異なりますが、上記のように機能します)。また、自動化されたロールオーバーは良い考えです...最初のバージョンは、必要のない機能を追加する誘惑に抵抗したため、意図的に最小限に抑えられています(結局、cronジョブを設定するのはそれほど難しくありません)。
これはtextの出力を目的としています。 nullバイトの可能性がある場合は、-z
を使用する必要があります。これにより、ゼロが別の値に置き換えられます。これは、実装を簡素化するためのトレードオフでした。
Dan Bernsteinの multilog は明らかにこれを行うことができます-またはおそらくそのほとんどは、!processorにファイル記述子を介してアウトレットを提供します20M/1Gサイズの仕様は、16Mがログあたりの外側の制限であると思われるため、多少の調整が必要になる場合がありますが、お好みで違いを補ってください。ほとんどの場合、上記のリンクからのコピーと貼り付けの選択が続きますが、リンクには、行ごとのタイムスタンプなど、他のオプションの詳細も表示され、最新の行の一致のみを含む[an] other file [s]が維持されますpatternなど。
multilog script
...scriptは、任意の数の引数で構成されます。各引数は1つのアクションを指定します。アクションは、入力の各行に対して順番に実行されます。
各行が最初に選択されます。アクション...
-pattern
...パターンがラインと一致する場合、ラインの選択を解除します。アクション...
+pattern
patternが行に一致する場合、行を選択します。
...patternは星と非星の文字列です。同じ順序ですべての星と非星が一致する文字列の連結に一致します。非スターはそれ自体と一致します。パターンの最後の前のスターは、パターンの次の文字を含まないすべての文字列と一致します。パターンの最後の星は、任意の文字列と一致します。
dirがドットまたはスラッシュで始まる場合、アクション...
dir
...選択した各行をdirという名前のログに追加します。 dirが存在しない場合は、multilog
が作成します。
ログの形式は次のとおりです。
dirは、いくつかの古いログファイルを含むディレクトリで、current、およびmultilog
のその他のファイル。そのアクションを追跡します。
各古いログファイルには、@で始まり、ファイルがいつ終了したかを示す正確なタイムスタンプが続き、次のコードのいずれかで終わる名前があります。
アクション...
ssize
...後続のdirアクションの最大ファイルサイズを設定します。 multilog
は、currentがcurrentはsizeバイトです。 (multilog
はまた、最大ファイルサイズの2000バイト以内の改行を検出した場合、currentが十分に大きいと判断します。行の境界でログファイルを終了しようとします。) は4096から16777215の間でなければなりません。デフォルトの最大ファイルサイズは99999です。
バージョン0.75以降:multilog
が[〜#〜] alrm [〜#〜]信号を受信すると、すぐにcurrentは、currentが空でない場合、十分な大きさです。
(注:zsh
schedule
組み込み関数は、必要に応じて、指定された間隔でALRM
を送信するように簡単に説得できると思います。)
アクション...
nnum
...後続のdirアクションのログファイルの数を設定します。 currentの名前を変更した後、multilog
がnumまたは古いログファイルが多いほど、タイムスタンプが最小の古いログファイルが削除されます。 numは少なくとも2でなければなりません。ログファイルのデフォルト数は10です。
アクション...
!processor
...後続のdirアクションのプロセッサを設定します。 multilog
はcurrentからprocessorをフィードし、 currentではなく、古いログファイルとして出力します。 multilog
は、プロセッサが記述子5に書き込む出力も保存し、次のログファイルでプロセッサを実行するときに記述子4でその出力を読み取り可能にします。信頼性のために、processorは、出力の作成に問題がある場合、ゼロ以外で終了する必要があります。 multilog
はそれを再度実行します。 processorを実行すると、multilog
への入力を供給するプログラムがブロックされる場合があることに注意してください。
これは、あなたが要求しているようなことをするためのハッキングされたpythonスクリプトです:
#!/bin/sh
''':'
exec python "$0" "$@"
'''
KEEP = 10
MAX_SIZE = 1024 # bytes
LOG_BASE_NAME = 'log'
from sys import stdin
from subprocess import call
log_num = 0
log_size = 0
log_name = LOG_BASE_NAME + '.' + str(log_num)
log_fh = open(log_name, 'w', 1)
while True:
line = stdin.readline()
if len(line) == 0:
log_fh.close()
call(['gzip', '-f', log_name])
break
log_fh.write(line)
log_size += len(line)
if log_size >= MAX_SIZE:
log_fh.close()
call(['gzip', '-f', log_name])
if log_num < KEEP:
log_num += 1
else:
log_num = 0
log_size = 0
log_name = LOG_BASE_NAME + '.' + str(log_num)
log_fh = open(log_name, 'w', 1)
膨大なコードの記述を含まない概算として私がこれまでに見つけた中で最高のものは、次のzsh
コードです。
autoload zmv
mycmd |
while head -c20M > mycmd.log && [ -s mycmd.log ]; do
zmv -f '(mycmd.log)(|.(<->))(|.gz)(#qnOn)' '$1.$(($3+1))$4'
{rm -f mycmd.log.1 mycmd.log.50.gz; (gzip&) > mycmd.log.1.gz} < mycmd.log.1
done
ここでは最大51の20MiBの大きなファイルに分割して回転しています。