ログファイル行でタイムスタンプを追加する

ログファイル行でタイムスタンプを追加する

ログファイルがあり、各行が追加されるたびにタイムスタンプを追加する必要があります。だから私はログ行の各エントリにタイムスタンプを追加し、cronジョブとして実行できるスクリプトを探しています。

答え1

一般的な方法

$ cat input.log | sed -e "s/^/$(date -R) /" >> output.log

仕組み:

  1. cat呼び出されたファイルを読み取り、input.log標準出力ストリームとして印刷します。

    通常、標準出力は端末に接続されますが、この小さなスクリプトには、シェルが標準出力を|標準cat入力にリダイレクトする内容が含まれていますsed

  2. sedデータを読み込み(cat生成されたとおり)、データを処理し(-eオプションで提供されているスクリプトに従って)、標準出力に印刷します。このスクリプトは、"s/^/$(date -R) /"各行の先頭をdate -Rコマンドによって生成されたテキストに置き換えるためのものです(代替コマンドの一般的な構造は次のとおりです)s/pattern/replace/

  3. その後、出力は名前付きファイルに>> bashリダイレクトされます(これはファイルの内容を置き換えて最後に追加することを意味します)。sedoutput.log>>>

問題は、$(date -R)スクリプトの実行時に一度だけ評価されるため、スクリプトが挿入されることです。現在の各行の先頭にあるタイムスタンプです。現在のタイムスタンプは、メッセージが生成された瞬間から離れている可能性があります。これを防ぐには、cronジョブを使用するのではなく、メッセージがファイルに書き込まれたときに処理する必要があります。

先入選出

上記の標準ストリームリダイレクトは次のとおりです。管路。スクリプト内のコマンド間でリダイレクトできるだけでなく、次のように|リダイレクトすることもできます。先入れ先出しファイル(別名名前付きパイプ)。あるプログラムはファイルに書き込み、もう一方のプログラムはデータを読み取り、最初に送信されたときにそれを受け取ります。

例を選択してください:

$ mkfifo foo.log.fifo
$ while true; do cat foo.log.fifo | sed -e "s/^/$(date -R) /" >> foo.log; done;

# have to open a second terminal at this point
$ echo "foo" > foo.log.fifo
$ echo "bar" > foo.log.fifo
$ echo "baz" > foo.log.fifo

$ cat foo.log      

Tue, 20 Nov 2012 15:32:56 +0400 foo
Tue, 20 Nov 2012 15:33:27 +0400 bar
Tue, 20 Nov 2012 15:33:30 +0400 baz

仕組み:

  1. mkfifo名前付きパイプの作成

  2. while true; do sed ... ; done無限ループを実行して、繰り返しごとに標準入力にsedリダイレクトします。foo.log.fifosed 入力データを待つブロックその後、受信したメッセージが処理され、にリダイレクトされた標準出力に印刷されますfoo.log

    この時点で、ループは現在の端末を占有するため、新しい端末ウィンドウを開く必要があります。

  3. echo ... > foo.log.fifofifoファイルにリダイレクトされた標準出力にメッセージを印刷し、sedそれを受信して​​処理し、それを通常のファイルに書き込みます。

重要なことは、fifoは他のパイプと同様に、片側がプロセスに接続されていない限り意味がないことです。パイプに書き込もうとすると、現在のプロセスは詰まった誰かがパイプの反対側の端にあるデータを読み取るまでです。パイプからデータを読み取ろうとすると、プロセスは次のことを行います。詰まった誰かがパイプにデータを書き込むまで。上記の例のループは、sed実行されるまで何もしません(休止状態)echo

場合によっては、fifoファイルにログメッセージを書き込むようにアプリケーションを簡単に構成できます。設定できない場合は、元のログファイルを削除してfifoファイルを作成してください。ただし、sed何らかの理由でループが終了すると、誰かがfifoからファイルにアクセスするwriteまでファイルにアクセスしようとするプログラムがブロックされます。read

特典は現在のプログラムがファイルにメッセージを書き込むと、タイムスタンプが評価され、メッセージに追加されます。

非同期処理tailf

ログの書き込みと処理をさらに独立させるために、両方のプロセスを使用できますtailf。アプリケーションはメッセージをソースファイルに書き込み、他のプロセスは新しい行を読み取り(非同期書き込み後)、データを処理して2番目のファイルに書き込みます。ファイル。

たとえば、見てみましょう。

# will occupy current shell
$ tailf -n0 bar.raw.log | while read line; do echo "$(date -R) $line" >> bar.log; done;

$ echo "foo" >> bar.raw.log
$ echo "bar" >> bar.raw.log
$ echo "baz" >> bar.raw.log

$ cat bar.log

Wed, 21 Nov 2012 16:15:33 +0400 foo
Wed, 21 Nov 2012 16:15:36 +0400 bar
Wed, 21 Nov 2012 16:15:39 +0400 baz

仕組み:

  1. 実行は、無限ループにリダイレクトされる標準出力にそれを書き込んでtailf印刷するプロセスに従います。このループは2つのことを行います。つまり、標準入力のデータをバッファ変数と呼ばれるバッファ変数に読み込み、次にバッファリングされたデータを含む結果のタイムスタンプを書き込みます。bar.raw.logwhile read ... echolinebar.log

  2. にメッセージを記入してくださいbar.raw.log。最初のターミナルウィンドウがいっぱいになり、書き込みに従い操作が完了するtailfため、別のターミナルウィンドウでこれを実行する必要があります。とても簡単です。

利点は、終了してもアプリケーションがブロックされないことですtailf。欠点は、正確性の低いタイムスタンプと重複したログファイルです。

答え2

tsPerlスクリプトを使用できますmoreutils:

$ echo test | ts %F-%H:%M:%.S
2012-11-20-13:34:10.731562 test

答え3

Dmitry Vasilyanovの回答が修正されました。

Bashスクリプトでは、タイムスタンプを使用して出力を1行ずつリダイレクトしてラップできます。

使用時期:

  • Bashスクリプト操作の場合は、デフォルトのスクリプトの前にこの行を挿入してください。
  • 非スクリプト操作の場合は、プログラムを呼び出すスクリプトを作成します。
  • tailfシステムサービスを制御するには、Dmitry Vasilianovが述べたようにログファイルを使用することをお勧めします。

以下は、次の例ですfoo.sh

#!/bin/bash
exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line" >> foo.log; done;)

echo "foo"
sleep 1
echo "bar" >&2
sleep 1
echo "foobar"

結果:

$ bash foo.sh
$ cat foo.log
May 12 20:04:11 foo
May 12 20:04:12 bar
May 12 20:04:13 foobar

どのように動作しますか?

  1. exec &>stdoutとstderrを同じ場所にリダイレクトする
  2. >( ... ) 非同期内部コマンドによる出力パイプ
  3. 残りはDmitry Vasilyanovが説明したように機能します。

たとえば、

  • タイムスタンプとログをファイルにパイプ

    #!/bin/bash        
    exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line" >> foo.log; done;)
    
    echo "some script commands"
    /path-to/some-thrid-party-programs
    
  • または、タイムスタンプを印刷して標準出力に書き込みます。

    #!/bin/bash        
    exec &> >(while read line; do echo "$(date +'%h %d %H:%M:%S') $line"; done;)
    
    echo "some script commands"
    /path-to/some-thrid-party-programs
    

    /etc/crontab次に設定に保存します。

    * * * * * root /path-to-script/foo.sh >> /path-to-log-file/foo.log
    

答え4

私はtsこの方法を使用してエラーログからタイムスタンプされたエントリを取得し、スクリプトはCactiを取得し、リモートホストの統計を入力するために使用されます。

Cactiをテストするためにrand任意の値を追加し、温度グラフを使用してシステム温度を監視しました。

Pushmonstats.shは、私のPCからシステム温度統計を収集し、Cactiを実行しているRaspberry Piに送信するスクリプトです。しばらく前にネットワークが詰まっていました。私のエラーログにはSSHタイムアウトのみが表示されます。残念ながら、このログには時間エントリはありません。ログエントリにタイムスタンプを追加する方法がわかりません。だから、インターネットで検索を行った後、偶然この記事を発見し、これが私が使用するものですts

テストには不明なオプションを使用しましたrand。これにより stderr にエラーが発生します。これをキャプチャするために一時ファイルにリダイレクトします。その後、catを使用してファイルの内容を表示し、にパイプし、このts記事で見つかった時間形式を追加し、最後にエラーファイルに書き込みました。次に、一時ファイルの内容を消去します。それ以外の場合は、同じエラーが重複する項目が発生します。

予約されたもの:

* * * * * /home/monusr/bin/pushmonstats.sh 1>> /home/monusr/pushmonstats.log 2> /home/monusr/.err;/bin/cat /home/monusr/.err|/usr/bin/ts %F-%H:%M:%.S 1>> /home/monusr/pushmonstats.err;> /home/monusr/.err

私のエラーログには次のものが表示されます。

2014-03-22-19:17:53.823720 rand: unknown option -- '-l'

おそらくこれは非常にエレガントなアプローチではありませんが、うまくいきます。もっとエレガントな方法があるのだろうか。

関連情報