it-swarm-id.com

Cara terbaik untuk mengikuti log dan menjalankan perintah ketika beberapa teks muncul di log

Saya memiliki log server yang menampilkan baris teks tertentu ke file log-nya ketika server habis. Saya ingin menjalankan perintah setelah server menyala, dan karenanya lakukan sesuatu seperti berikut:

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

Apa cara terbaik untuk melakukan ini?

56
jonderry

Cara sederhana akan menjadi aneh.

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

Dan ya, keduanya adalah pesan nyata dari log kernel. Perl mungkin sedikit lebih elegan untuk digunakan untuk ini dan juga dapat menggantikan kebutuhan akan ekor. Jika menggunakan Perl, akan terlihat seperti ini:

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

Jika Anda hanya mencari satu kemungkinan dan ingin tetap sebagian besar di Shell daripada menggunakan awk atau Perl, Anda dapat melakukan sesuatu seperti:

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

... yang akan berjalan my_command setiap kali "server habis" muncul di file log. Untuk beberapa kemungkinan, Anda mungkin dapat melepaskan grep dan sebagai gantinya menggunakan case di dalam while.

Ibukota -F memberitahu tail untuk menonton file log diputar; i.e. jika file saat ini diganti namanya dan file lain dengan nama yang sama menggantikannya, tail akan beralih ke file baru.

--line-buffered pilihan memberitahu grep untuk menyiram buffernya setelah setiap baris; jika tidak, my_command mungkin tidak dapat dijangkau secara tepat waktu (dengan asumsi log memiliki garis berukuran cukup).

20
Jander

Pertanyaan ini tampaknya sudah dijawab, tetapi saya pikir ada solusi yang lebih baik.

Daripada tail | whatever, Saya pikir yang Anda inginkan adalah swatch. Swatch adalah program yang dirancang secara eksplisit untuk melakukan apa yang Anda minta, menonton file log, dan mengeksekusi tindakan berdasarkan baris log. Menggunakan tail|foo akan mengharuskan Anda memiliki terminal yang aktif berjalan untuk melakukan ini. Swatch di sisi lain berjalan sebagai daemon dan akan selalu mengawasi log Anda. Swatch tersedia di semua distro Linux,

Saya mendorong Anda untuk mencobanya. Meskipun Anda dapat menumbuk paku dengan sisi belakang obeng tidak berarti Anda harus melakukannya.

Tutorial 30 detik terbaik tentang carikan yang bisa saya temukan adalah di sini .

14
bahamat

Sungguh aneh bahwa tidak ada yang menyebutkan tentang multitail utilitas yang memiliki fungsi ini di luar kotak. Salah satu contoh penggunaan:

Tampilkan output dari perintah ping dan jika itu menampilkan batas waktu, kirim pesan ke semua pengguna yang saat ini masuk

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

Lihat juga contoh lain dari multitail penggunaan.

11
php-coder

bash bisa melakukan pekerjaan sendiri

Mari kita lihat betapa sederhananya dan mudah dibaca:

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)

Meskipun Anda tidak menggunakan regex bash, ini bisa tetap sangat cepat!

Tapi bash + sed adalah tandem yang sangat efisien dan menarik

Tetapi untuk server dengan beban tinggi, dan seperti yang saya suka sed karena sangat cepat dan sangat terukur, saya sering menggunakan ini:

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

Begitulah cara saya mulai melakukan ini, tetapi menjadi jauh lebih canggih dengannya. Beberapa hal yang perlu diperhatikan:

  1. Jika ekor log sudah berisi "server sudah habis".
  2. Secara otomatis mengakhiri proses ekor setelah ditemukan.

Saya menggunakan sesuatu seperti ini:

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}

Ia bekerja dengan menahan tail terbuka sampai ${RELEASE} file berisi data.

Setelah grep berhasil:

  1. tulis hasilnya ke ${RELEASE} yang mana akan
  2. mengakhiri ${wait_pid} proses ke
  3. keluar dari tail

Catatan: sed dapat menjadi lebih canggih untuk benar-benar menentukan jumlah baris tail akan menghasilkan saat startup dan menghapus nomor itu. Tetapi secara umum, ini 10.

6
nix