it-swarm-eu.dev

Nejlepší způsob, jak sledovat protokol a provést příkaz, když se v protokolu objeví nějaký text

Mám serverový protokol, který vydá konkrétní řádek textu do jeho logovacího souboru, když je server nahoře. Chci provést příkaz, jakmile je server spuštěn, a proto udělat něco jako následující:

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

Jaký je nejlepší způsob, jak toho dosáhnout?

56
jonderry

Jednoduchý způsob by byl 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") }'

A ano, obě jsou to skutečné zprávy z protokolu jádra. Perl může být o něco elegantnější k použití pro tento a může také nahradit potřebu ocasu. Pokud používáte Perl, bude to vypadat asi takto:

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

Pokud hledáte pouze jednu možnost a chcete zůstat převážně ve skořápce místo použití awk nebo Perl, můžete udělat něco jako:

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

... který poběží my_command pokaždé, když se v souboru protokolu objeví „server je zapnutý“. Pro více možností můžete použít přetažení grep a místo toho použít case v rámci while.

Hlavní město -F řekne tail, aby sledoval rotaci souboru protokolu; tj. Pokud se aktuální soubor přejmenuje a místo něj se objeví jiný soubor se stejným názvem, tail se přepne na nový soubor.

The --line-buffered volba říká grep, aby vyprázdnil svůj buffer po každém řádku; v opačném případě, my_command nemusí být dosaženo včas (za předpokladu, že protokoly mají přiměřeně velké řádky).

20
Jander

Zdá se, že tato otázka již byla zodpovězena, ale myslím, že existuje lepší řešení.

Spíše než tail | whatever, Myslím, že to, co opravdu chcete, je swatch. Swatch je program navržený výslovně pro provádění toho, co požadujete, sledování souboru protokolu a provádění akcí na základě řádků protokolu. Použitím tail|foo bude vyžadovat aktivní terminál, který to provede. Swatch na druhé straně běží jako démon a vždy bude sledovat vaše protokoly. Swatch je k dispozici ve všech distribucích Linuxu,

Doporučuji vám to vyzkoušet. I když můžete vrazit hřebík do zadní strany šroubováku, neznamená to, že byste měli.

Nejlepší 30sekundový tutoriál o vzorcích, který jsem našel, je zde .

14
bahamat

Je zvláštní, že se nikdo nezmínil o obslužném programu multitail, který má tuto funkci již mimo krabici. Jeden z příkladů použití:

Zobrazit výstup příkazu ping a pokud se zobrazí časový limit, pošlete zprávu všem aktuálně přihlášeným uživatelům

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

Viz také další příklady použití multitail.

11
php-coder

bash mohl dělat svou práci sám

Uvidíme, jak jednoduché a čitelné by to mohlo být:

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)

I když nepoužíváte bash's regex, mohlo by to zůstat velmi rychlé!

Ale bash + sed je velmi efektivní a zajímavý tandem

Ale pro server s vysokou zátěží a protože se mi líbí sed, protože je to velmi rychlé a velmi škálovatelné, často používám toto:

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

Tak jsem to začal také dělat, ale díky tomu jsem byl mnohem sofistikovanější. Několik věcí, které je třeba se zabývat:

  1. Pokud již konec protokolu obsahuje „server je nahoře“.
  2. Jakmile je nalezen, automaticky ukončí ocasní proces.

Používám něco v souladu s tímto:

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}

Funguje tak, že podržíte tail otevřené, dokud ${RELEASE} soubor obsahuje data.

Jakmile grep uspěje:

  1. zapíše výstup do ${RELEASE} který bude
  2. ukončit ${wait_pid} zpracovat
  3. ukončit tail

Poznámka: sed může být sofistikovanější, aby skutečně určil počet řádků, které tail vytvoří při spuštění, a toto číslo odebere. Ale obecně je to 10.

6
nix