J'ai un journal de server qui produit une ligne de text spécifique dans son file journal lorsque le server est en place. Je veux exécuter une command une fois que le server est en place, et donc faire quelque chose comme ce qui suit:
tail -f /path/to/serverLog | grep "server is up" ...(now, eg, wget on server)?
Quelle est la meilleure façon de procéder?
Un moyen simple serait 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")'
Et oui, les deux sont de vrais messages d'un journal du kernel. Perl pourrait être un peu plus élégant à utiliser pour cela et peut également replace le besoin de queue. Si vous utilisez perl, cela ressemblera à ceci:
open(my $fd, "<", "/path/to/serverLog") or die "Can't open log"; while(1) { if(eof $dataFd) { 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"); } }
Cette question semble déjà répondre, mais je pense qu'il y a une meilleure solution.
Plutôt que de la tail | whatever
tail | whatever
, je pense que ce que vous voulez vraiment, c'est swatch
. Swatch est un programme conçu explicitement pour faire ce que vous requestz, regarder un file journal et exécuter des actions basées sur des lignes de log. L'utilisation de tail|foo
nécessitera que vous ayez un terminal actif pour le faire. Swatch d'un autre côté fonctionne comme un démon et surveillera toujours vos journaux. Swatch est disponible dans toutes les dissortingbutions Linux,
Je vous encourage à l'essayer. Alors que vous pouvez marteler un clou avec l'arrière d'un tournevis ne signifie pas que vous devriez.
Le meilleur tutoriel de 30 secondes sur swatch que j'ai pu find est ici: http://www.campin.net/newlogcheck.html
Si vous cherchez uniquement une possibilité et que vous souhaitez restr dans la coquille plutôt que d'utiliser awk ou perl, vous pouvez faire quelque chose comme:
tail -F /path/to/serverLog | grep --line-buffered 'server is up' | while read ; do my_command ; done
… qui exécutera my_command
chaque fois que "le server est en place" apparaît dans le file journal. Pour plusieurs possibilités, vous pouvez peut-être supprimer le grep
et utiliser un case
dans le while
.
La majuscule -F
indique à la tail
de surveiller le file journal à faire pivoter; c'est-à-dire si le file actuel est renommé et qu'un autre file du même nom prend sa place, la tail
bascule vers le nouveau file.
L'option --line-buffered
indique à grep
de vider sa memory tampon après chaque ligne; sinon, my_command
peut ne pas être atteinte en time voulu (en supposant que les journaux ont des lignes de taille raisonnable).
C'est comme ça que j'ai commencé à faire ça aussi, mais je suis devenu beaucoup plus sophistiqué avec ça. Quelques choses à se soucier de:
J'utilise quelque chose comme ça:
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}
Cela fonctionne en maintenant la tail
ouverte jusqu'à ce que le file ${RELEASE}
contienne des données.
Une fois que le grep
réussit:
${RELEASE}
qui sera ${wait_pid}
tail
Note: Le sed
peut être plus sophistiqué pour déterminer réellement le nombre de lignes que produira la tail
au démarrage et supprimer ce nombre. Mais généralement, c'est 10.
Il est étrange que personne ne parle de l'utilité multitail
qui a cette fonctionnalité hors-boîte. Un exemple d'utilisation:
Afficher la sortie d'une command ping et s'il affiche un timeout d'attente, envoyer un message à tous les users actuellement connectés
multitail -ex timeout "echo timeout | wall" -l "ping 192.168.0.1"
Voir aussi un autre exemple d'utilisation multitail
.
Voyons à quel point il pourrait être simple et lisible:
mylog() { echo >>/path/to/myscriptLog "$@" } 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)
Bien que vous n'utilisiez pas regex
bash, cela pourrait restr très rapide!
Mais pour le server à forte charge, et comme j'aime sed
parce que c'est très rapide et très évolutif, j'utilise souvent ceci:
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; ... ')