Bagaimana cara menambahkan stempel waktu ke bash skrip log?

94

Saya memiliki skrip yang terus berjalan yang saya hasilkan ke file log:

script.sh >> /var/log/logfile

Saya ingin menambahkan cap waktu sebelum setiap baris yang ditambahkan ke log. Suka:

Sat Sep 10 21:33:06 UTC 2011 The server has booted up.  Hmmph.

Apakah ada jujitsu yang bisa saya gunakan?

Antonius Bloch
sumber
2
Lihat pencarian ini. serverfault.com/questions/80749/… . Jawaban pasangan akan berlaku di sini.
Zoredache
Untuk solusi awk / gawk lihat: stackoverflow.com/questions/21564/…
Pengguna
Berikut ini adalah implementasi komprehensif pencatatan untuk bash: github.com/codeforester/base/blob/master/lib/stdlib.sh
codeforester

Jawaban:

88

Anda dapat menyalurkan output skrip melalui loop yang mengawali tanggal dan waktu saat ini:

./script.sh | while IFS= read -r line; do printf '%s %s\n' "$(date)" "$line"; done >>/var/log/logfile

Jika Anda akan sering menggunakan ini, mudah untuk membuat fungsi bash untuk menangani loop:

adddate() {
    while IFS= read -r line; do
        printf '%s %s\n' "$(date)" "$line";
    done
}

./thisscript.sh | adddate >>/var/log/logfile
./thatscript.sh | adddate >>/var/log/logfile
./theotherscript.sh | adddate >>/var/log/logfile
Gordon Davisson
sumber
3
@Nils itu adalah trik untuk mencegah readpemangkasan spasi putih di awal dan dan dari garis. Ini menetapkan IFS (Pemisah Bidang Internal bash, pada dasarnya daftar karakter spasi) untuk mengosongkan untuk readperintah.
Gordon Davisson
2
... dan -r mengabaikan karakter pelarian "\". Ini harus benar-benar berfungsi dalam semua kasus - petak skrip yang hebat.
Nils
7
@Nils itu tidak sepenuhnya antipeluru, karena beberapa implementasi echomenafsirkan urutan melarikan diri. Jika Anda benar - benar ingin itu tidak mengacaukan konten (selain menambahkan tanggal), ganti echoperintah denganprintf "%s %s\n" "$(date)" "$line"
Gordon Davisson
4
Anda mungkin tertarik pada tanggal / cap waktu yang sesuai dengan ISO-8601 : date -u +"%Y-%m-%dT%H:%M:%SZ"atau mungkin lebih cantik date +"%Y-%m-%d %T".
Pablo A
1
sementara skrip ini berfungsi seperti yang diharapkan, skrip ini memunculkan proses baru (mengeksekusi date) untuk setiap baris log, yang dapat menjadi kelemahan besar tergantung pada mesin Anda dan jumlah log. Saya lebih suka menyarankan untuk menggunakan tsjika tersedia, lihat jawaban dari @willem
Michael Schaefers
56

Lihat tsdari moreutilspaket Ubuntu :

command | ts

Atau, jika $commandbuffering otomatis (memerlukan expect-devpaket):

unbuffer command | ts
Willem
sumber
18

The tanggal perintah akan memberikan informasi yang

date -u
Sat Sep 10 22:39:24 UTC 2011

jadi kamu bisa

echo $(date -u) "Some message or other"

itukah yang kamu inginkan?

user9517
sumber
Menggunakan perintah tanggal adalah jenis yang ada dalam pikiran saya, tetapi saya tidak bisa menambahkannya ke skrip itu sendiri, jadi apa yang saya cari adalah cara untuk mengubah baris ini: "script.sh >> / var / log / logfile "untuk menambahkan tanggal.
Antonius Bloch
Dalam hal itu arahkan output skrip Anda ke pipa bernama dan memiliki daemon mendengarkan output yang mengambil output skrip dan menambahkan tanggal sebelum menulisnya ke file log. Anda mungkin dapat memodifikasi skrip yang saya tulis di sini untuk melakukan ini. Saya akan melakukannya karena itu menarik minat saya tetapi ini sudah terlambat di Inggris dan saya akan memulai lebih awal besok.
user9517
12

Anda bisa mengumandangkan output perintah ke file log. yaitu,

echo "`date -u` `./script.sh`" >> /var/log/logfile

Ini benar-benar bekerja :)

Contoh:

[sparx@E1]$ ./script.sh 
Hello Worldy
[sparx@E1]$ echo "`date -u` `./script.sh`" >> logfile.txt
[sparx@E1]$ cat logfile.txt 
Mon Sep 12 20:18:28 UTC 2011 Hello Worldy
[sparx@E1]$ 
SparX
sumber
Hmm tidak bekerja untuk saya.
Antonius Bloch
Apa yang Anda dapatkan ketika Anda menjalankan perintah?
SparX
8
Itu menempatkan cap waktu sebelum seluruh output dari '' ./script.sh '', bukan sebelum setiap baris.
clacke
8

Buat config.shfile

#!/usr/bin/env bash
LOGFILE="/path/to/log.log"
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`

Ketika Anda perlu mengirim untuk menggunakan file log

#!/usr/bin/env bash
source /path/to/config.sh

echo "$TIMESTAMP Say what you are doing" >> $LOGFILE

do_what_you_want >> $LOGFILE

File log akan terlihat seperti

2013-02-03 18:22:30 Say what you are doing

Jadi akan mudah untuk mengurutkan berdasarkan tanggal

scls
sumber
8
'' Config.sh '' Anda akan menjalankan '' date '' tepat sekali, pada '' sumber ... / config.sh ''.
clacke
5

Maksud Anda seperti:

(date && script.sh) >> /var/log/logfile
cjc
sumber
Ya Tuhan, orang-orang, semua orang melakukan penggantian centang kembali, bernama pipa, dll. Cukup lampirkan kedua perintah tanggal dan script di parens! Orang yang memiliki fungsi memiliki kasus yang sah jika ada keluaran multi-line dan log harus terlihat cantik dengan tanggal pada setiap baris, tetapi sebagian besar solusi ini adalah pembunuhan berlebihan yang tidak menggunakan shell semantik.
cjc
8
Itu hanya akan menambahkan stempel waktu sekali per eksekusi script.sh. OP membutuhkan cap waktu per baris.
Dave Forgac
1
walaupun ini tidak menjawab pertanyaan OP, saya masih menemukan info yang berguna.
Pengguna
4

Coba ini

timestamp()
{
 date +"%Y-%m-%d %T"
}

Sebut fungsi cap waktu ini di setiap perintah gema:

echo "$(timestamp): write your log here" >> /var/log/<logfile>.log
Sanjay Yadav
sumber
@ shazbot: Terima kasih sudah mengedit, itu kesalahan ketik, saya tidak menyadarinya.
Sanjay Yadav
4

Jawaban yang diterima https://serverfault.com/a/310104 bisa agak lambat, jika banyak baris harus diproses, dengan overhead memulai dateproses yang memungkinkan sekitar 50 baris per detik di Ubuntu, dan hanya sekitar 10 -20 di Cygwin.

Ketika bashdapat diasumsikan alternatif yang lebih cepat adalah printfbuiltin dengan penentu %(...)Tformatnya. Membandingkan

>> while true; do date; done | uniq -c
     47 Wed Nov  9 23:17:18 STD 2016
     56 Wed Nov  9 23:17:19 STD 2016
     55 Wed Nov  9 23:17:20 STD 2016
     51 Wed Nov  9 23:17:21 STD 2016
     50 Wed Nov  9 23:17:22 STD 2016

>> while true; do printf '%(%F %T)T\n'; done | uniq -c
  20300 2016-11-09 23:17:56
  31767 2016-11-09 23:17:57
  32109 2016-11-09 23:17:58
  31036 2016-11-09 23:17:59
  30714 2016-11-09 23:18:00
kdb
sumber
1

Anda mungkin memperhatikan bahwa awk berjalan cepat,

gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }'

yes |head -5000000 |gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }' |uniq -c
 461592 [2017-02-28 19:46:44] y
 488555 [2017-02-28 19:46:45] y
 491205 [2017-02-28 19:46:46] y
 498568 [2017-02-28 19:46:47] y
 502605 [2017-02-28 19:46:48] y
 494048 [2017-02-28 19:46:49] y
 493299 [2017-02-28 19:46:50] y
 498005 [2017-02-28 19:46:51] y
 502916 [2017-02-28 19:46:52] y
 495550 [2017-02-28 19:46:53] y
  73657 [2017-02-28 19:46:54] y

Tapi, sed berjalan lebih cepat,

sed -e "s/^/$(date -R) /"

yes |head -5000000 |sed -e "s/^/$(date -R) /" |uniq -c
5000000 Tue, 28 Feb 2017 19:57:00 -0500 y

Namun, pada pemeriksaan lebih dekat, mengatur sepertinya tidak mengubah waktu,

vmstat 1 | sed -e "s/^/$(date -R) /"
ChuckCottrill
sumber
1
ini karena itu bash mengevaluasi "s/^/$(date -R) /"dan menjalankan tanggal sekali sebelum sed. Sed melewati string statis.
Evan Benn
Bash polos: yes | head -5000000 | while read line; do echo $((SECONDS)); done | uniq -cyang jauh lebih lambat daripada melongo. tsutilitas memiliki kinerja yang mirip dengan bash loop.
akhan
Perl: yes |head -5000000 |perl -ne 'print localtime."\t".$_' |uniq -cyang sedikit lebih lambat dari awk.
akhan
1

Di bawah ini adalah isi file log saya

xiongyu@ubuntu:~/search_start_sh$ tail restart_scrape.log 

2017-08-25 21:10:09 scrape_yy_news_main.py got down, now I will restart it

2017-08-25 21:10:09 check_yy_news_warn.py got down, now I will restart it

2017-08-25 21:14:53 scrape_yy_news_main.py got down, now I will restart it

beberapa konten shell saya adalah seperti di bawah ini

log_file="restart_scrape.log"
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`
echo "$TIMESTAMP $search_py_file got down, now I will restart it" | tee -a $log_file 
Jayhello
sumber
1

Script ini mencetak output dalam terminal dan juga menyimpan dalam file log.

#!/bin/bash

MY_LOG=/var/log/output.log

echolog(){
    if [ $# -eq 0 ]
    then cat - | while read -r message
        do
                echo "$(date +"[%F %T %Z] -") $message" | tee -a $MY_LOG
            done
    else
        echo -n "$(date +'[%F %T %Z]') - " | tee -a $MY_LOG
        echo $* | tee -a $MY_LOG
    fi
}

echolog "My script is starting"
whoami | echolog

Output sampel:

[2017-10-29 19:46:36 UTC] - My script is starting
[2017-10-29 19:46:36 UTC] - root
Seff
sumber
perintah kencan pertama Anda harus menggunakan tanda kutip tunggal, bukan tanda kutip ganda.
Jason Harrison
1

Pilihan lain adalah mengatur fungsi untuk memanggil setiap kali Anda ingin menampilkan data dalam kode Anda:

PrintLog(){
  information=$1
  logFile=$2
  echo "$(date +'%Y-%m-%d %H:%M:%S" $information} >> $logFile
}

Kemudian setiap kali dalam kode Anda, Anda ingin mengirimnya ke panggilan file log

PrintLog "Stuff you want to add..." ${LogFileVariable}

Peasy mudah ....

Josh Williams
sumber
0

Pipa "sed":

script.sh | sed "s|^|$('date') :: |" >> /var/log/logfile
Eubide
sumber
Adapun jawaban lainnya, ini hanya kencan berjalan bash sekali. sed tidak memperbarui waktu per baris.
Evan Benn