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?
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");
}
}
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).
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 .
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
.
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 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;
...
')
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:
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:
${RELEASE}
který bude${wait_pid}
zpracovattail
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.