it-swarm-tr.com

Bir günlüğü takip etmenin ve günlükte bir metin göründüğünde bir komut yürütmenin en iyi yolu

Sunucu kalktığında günlük dosyasına belirli bir metin satırı çıktısı bir sunucu günlüğü var. Sunucu kalktıktan sonra bir komut yürütmek istiyorum ve bu nedenle aşağıdaki gibi bir şey yapmak istiyorum:

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

Bunu yapmanın en iyi yolu nedir?

56
jonderry

Basit bir yol garip olurdu.

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

Ve evet, her ikisi de bir çekirdek kaydından gerçek mesajlar. Perl bunun için biraz daha zarif olabilir ve kuyruk ihtiyacını da değiştirebilir. Perl kullanıyorsanız, şöyle görünecektir:

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

Yalnızca bir olasılık arıyorsanız ve awk veya Perl kullanmak yerine çoğunlukla Kabukta kalmak istiyorsanız, şöyle bir şey yapabilirsiniz:

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

... hangisi my_command günlük dosyasında "sunucu açıldığında" her görüntülendiğinde. Birden çok olasılık için, grep 'ı bırakabilir ve bunun yerine case içinde bir while kullanabilirsiniz.

Başkent -Ftail'ye günlük dosyasının döndürülmesini izlemesini söyler; yani. geçerli dosya yeniden adlandırılır ve aynı ada sahip başka bir dosya yerini alırsa, tail yeni dosyaya geçer.

--line-buffered seçeneği grep 'a her satırdan sonra arabelleğini temizlemesini söyler; aksi takdirde, my_command'e zamanında ulaşılamayabilir (günlüklerin makul boyutta satırları olduğu varsayılarak).

20
Jander

Bu soru zaten cevaplanmış gibi görünüyor, ancak bence daha iyi bir çözüm var.

tail | whatever Yerine, gerçekten istediğiniz şeyin swatch olduğunu düşünüyorum. Swatch, sorduğunuz şeyi yapmak, bir günlük dosyasını izlemek ve günlük satırlarına dayalı eylemleri yürütmek için özel olarak tasarlanmış bir programdır. tail|foo Kullanmak, bunu yapmak için aktif olarak çalışan bir terminalinizin olmasını gerektirir. Swatch ise bir daemon olarak çalışır ve her zaman günlüklerinizi izler. Renk Örneği tüm Linux dağıtımlarında kullanılabilir,

Denemenizi tavsiye ederim. Bir tornavidanın arka tarafı ile bir çivi çakabilmeniz gerekir, yapmanız gerektiği anlamına gelmez.

Bulabildiğim renk örneğiyle ilgili en iyi 30 saniyelik öğretici burada .

14
bahamat

Kimsenin bu işlevselliği kullanıma hazır olan multitail yardımcı programından bahsetmemesi garip. Kullanım örneğinden biri:

Ping komutunun çıktısını gösterme ve zaman aşımı göstermesi durumunda, oturum açmış olan tüm kullanıcılara bir ileti gönderme

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

Ayrıca bkz. başka örnekler /multitail kullanımı.

11
php-coder

bash işi kendi başına yapabilir

Ne kadar basit ve okunabilir olabileceğini görelim:

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)

Bash'ın regex kısmını kullanmasanız da, bu çok hızlı olabilir!

Ama bash + sed çok verimli ve ilginç bir tandem

Ancak yüksek yük sunucusu için ve çok hızlı ve ölçeklenebilir olduğu için sed gibi

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

Ben de böyle yapmaya başladım ama onunla daha sofistike oldum. İlgilenmeniz gereken birkaç şey:

  1. Günlüğün kuyruğu zaten "sunucu açık" içeriyorsa.
  2. Kuyruk işlemini bulunduğunda otomatik olarak sonlandırma.

Bunun çizgileri boyunca bir şey kullanıyorum:

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}

tail tuşunu ${RELEASE} dosya veri içeriyor.

grep başarılı olduğunda:

  1. çıktıyı ${RELEASE} olacak
  2. ${wait_pid} işlem
  3. tail 'den çıkın

Not: sed, başlangıçta üreteceği tail satır sayısını belirlemek ve bu sayıyı kaldırmak için daha karmaşık olabilir. Ama genellikle, 10.

6
nix