it-swarm-vi.com

Cách tốt nhất để theo dõi nhật ký và thực thi lệnh khi một số văn bản xuất hiện trong nhật ký

Tôi có một nhật ký máy chủ xuất ra một dòng văn bản cụ thể vào tệp nhật ký của nó khi máy chủ hoạt động. Tôi muốn thực thi một lệnh khi máy chủ hoạt động, và do đó thực hiện một số việc như sau:

tail -f /path/to/serverLog | grep "server is up" ...(now, e.g., wget on server)?

Cách tốt nhất để làm việc này là gì?

56
jonderry

Một cách đơn giản sẽ là awk.

tail -f /path/to/serverLog | awk '
                    /Printer is on fire!/ { system("shutdown -h now") }
                    /new USB high speed/  { system("echo \"New USB\" | mail admin") }'

Và vâng, cả hai đều là tin nhắn thực từ nhật ký kernel. Perl có thể thanh lịch hơn một chút để sử dụng cho việc này và cũng có thể thay thế nhu cầu về đuôi. Nếu sử dụng Perl, nó sẽ trông giống như thế này:

open(my $fd, "<", "/path/to/serverLog") or die "Can't open log";
while(1) {
    if(eof $fd) {
        sleep 1;
        $fd->clearerr;
        next;
    }
    my $line = <$fd>;
    chomp($line);
    if($line =~ /Printer is on fire!/) {
        system("shutdown -h now");
    } elsif($line =~ /new USB high speed/) {
        system("echo \"New USB\" | mail admin");
    }
}
36
penguin359

Nếu bạn chỉ tìm kiếm một khả năng và muốn chủ yếu ở trong Shell thay vì sử dụng awk hoặc Perl, bạn có thể làm điều gì đó như:

tail -F /path/to/serverLog | 
grep --line-buffered 'server is up' | 
while read ; do my_command ; done

... sẽ chạy my_command mỗi khi "máy chủ hoạt động" xuất hiện trong tệp nhật ký. Đối với nhiều khả năng, bạn có thể bỏ grep và thay vào đó sử dụng case trong while.

Thủ đô -F nói với tail để xem tệp nhật ký được xoay; tức là. nếu tệp hiện tại được đổi tên và một tệp khác có cùng tên sẽ thay thế, tail sẽ chuyển sang tệp mới.

Các --line-buffered tùy chọn yêu cầu grep xóa bộ đệm của nó sau mỗi dòng; nếu không thì, my_command có thể không đạt được một cách kịp thời (giả sử các bản ghi có các dòng có kích thước hợp lý).

20
Jander

Câu hỏi này dường như đã được trả lời, nhưng tôi nghĩ có một giải pháp tốt hơn.

Thay vì tail | whatever, Tôi nghĩ những gì bạn thực sự muốn là swatch. Swatch là một chương trình được thiết kế rõ ràng để thực hiện những gì bạn yêu cầu, xem tệp nhật ký và thực hiện các hành động dựa trên các dòng nhật ký. Sử dụng tail|foo sẽ yêu cầu bạn có một thiết bị đầu cuối tích cực chạy để làm điều này. Swatch mặt khác chạy như một daemon và sẽ luôn luôn xem nhật ký của bạn. Swatch có sẵn trong tất cả các bản phân phối Linux,

Tôi khuyến khích bạn thử nó. Mặc dù bạn có thể đóng đinh vào mặt sau của tuốc nơ vít không có nghĩa là bạn nên làm vậy.

Hướng dẫn 30 giây tốt nhất về swatch tôi có thể tìm thấy là tại đây .

14
bahamat

Điều kỳ lạ là không ai đề cập đến tiện ích multitail có chức năng vượt trội này. Một trong những ví dụ sử dụng:

Hiển thị đầu ra của lệnh ping và nếu nó hiển thị thời gian chờ, hãy gửi tin nhắn cho tất cả người dùng hiện đang đăng nhập

multitail -ex timeout "echo timeout | wall" -l "ping 192.168.0.1"

Xem thêm ví dụ khác of multitail cách sử dụng.

11
php-coder

bash có thể tự mình làm công việc

Hãy xem nó đơn giản và dễ đọc như thế nào:

mylog() {
    echo >>/path/to/myscriptLog "[email protected]"
}

while read line;do
    case "$line" in
        *"Printer on fire"* )
            mylog Halting immediately
            shutdown -h now
            ;;
        *DHCPREQUEST* )
            [[ "$line" =~ DHCPREQUEST\ for\ ([^\ ]*)\  ]]
            mylog Incomming or refresh for ${BASH_REMATCH[1]}
            $HOME/SomethingWithNewClient ${BASH_REMATCH[1]}
            ;;
        * )
            mylog "untrapped entry: $line"
            ;;
    esac
  done < <(tail -f /path/to/logfile)

Mặc dù bạn không sử dụng regex của bash, nhưng điều này có thể rất nhanh!

Nhưng bash + sed là một song song rất hiệu quả và thú vị

Nhưng đối với máy chủ tải cao và như tôi thích sed vì nó rất nhanh và rất có thể mở rộng, tôi thường sử dụng điều này:

while read event target lost ; do
    case $event in
        NEW )
            ip2int $target intTarget
            ((count[intTarget]++))
        ...

    esac
done < <(tail -f /path/logfile | sed -une '
  s/^.*New incom.*from ip \([0-9.]\+\) .*$/NEW \1/p;
  s/^.*Auth.*ip \([0-9.]\+\) failed./FAIL \1/p;
  ...
')
8
F. Hauri

Đó là cách tôi bắt đầu làm điều này quá nhưng đã trở nên tinh vi hơn nhiều với nó. Một vài điều cần quan tâm:

  1. Nếu đuôi của nhật ký đã chứa "máy chủ hoạt động".
  2. Tự động kết thúc quá trình đuôi khi nó được tìm thấy.

Tôi sử dụng một cái gì đó dọc theo dòng này:

RELEASE=/tmp/${RANDOM}$$
(
  trap 'false' 1
  trap "rm -f ${RELEASE}" 0
  while ! [ -s ${RELEASE} ]; do sleep 3; done
  # You can put code here if you want to do something
  # once the grep succeeds.
) & wait_pid=$!
tail --pid=${wait_pid} -F /path/to/serverLog \
| sed "1,10d" \
| grep "server is up" > ${RELEASE}

Nó hoạt động bằng cách giữ tail mở cho đến khi ${RELEASE} tập tin chứa dữ liệu.

Khi grep thành công:

  1. ghi đầu ra vào ${RELEASE} mà sẽ
  2. chấm dứt ${wait_pid} xử lý
  3. thoát khỏi tail

Lưu ý: sed có thể phức tạp hơn để thực sự xác định số lượng dòng tail sẽ tạo khi khởi động và xóa số đó. Nhưng nói chung, nó là 10.

6
nix