コマンドの出力をリングバッファに格納

コマンドの出力をリングバッファに格納

標準出力から多くの出力を生成する長期実行コマンドがあります。たとえば、過去3日間または過去1 GBだけを保存し(行が途中で切り捨てられないように)、可能であればファイルブロックを20MiB以下に保存したいと思います。各ファイルブロックの名前は、数字のサフィックスまたはタイムスタンプで指定されます。

それは次のとおりです。

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クローンジョブの設定、ルールの指定、プロセスの一時停止などを必要としない、より簡単なものを探しています。

答え1

あなたはあなたが望むものを得ることができますパイプラインログ、これは、「実行中のプロセスのログを外部信号に応答する中間体を介して回転または消去することを可能にします。」たとえば、次のようになります。

spewstuff | pipelog spew.log -p /tmp/spewpipe.pid -x "gzip spew.log.1"

その後、からpidを取得します/tmp/spewpipe.pid

kill -s USR1 $(</tmp/spewpipe.pid)

しかし、cronのようなものを使って設定する必要があります。しかし、問題があります。参考にしてくださいgzip spew.log.1。これは-x、ログの回転後にコマンドが実行されるためです。そのためspew.log.1.gz、gzipを実行してからファイルを移動する短いスクリプトを作成し、それをコマンドとして使用しない限り、上書きするたびに追加の-x問題が発生します。

完全な公開:私はこれを書いたので、当然動作します。完璧。 ;) バージョン 0.2 では、圧縮オプションやより良い機能を提供するオプションを念頭に置いておきます(意図した目的は少し-x異なりますが、上記のように動作します)。自動ロールオーバーも良い考えです...最初のバージョンは、不要な機能を追加しようとする誘惑に抵抗したため、意図的に最小限に抑えられました(最終的にこれを行うためにクローンタスクを設定することはそれほど難しくありません)。

その目的は次のとおりです。テキスト-z出力;潜在的なnullバイトがある場合は、0を別のものに置き換える - を使用する必要があります。これは実装を簡素化するための妥協案です。

答え2

ダンバーンスタインマルチログファイル記述子を介してアウトレットを提供しながら、それを行うことは明らかに可能です。あるいは、ほとんどの場合かもしれません。!プロセッサ必要に応じて違いを設定します。 20M / 1Gサイズの仕様にはわずかな不正行為が必要な場合がありますが、16Mが各ログの外部制限のように見えます。以下のほとんどは、上記のリンクからコピー+貼り付けを選択することです。ただし、そのリンクは、最新の行一致のみを含む追加ファイルを保持する行ごとのタイムスタンプなどの他のオプションも詳細に説明します。模様そしてもっと。

相互作用

 multilog script

...スクリプトさまざまなパラメータで構成されています。各パラメーターはジョブを指定します。各入力行に対してこれらの操作を順次実行します。

ライン選択

各行は最初に選択されます。その行動...

-pattern

...パターンが行と一致する場合は、行を選択解除します。その行動...

+pattern

次の場合は、行を選択してください。模様行と一致します。

...模様星と星ではない文字列です。同じ順序で一致するすべてのアスタリスクと、アスタリスク以外の文字で構成されるすべての文字列連結と一致します。星じゃない人は自分とマッチします。パターンの終わりの前のアスタリスクは、パターンの次の文字を含まないすべての文字列と一致します。パターンの末尾にあるアスタリスクはすべての文字列と一致します。

ログ自動循環

もし目次ドットまたはスラッシュで始めて...

 dir

...選択した各行を次の名前のログに追加します。目次。もし目次存在しない場合はmultilog作成してください。

ログ形式は次のとおりです。

  1. 目次特定の数の古いログファイルを含むディレクトリ。ログファイルの名前は次のとおりです。現在のmultilogおよびタスクを追跡するために使用されるその他のファイル。

  2. 各古いログファイルの名前は次のように終了します。@、ファイルが完了した正確なタイムスタンプを表示し、次のいずれかのコードで終わります。

    • .S:このファイルは完全に処理され、ディスクに安全に書き込まれました。
    • .油:このファイルは中断時に作成されました。切り取った可能性があります。まだ処理されていません。

その行動...

 ssize

...以降の最大ファイルサイズの設定目次アクション。multilog決める現在のだとしたら十分大きい現在の持つサイズバイト。multilogまた、最大ファイルサイズの2000バイト以内で改行文字が見えた場合、currentが十分に大きいと判断します。ライン境界でログファイルを完成しようとします。)4096 から 16777215 の間でなければなりません。デフォルトの最大ファイルサイズは99999です。

0.75以上:multilog受け取った場合アラームシグナルを送信するとすぐに決定されます。現在のだとしたら十分大きい現在の空ではありません。

(注:必要に応じて、指定した間隔で送信するzsh scheduleように組み込み機能を簡単に説得できると思います。)ALRM

その行動...

 nnum

...後続のログファイル数の設定目次アクション。名前を変更した後現在のmultilog見たらシリアル番号または、より古いログファイルを使用すると、タイムスタンプが最も小さい古いログファイルが削除されます。シリアル番号2つ以上でなければなりません。デフォルトのログファイル数は10です。

その行動...

 !processor

...次の作業用にプロセッサを設定します。目次アクション。multilog与えることができる現在の渡すプロセッサ出力を代わりに古いログファイルとして保存します。現在のmultilogプロセッサがディスクリプタ5に書き込んだすべての出力は、プロセッサが次のログファイルで実行されたときにディスクリプタ4で保存および読み取ることができます。信頼性のため、プロセッサ出力の生成中に問題が発生した場合は、ゼロ以外の値で終了する必要があります。multilogその後、再実行されます。実行中です。プロセッサプログラムが入力を提供できないようにすることができますmultilog

答え3

これはあなたが要求したものと同じことをするように変更された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)

答え4

systemdを持つLinuxでは、root権限がある場合のみ丸太はい。LogNamespace=ユニットファイルになければなりません。

/etc/systemd/[email protected]:

[Journal]
Storage=volatile
RuntimeMaxUse=20M

/etc/systemd/system/myprogram.service:

[Unit]
Description=My Test Service
[Service]
ExecStart=/home/myuser/myprogram
LogNamespace=myprogram
User=myuser

_

systemctl daemon-reload
systemctl start myprogram
journalctl --namespace=myprogram --follow

バラよりhttps://www.freedesktop.org/software/systemd/man/systemd-journald.service.html#Journal%20Namespaces

関連情報