Meilleure façon de suivre un journal et d'exécuter une command lorsqu'un text apparaît dans le journal

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:

  1. Si la queue du journal contient déjà "le server est en place".
  2. Terminer automatiquement le process de queue une fois qu'il est trouvé.

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:

  1. écrit la sortie dans ${RELEASE} qui sera
  2. terminer le process ${wait_pid}
  3. sortir de la 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 .

bash pourrait faire le travail tout seul

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 bash + sed est un tandem très efficace et intéressant

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; ... ')