Dán dấu thời gian cùng với dòng tệp nhật ký


11

Tôi có một tệp nhật ký và tôi cần nối thêm dấu thời gian cho mỗi dòng khi chúng được thêm vào. Vì vậy, tôi đang tìm kiếm tập lệnh nối thêm dấu thời gian cho từng mục trong dòng nhật ký và có thể chạy như một công việc định kỳ.

Câu trả lời:


18

Con đường chung

$ cat input.log | sed -e "s/^/$(date -R) /" >> output.log

Làm thế nào nó hoạt động:

  1. catđọc tệp được gọi input.logvà chỉ in nó ra luồng đầu ra tiêu chuẩn của nó.

    Thông thường, đầu ra tiêu chuẩn được kết nối với một thiết bị đầu cuối, nhưng tập lệnh nhỏ này chứa |shell để chuyển hướng đầu ra cattiêu chuẩn thành đầu vào tiêu chuẩn của sed.

  2. sedđọc dữ liệu (như cattạo ra nó), xử lý nó (theo kịch bản được cung cấp với -etùy chọn) và sau đó in nó ra đầu ra tiêu chuẩn của nó. Kịch bản "s/^/$(date -R) /"có nghĩa là thay thế mọi bắt đầu của dòng thành một văn bản được tạo bởi date -Rlệnh (cấu trúc chung cho lệnh thay thế là s/pattern/replace/:).

  3. Sau đó, theo >> bashchuyển hướng đầu ra của sedmột tệp được gọi output.log( >có nghĩa là thay thế nội dung tệp và >>có nghĩa là nối vào cuối).

Vấn đề là được $(date -R)đánh giá một lần khi bạn chạy tập lệnh để nó sẽ chèn dấu thời gian hiện tại vào đầu mỗi dòng. Dấu thời gian hiện tại có thể cách xa thời điểm một tin nhắn được tạo. Để tránh điều đó, bạn phải xử lý các tin nhắn khi chúng được ghi vào tệp, không phải với một công việc định kỳ.

VÒI

Chuyển hướng dòng tiêu chuẩn được mô tả ở trên được gọi là đường ống . Bạn có thể chuyển hướng nó không chỉ với |giữa các lệnh trong tập lệnh, mà thông qua một tệp FIFO (còn được gọi là ống ). Một chương trình sẽ ghi vào tệp và chương trình khác sẽ đọc dữ liệu và nhận nó khi gửi lần đầu tiên.

Chọn một ví dụ:

$ 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

Làm thế nào nó hoạt động:

  1. mkfifo tạo ra một đường ống có tên

  2. while true; do sed ... ; donechạy một vòng lặp vô hạn và tại mỗi lần lặp, nó chạy sedvới chuyển hướng foo.log.fifođến đầu vào tiêu chuẩn của nó; sed chặn chờ dữ liệu đầu vào và sau đó xử lý tin nhắn nhận được và in nó sang đầu ra tiêu chuẩn được chuyển hướng đến foo.log.

    Tại thời điểm này, bạn phải mở một cửa sổ thiết bị đầu cuối mới vì vòng lặp chiếm thiết bị đầu cuối hiện tại.

  3. echo ... > foo.log.fifoin một thông điệp đến đầu ra tiêu chuẩn của nó được chuyển hướng đến tệp fifo và sednhận nó và xử lý và ghi vào một tệp thông thường.

Lưu ý quan trọng là fifo giống như bất kỳ đường ống nào khác không có ý nghĩa nếu một trong các mặt của nó không được kết nối với bất kỳ quá trình. Nếu bạn cố gắng ghi vào một đường ống, quy trình hiện tại sẽ chặn cho đến khi ai đó đọc dữ liệu ở phía bên kia của đường ống. Nếu bạn muốn đọc từ một đường ống, quy trình sẽ chặn cho đến khi ai đó sẽ ghi dữ liệu vào đường ống. Các sedvòng lặp trong ví dụ trên không có gì (ngủ) cho đến khi bạn làm echo.

Đối với tình huống cụ thể của bạn, bạn chỉ cần cấu hình ứng dụng của mình để viết thông điệp tường trình vào tệp fifo. Nếu bạn không thể định cấu hình nó - chỉ cần xóa tệp nhật ký gốc và tạo tệp fifo. Nhưng lưu ý một lần nữa rằng nếu sedvòng lặp sẽ chết vì một số lý do - chương trình của bạn sẽ bị chặn khi cố gắng truy writecập tệp cho đến khi có ai đó readtừ fifo.

Lợi ích là dấu thời gian hiện tại được đánh giá và đính kèm vào một thông báo khi chương trình ghi nó vào tệp.

Xử lý không đồng bộ với tailf

Để ghi vào nhật ký và xử lý độc lập hơn, bạn có thể sử dụng hai tệp thông thường với tailf. Một ứng dụng sẽ viết tin nhắn vào một tệp thô và quá trình khác đọc các dòng mới (làm theo để ghi không đồng bộ) và xử lý dữ liệu bằng cách ghi vào tệp thứ hai.

Hãy lấy một ví dụ:

# 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

Làm thế nào nó hoạt động:

  1. Chạy tailftiến trình sẽ theo ghi bar.raw.logvà in chúng thành đầu ra tiêu chuẩn được chuyển hướng đến while read ... echovòng lặp vô hạn . Vòng lặp này thực hiện hai hành động: đọc dữ liệu từ đầu vào tiêu chuẩn đến một biến đệm được gọi linevà sau đó ghi dấu thời gian được tạo với dữ liệu được đệm sau đây vào bar.log.

  2. Viết một số tin nhắn cho bar.raw.log. Bạn phải làm điều này trong một cửa sổ đầu cuối riêng biệt bởi vì cái đầu tiên sẽ bị chiếm giữ bởi tailfnó sẽ theo sau ghi và thực hiện công việc của nó. Khá đơn giản.

Ưu điểm là ứng dụng của bạn sẽ không chặn nếu bạn giết tailf. Nhược điểm là dấu thời gian ít chính xác hơn và sao chép các tệp nhật ký.


Cảm ơn bạn. Có vẻ như rất thích hợp cho việc sử dụng. Chương trình của tôi đã ghi vào nhật ký file.txt nhưng tệp này cần được chuyển hướng đến foo.log.fifo. Nhưng thực hiện $ tailf file.txt> foo.log.fifo bị treo ! Vậy làm thế nào tôi có thể chuyển hướng nội dung của mình trong một tệp nhật ký cập nhật sang foo.log.fifo này để nó có thể nối thêm thời gian.
Kratos

Chỉ cần cải thiện câu trả lời. Giải thích tại sao fifo chặn của bạn tailf, thêm cách sử dụng đúng. Trên thực tế, con đường với tailfdường như thanh lịch hơn, nhưng tôi đã nhảy theo con đường fifo với hy vọng nó sẽ hữu ích cho ai đó.
Dmitry Vasilyanov

Sử dụng câu trả lời sed của bạn để chú thích đầu ra vmstat mang lại dấu thời gian không thay đổi, vmstat 1 | sed -e "s / ^ / $ (ngày -R) /"
ChuckCottrill


2

Được sửa đổi từ câu trả lời của Dmitry Vasilyanov.

Trong bash script, bạn có thể chuyển hướng và kết thúc đầu ra với dấu thời gian theo từng dòng một.

Khi nào nên sử dụng:

  • Đối với các lệnh bash script, chèn dòng trước script chính
  • Đối với các công việc không phải là tập lệnh, hãy tạo một tập lệnh để gọi chương trình.
  • Đối với các dịch vụ được kiểm soát bởi hệ thống, tốt hơn là sử dụng tailftệp nhật ký như Dmitry Vasilyanov nói.

Một ví dụ có tên 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"

Và kết quả:

$ bash foo.sh
$ cat foo.log
May 12 20:04:11 foo
May 12 20:04:12 bar
May 12 20:04:13 foobar

Làm thế nào nó hoạt động

  1. exec &> Chuyển hướng stdout và stderr đến cùng một nơi
  2. >( ... ) đầu ra ống cho một lệnh bên trong không đồng bộ
  3. Phần còn lại hoạt động khi Dmitry Vasilyanov mở rộng.

Ví dụ:

  • dấu thời gian ống và đăng nhập vào tập tin

    #!/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
    
  • Hoặc in dấu thời gian và đăng nhập vào thiết bị xuất chuẩn

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

    sau đó lưu chúng trong /etc/crontabcài đặt

    * * * * * root /path-to-script/foo.sh >> /path-to-log-file/foo.log
    

1

Tôi đã sử dụng tscách này để có được một mục có dấu thời gian trong nhật ký lỗi cho tập lệnh mà tôi sử dụng để đưa Cacti chứa đầy các số liệu thống kê của máy chủ từ xa.

Để kiểm tra Cacti tôi sử dụng randđể thêm một số giá trị ngẫu nhiên mà tôi sử dụng cho biểu đồ nhiệt độ để theo dõi nhiệt độ hệ thống của mình.

Pushmonstats.sh là một tập lệnh thu thập số liệu thống kê nhiệt độ hệ thống của PC của tôi và gửi nó đến Raspberry Pi mà Cacti chạy. Một thời gian trước, mạng đã bị kẹt. Tôi chỉ nhận được thời gian SSH trong nhật ký lỗi của tôi. Thật không may, không có mục thời gian trong nhật ký đó. Tôi không biết cách thêm dấu thời gian vào mục nhật ký. Vì vậy, sau một số tìm kiếm trên Internet, tôi tình cờ thấy bài đăng này và đây là những gì tôi đã sử dụng ts.

Để kiểm tra nó, tôi đã sử dụng một tùy chọn không xác định rand. Mà đã đưa ra một lỗi cho stderr. Để chụp nó, tôi chuyển hướng nó đến một tập tin tạm thời. Sau đó, tôi sử dụng cat để hiển thị nội dung của tệp và chuyển nó sang ts, thêm định dạng thời gian mà tôi tìm thấy trên bài đăng này và cuối cùng đăng nhập vào tệp lỗi. Sau đó, tôi xóa nội dung của tệp tạm thời, nếu không tôi nhận được hai mục nhập cho cùng một lỗi.

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

Điều này đưa ra những điều sau đây trong nhật ký lỗi của tôi:

2014-03-22-19:17:53.823720 rand: unknown option -- '-l'

Có thể đây không phải là một cách rất thanh lịch để làm điều đó, nhưng nó hoạt động. Tôi tự hỏi nếu có một cách tiếp cận thanh lịch hơn cho nó.

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.