ログファイルがあり、各行が追加されるたびにタイムスタンプを追加する必要があります。だから私はログ行の各エントリにタイムスタンプを追加し、cronジョブとして実行できるスクリプトを探しています。
答え1
一般的な方法
$ cat input.log | sed -e "s/^/$(date -R) /" >> output.log
仕組み:
cat
呼び出されたファイルを読み取り、input.log
標準出力ストリームとして印刷します。通常、標準出力は端末に接続されますが、この小さなスクリプトには、シェルが標準出力を
|
標準cat
入力にリダイレクトする内容が含まれていますsed
。sed
データを読み込み(cat
生成されたとおり)、データを処理し(-e
オプションで提供されているスクリプトに従って)、標準出力に印刷します。このスクリプトは、"s/^/$(date -R) /"
各行の先頭をdate -R
コマンドによって生成されたテキストに置き換えるためのものです(代替コマンドの一般的な構造は次のとおりです)s/pattern/replace/
。その後、出力は名前付きファイルに
>>
bash
リダイレクトされます(これはファイルの内容を置き換えて最後に追加することを意味します)。sed
output.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
仕組み:
mkfifo
名前付きパイプの作成while true; do sed ... ; done
無限ループを実行して、繰り返しごとに標準入力にsed
リダイレクトします。foo.log.fifo
sed
入力データを待つブロックその後、受信したメッセージが処理され、にリダイレクトされた標準出力に印刷されますfoo.log
。この時点で、ループは現在の端末を占有するため、新しい端末ウィンドウを開く必要があります。
echo ... > foo.log.fifo
fifoファイルにリダイレクトされた標準出力にメッセージを印刷し、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
仕組み:
実行は、無限ループにリダイレクトされる標準出力にそれを書き込んで
tailf
印刷するプロセスに従います。このループは2つのことを行います。つまり、標準入力のデータをバッファ変数と呼ばれるバッファ変数に読み込み、次にバッファリングされたデータを含む結果のタイムスタンプを書き込みます。bar.raw.log
while read ... echo
line
bar.log
にメッセージを記入してください
bar.raw.log
。最初のターミナルウィンドウがいっぱいになり、書き込みに従い操作が完了するtailf
ため、別のターミナルウィンドウでこれを実行する必要があります。とても簡単です。
利点は、終了してもアプリケーションがブロックされないことですtailf
。欠点は、正確性の低いタイムスタンプと重複したログファイルです。
答え2
ts
Perlスクリプトを使用できます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
どのように動作しますか?
exec &>
stdoutとstderrを同じ場所にリダイレクトする>( ... )
非同期内部コマンドによる出力パイプ- 残りは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'
おそらくこれは非常にエレガントなアプローチではありませんが、うまくいきます。もっとエレガントな方法があるのだろうか。