ログファイルの行とともにタイムスタンプスタンプを追加


11

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

回答:


18

一般的な方法

$ 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コマンドによって生成されたテキストに置き換えることを意味します(replaceコマンドの一般的な構成は次のとおりです:) s/pattern/replace/

  3. 次に>> bashの出力をsed呼び出されたファイルにリダイレクトしますoutput.log>はファイルの内容を置き換え>>、最後に追加することを意味します)。

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

FIFO

上記の標準ストリームリダイレクトはpipeと呼ばれます。|スクリプト内のコマンド間だけでなく、FIFOファイル(別名名前付きパイプ)を介してリダイレクトすることもできます。1つのプログラムがファイルに書き込み、別のプログラムがデータを読み取り、最初の送信時にそれを受信します。

例を選んでください:

$ 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.fifoして実行します。sed 入力データの待機をブロックし、受信したメッセージを処理して、にリダイレクトされた標準出力に出力しfoo.logます。

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

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

重要な注意点は、他のパイプがいずれかのプロセスに接続されていない場合に他のパイプが意味をなさないのと同じように、FIFOです。パイプに書き込もうとすると、誰かがパイプの反対側でデータを読み取るまで、現在のプロセスはブロックされます。パイプから読み取る場合、プロセスは誰かがパイプにデータを書き込むまでブロックされます。sed上の例のループは、実行するまで何もしません(スリープ)echo

特定の状況では、アプリケーションを設定してログメッセージをfifoファイルに書き込むだけです。設定できない場合は、元のログファイルを削除してfifoファイルを作成してください。ただし、sedループが何らかの理由で停止writeする場合readは、誰かがfifoから実行するまで、ファイルへのアクセス試行がブロックされます。

利点は、プログラムがメッセージをファイルに書き込むときに評価され、メッセージに添付される現在のタイムスタンプです。

非同期処理 tailf

ログへの書き込みと処理をより独立させるには、で2つの通常のファイルを使用できます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書き込みを追跡しbar.raw.log、それらを無限while read ... echoループにリダイレクトされた標準出力に出力するプロセスを実行します。このループは2つのアクションを実行します。標準入力から呼び出されたバッファ変数にデータを読み取りline、次に生成されたタイムスタンプを次のバッファデータとともにに書き込みbar.logます。

  2. にメッセージを書き込みますbar.raw.log。最初のウィンドウが占有されtailf、書き込みを追跡してその作業を行うため、別のターミナルウィンドウでこれを行う必要があります。とてもシンプルです。

長所は、あなたが殺してもアプリケーションがブロックしないことですtailf。短所は、タイムスタンプが正確でなく、ログファイルが重複することです。


ありがとうございます.Fifoは私の使用に非常に適しているようです.myプログラムはすでにfile.txtログに書き込みますが、このファイルはfoo.log.fifoにリダイレクトする必要があります。 !では、更新ログファイルのコンテンツをこのfoo.log.fifoにリダイレクトして、時間を追加する方法を教えてください。
Kratos

ちょうど答えを改善しました。fifoがをブロックする理由を説明し、tailfそれを使用する正しい方法を追加しました。実際にはwithのtailf方がエレガントなようですが、fifoの方法は誰かに役立つことを願って残しました。
Dmitry Vasilyanov

sed回答を使用してvmstat出力に注釈を付けると、変更されないタイムスタンプvmstat 1 | sed -e "s / ^ / $(date -R)/"
ChuckCottrill 2017年


2

Dmitry Vasilyanovの回答から変更。

bashスクリプトでは、出力をタイムラインで行ごとにリダイレクトしてラップできます。

いつ使用するか:

  • bashスクリプトジョブの場合、メインスクリプトの前に行を挿入します
  • スクリプト以外のジョブの場合は、プログラムを呼び出すスクリプトを作成します。
  • システムによるサービス制御についてはtailf、Dmitry Vasilyanovが言ったように、ログファイルに使用することをお勧めします。

という名前の例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
    

1

私が使用しts、私はサボテンは、リモートホストの統計で満たさ取得するために使用するスクリプトのエラーログにタイムスタンプを持つエントリを取得するには、この方法を。

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'

多分これはそれを行うための非常にエレガントな方法ではありませんが、それは機能します。もっと洗練されたアプローチがあるのでしょうか。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.