Jawaban:
$ cat input.log | sed -e "s/^/$(date -R) /" >> output.log
Bagaimana itu bekerja:
cat
membaca file yang dipanggil input.log
dan hanya mencetaknya ke aliran output standar.
Biasanya output standar terhubung ke terminal, tetapi skrip kecil ini berisi |
sehingga shell mengarahkan output cat
standar ke input standar sed
.
sed
membaca data (saat cat
memproduksinya), memprosesnya (sesuai dengan skrip yang disediakan dengan -e
opsi) dan kemudian mencetaknya ke output standar. Skrip "s/^/$(date -R) /"
berarti mengganti setiap awal baris ke teks yang dihasilkan oleh date -R
perintah (konstruksi umum untuk perintah ganti adalah:) s/pattern/replace/
.
Kemudian sesuai dengan >>
bash
pengalihan output sed
ke file bernama output.log
( >
berarti ganti konten file dan >>
berarti tambahkan sampai akhir).
Masalahnya adalah $(date -R)
dievaluasi satu kali ketika Anda menjalankan skrip sehingga akan memasukkan cap waktu saat ini ke awal setiap baris. Stempel waktu saat ini mungkin jauh dari saat ketika pesan dihasilkan. Untuk menghindarinya, Anda harus memproses pesan sebagaimana ditulis ke file, bukan dengan tugas cron.
Pengalihan aliran standar yang dijelaskan di atas disebut pipa . Anda dapat mengarahkan ulang tidak hanya dengan |
antara perintah dalam skrip, tetapi melalui file FIFO (alias pipa bernama ). Satu program akan menulis ke file dan yang lain akan membaca data dan menerimanya sebagai yang pertama dikirim.
Pilih sebuah contoh:
$ 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
Bagaimana itu bekerja:
mkfifo
menciptakan pipa bernama
while true; do sed ... ; done
menjalankan loop tak terbatas dan pada setiap iterasi ia berjalan sed
dengan mengarahkan ulang foo.log.fifo
ke input standarnya; sed
blok menunggu input data dan kemudian memproses pesan yang diterima dan mencetaknya ke output standar diarahkan ke foo.log
.
Pada titik ini Anda harus membuka jendela terminal baru karena loop menempati terminal saat ini.
echo ... > foo.log.fifo
mencetak pesan ke output standarnya yang dialihkan ke file fifo dan sed
menerimanya serta memproses dan menulis ke file biasa.
Catatan penting adalah fifo sama seperti pipa lain tidak masuk akal jika salah satu sisinya tidak terhubung ke proses apa pun. Jika Anda mencoba menulis ke pipa, proses saat ini akan memblokir sampai seseorang akan membaca data di sisi lain pipa. Jika Anda ingin membaca dari sebuah pipa proses akan memblokir sampai seseorang akan menulis data ke pipa. The sed
loop dalam contoh di atas tidak apa-apa (tidur) sampai Anda lakukan echo
.
Untuk situasi khusus Anda, Anda cukup mengkonfigurasi aplikasi Anda untuk menulis pesan log ke file fifo. Jika Anda tidak dapat mengonfigurasinya - cukup hapus file log asli dan buat file fifo. Tetapi perhatikan lagi bahwa jika sed
loop akan mati karena suatu alasan - program Anda akan diblokir saat mencoba ke write
file sampai seseorang akan read
dari fifo.
Manfaatnya adalah cap waktu saat ini dievaluasi dan dilampirkan ke pesan ketika program menulisnya ke file.
tailf
Untuk membuat penulisan ke log dan pemrosesan lebih mandiri, Anda dapat menggunakan dua file biasa tailf
. Aplikasi akan menulis pesan ke file mentah dan proses lain membaca baris baru (ikuti untuk menulis secara tidak sinkron) dan memproses data dengan menulis ke file kedua.
Mari kita ambil contoh:
# 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
Bagaimana itu bekerja:
Jalankan tailf
proses yang akan mengikuti tulis bar.raw.log
dan cetak ke output standar yang dialihkan ke while read ... echo
loop tak terbatas . Loop ini melakukan dua tindakan: membaca data dari input standar ke variabel buffer yang disebut line
dan kemudian menulis timestamp yang dihasilkan dengan data buffered berikut ke bar.log
.
Tulis beberapa pesan ke bar.raw.log
. Anda harus melakukan ini di jendela terminal terpisah karena yang pertama akan ditempati oleh tailf
yang akan mengikuti penulisan dan melakukan tugasnya. Cukup sederhana.
Pro adalah aplikasi Anda tidak akan diblokir jika Anda membunuh tailf
. Kontra adalah cap waktu yang kurang akurat dan duplikat file log.
tailf
, menambahkan cara yang tepat untuk menggunakannya. Sebenarnya cara dengan tailf
tampaknya lebih elegan, tetapi saya meninggalkan cara fifo dengan harapan itu akan bermanfaat bagi seseorang.
Anda dapat menggunakan ts
skrip perl dari moreutils
:
$ echo test | ts %F-%H:%M:%.S
2012-11-20-13:34:10.731562 test
Dimodifikasi dari jawaban Dmitry Vasilyanov.
Dalam skrip bash, Anda dapat mengarahkan dan membungkus output dengan timestamp baris demi baris dengan cepat.
Kapan harus menggunakan:
tailf
untuk file log seperti kata Dmitry Vasilyanov.Contoh bernama 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"
Dan hasilnya:
$ bash foo.sh
$ cat foo.log
May 12 20:04:11 foo
May 12 20:04:12 bar
May 12 20:04:13 foobar
Bagaimana itu bekerja
exec &>
Redirect stdout dan stderr ke tempat yang sama>( ... )
output pipa ke perintah dalam asinkronSebagai contoh:
stempel waktu pipa dan masuk ke file
#!/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
Atau cetak stempel waktu dan masuk ke stdout
#!/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
lalu simpan dalam /etc/crontab
pengaturan
* * * * * root /path-to-script/foo.sh >> /path-to-log-file/foo.log
Saya menggunakan ts
cara ini untuk mendapatkan entri dengan cap waktu di log kesalahan untuk skrip yang saya gunakan untuk membuat Cacti diisi dengan statistik host jarak jauh.
Untuk menguji Cacti saya gunakan rand
untuk menambahkan beberapa nilai acak yang saya gunakan untuk grafik suhu untuk memonitor suhu sistem saya.
Pushmonstats.sh adalah skrip yang mengumpulkan statistik suhu sistem PC saya dan mengirimkannya ke Raspberry Pi tempat Cacti beroperasi. Beberapa waktu lalu, jaringannya macet. Saya hanya mendapat SSH time out di log kesalahan saya. Sayangnya, tidak ada entri waktu dalam log itu. Saya tidak tahu cara menambahkan cap waktu ke entri log. Jadi, setelah beberapa pencarian di Internet, saya menemukan posting ini dan inilah yang saya gunakan ts
.
Untuk mengujinya, saya menggunakan opsi yang tidak diketahui rand
. Yang memberi kesalahan pada stderr. Untuk menangkapnya, saya mengarahkannya ke file sementara. Kemudian saya menggunakan cat untuk menunjukkan isi file dan mengirimnya ke pipa ts
, menambahkan format waktu yang saya temukan di posting ini dan akhirnya log ke file kesalahan. Lalu saya menghapus isi dari file sementara, kalau tidak saya mendapatkan entri ganda untuk kesalahan yang sama.
Crontab:
* * * * * /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
Ini memberikan yang berikut di log kesalahan saya:
2014-03-22-19:17:53.823720 rand: unknown option -- '-l'
Mungkin ini bukan cara yang sangat elegan untuk melakukannya, tetapi berhasil. Saya bertanya-tanya apakah ada pendekatan yang lebih elegan untuk itu.