Làm cách nào để thêm dấu thời gian vào bash script log?


94

Tôi có một tập lệnh chạy liên tục mà tôi xuất ra một tệp nhật ký:

script.sh >> /var/log/logfile

Tôi muốn thêm dấu thời gian trước mỗi dòng được thêm vào nhật ký. Như:

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

Có bất kỳ jujitsu tôi có thể sử dụng?


2
Xem nhiệm vụ này. serverfault.com/questions/80749/ trên . Một câu trả lời sẽ được áp dụng ở đây.
Zoredache

Để biết giải pháp awk / gawk, hãy xem: stackoverflow.com/questions/21564/iêu
Người dùng

Dưới đây là một triển khai toàn diện về đăng nhập cho bash: github.com/codeforester/base/blob/master/lib/stdlib.sh
codeforester

Câu trả lời:


88

Bạn có thể dẫn đầu ra của tập lệnh thông qua một vòng lặp tiền tố ngày và giờ hiện tại:

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

Nếu bạn sẽ sử dụng nhiều thứ này, thật dễ dàng để tạo một hàm bash để xử lý vòng lặp:

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

3
@ Không phải là một mẹo để ngăn chặn readkhoảng trắng ở đầu và của dòng. Nó đặt IFS (Dấu tách trường nội bộ của bash, về cơ bản là một danh sách các ký tự khoảng trắng) để trống cho readlệnh.
Gordon Davisson

2
... và -r bỏ qua ký tự thoát "\". Điều này thực sự sẽ làm việc trong tất cả các trường hợp - pice tuyệt vời của kịch bản.
Nils

7
@ Không có khả năng chống đạn hoàn toàn, vì một số triển khai echogiải thích trình tự thoát. Nếu bạn thực sự muốn nó không gây rối với nội dung (ngoài việc thêm ngày), hãy thay thế echolệnh bằngprintf "%s %s\n" "$(date)" "$line"
Gordon Davisson

4
Bạn có thể quan tâm đến ngày / dấu thời gian tuân thủ ISO-8601 : date -u +"%Y-%m-%dT%H:%M:%SZ"hoặc có thể đẹp hơn date +"%Y-%m-%d %T".
Pablo A

1
trong khi tập lệnh này hoạt động như mong đợi, nó tạo ra một quy trình mới (thực thi date) cho mỗi dòng nhật ký, đây có thể là một nhược điểm lớn tùy thuộc vào máy của bạn và số lượng nhật ký. Tôi muốn đề nghị sử dụng tsnếu có sẵn, hãy xem câu trả lời từ @willem
Michael Schaefers

56

Xem tstừ moreutilsgói Ubuntu :

command | ts

Hoặc, nếu $commandkhông đệm tự động (yêu cầu expect-devgói):

unbuffer command | ts

18

Lệnh date sẽ cung cấp thông tin đó

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

để bạn có thể

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

Là những gì bạn muốn ?


Sử dụng lệnh date là loại suy nghĩ của tôi, nhưng tôi thực sự không thể thêm nó vào tập lệnh, vì vậy điều tôi đang tìm kiếm là một cách để thay đổi dòng này: "script.sh >> / var / log / logfile "để nối ngày.
Antonius Bloch

Trong trường hợp đó, hãy chuyển hướng đầu ra của tập lệnh của bạn sang một ống có tên và có một daemon lắng nghe đầu ra để lấy đầu ra của tập lệnh và thêm một ngày trước khi ghi nó vào một tệp nhật ký. Bạn có thể sửa đổi kịch bản tôi đã viết ở đây để làm điều này. Tôi sẽ làm điều đó bởi vì nó làm tôi hứng thú nhưng đến muộn ở Anh và tôi sẽ bắt đầu sớm vào ngày mai.
dùng9517

12

Bạn chỉ có thể lặp lại các đầu ra lệnh vào logfile. I E,

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

Nó thật sự có hiệu quả :)

Thí dụ:

[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]$ 

Hmm không làm việc cho tôi.
Antonius Bloch

Bạn nhận được gì khi thực hiện lệnh?
SparX

8
Điều đó đặt dấu thời gian trước toàn bộ đầu ra của '' ./script.sh '', không phải trước mỗi dòng.
clacke

8

Tạo một config.shtập tin

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

Khi bạn cần gửi để sử dụng tệp nhật ký

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

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

do_what_you_want >> $LOGFILE

Tệp nhật ký sẽ trông như

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

Vì vậy, nó sẽ dễ dàng sắp xếp theo ngày


8
'' Config.sh '' của bạn sẽ chạy '' ngày '' chính xác một lần, trên '' nguồn ... / config.sh ''.
clacke

5

Bạn có ý nghĩa như:

(date && script.sh) >> /var/log/logfile

Chúa ơi, mọi người, tất cả mọi người đang thực hiện thay thế đánh dấu, đặt tên ống, v.v. Chỉ cần kèm theo cả lệnh ngày và tập lệnh trong parens! Anh chàng có chức năng này có một trường hợp hợp pháp nếu có đầu ra nhiều dòng và nhật ký cần trông đẹp với ngày trên mỗi dòng, nhưng hầu hết các giải pháp này đều quá mức không sử dụng ngữ nghĩa shell.
cjc

8
Điều đó sẽ chỉ thêm dấu thời gian một lần cho mỗi lần thực hiện script.sh. OP cần dấu thời gian trên mỗi dòng.
Dave Forgac

1
Mặc dù điều này không trả lời câu hỏi OP nhưng tôi vẫn thấy nó là thông tin hữu ích.
Người dùng

4

Thử đi

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

Gọi hàm dấu thời gian này trong mỗi lệnh echo:

echo "$(timestamp): write your log here" >> /var/log/<logfile>.log

@ shazbot: Cảm ơn bạn đã chỉnh sửa, đó là một lỗi đánh máy, tôi đã không thông báo.
Sanjay Yadav

4

Câu trả lời được chấp nhận https://serverfault.com/a/310104 có thể hơi chậm, nếu phải xử lý nhiều dòng, với chi phí bắt đầu datequá trình cho phép khoảng 50 dòng mỗi giây trong Ubuntu và chỉ khoảng 10 dòng -20 ở Cygwin.

Khi bashcó thể được giả định, một sự thay thế nhanh hơn sẽ là printfnội dung với trình %(...)Txác định định dạng của nó . So sánh

>> 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

1

Bạn có thể lưu ý rằng awk chạy nhanh,

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

Nhưng, sed chạy nhanh hơn nhiều,

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

Tuy nhiên, khi kiểm tra kỹ hơn, thiết lập dường như không thay đổi thời gian,

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

1
điều này là do nó được đánh giá bash "s/^/$(date -R) /"và chạy ngày một lần trước khi sed. Sed được thông qua một chuỗi tĩnh.
Evan Benn

Plain bash: yes | head -5000000 | while read line; do echo $((SECONDS)); done | uniq -cchậm hơn nhiều so với gawk. tstiện ích có hiệu suất tương tự như bash loop.
akhan

Perl: yes |head -5000000 |perl -ne 'print localtime."\t".$_' |uniq -cchậm hơn một chút so với awk.
akhan

1

Dưới đây là nội dung tệp nhật ký của tôi

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

một số nội dung shell của tôi là như dưới đây

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 

1

Kịch bản lệnh này in đầu ra trong thiết bị đầu cuối và cũng lưu trong tệp nhật ký.

#!/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

Đầu ra mẫu:

[2017-10-29 19:46:36 UTC] - My script is starting
[2017-10-29 19:46:36 UTC] - root

lệnh ngày đầu tiên của bạn nên sử dụng dấu ngoặc đơn, không phải dấu ngoặc kép.
Jason Harrison

1

Một tùy chọn khác là thiết lập một chức năng để gọi mỗi lần bạn muốn xuất dữ liệu trong mã của mình:

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

Sau đó, mỗi lần trong mã của bạn, bạn muốn gửi nó đến cuộc gọi tệp nhật ký

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

Dễ như ăn bánh....


0

Ống một "sed":

script.sh | sed "s|^|$('date') :: |" >> /var/log/logfile

Đối với câu trả lời khác, đây chỉ là ngày bash chạy một lần. sed không cập nhật thời gian trên mỗi dòng.
Evan Benn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.