2 votes

Comment détecter un fichier journal non déroulant et une correspondance de motifs dans un shell script qui utilise tail, while, read, and ?

Je surveille un fichier journal et si PATTERN n'est pas apparu dans le film. THRESHOLD secondes, le script doit imprimer "error", sinon, il doit imprimer "clear". Le script fonctionne bien, mais seulement si le journal tourne.

J'ai essayé de lire 'timeout' mais ça n'a pas marché.

log_file=/tmp/app.log
threshold=120

tail -Fn0 ${log_file} | \
while read line ; do
  echo "${line}" | awk '/PATTERN/ { system("touch pattern.tmp") }'

code pour calculer depuis combien de temps pattern.tmp a été touché et la même chose est assignée à DIFF

if [ ${diff} -gt ${threshold} ]; then
   echo "Error"
else
   echo "Clear"
done

Il fonctionne comme prévu uniquement lorsqu'il y a une ligne 'any' imprimée dans le app.log.

Si l'application s'est arrêtée pour une raison quelconque et que le journal s'est arrêté de tourner, il n'y aura pas de sortie par le script.

Existe-t-il un moyen de détecter l'absence de sortie de l'appareil ? tail et faire une commande à ce moment-là ?

0voto

Ed Morton Points 25374

Pourquoi pas quelque chose de simple comme :

sleep "$threshold"
grep -q 'PATTERN' "$log_file" && { echo "Clear"; exit; }
echo "Error"

Si ce n'est pas tout ce dont vous avez besoin, modifiez votre question pour préciser vos besoins. N'utilisez pas de majuscules pour les noms de variables shell non exportées - allez sur Google.

0voto

Mike Holt Points 932

Il semble que le problème que vous rencontrez est que les calculs de temps dans votre while la boucle n'a jamais la chance de courir quand read est bloquant sur l'entrée. Dans ce cas, vous pouvez faire passer le tail dans un while true à l'intérieur de laquelle vous pouvez faire if read -t $timeout :

log_file=/tmp/app.log
threshold=120
timeout=10

tail -Fn0 "$log_file" | while true; do
  if read -t $timeout line; then
    echo "${line}" | awk '/PATTERN/ { system("touch pattern.tmp") }'
  fi

  # code to calculate how long ago pattern.tmp touched and same is assigned to diff 

  if [ ${diff} -gt ${threshold} ]; then
    echo "Error"
  else
    echo "Clear"
  fi
done

Comme Ed Morton l'a fait remarquer, les noms de variables en majuscules ne sont pas une bonne idée dans les scripts de bash, j'ai donc utilisé des noms de variables en minuscules.

0voto

kvantour Points 11497

Pour aller plus loin dans votre idée, il pourrait être avantageux d'exécuter la partie awk en arrière-plan et une boucle continue pour effectuer la vérification.

#!/usr/bin/env bash

log_file="log.txt"
# threshold in seconds
threshold=10

# run the following process in the background
stdbuf -oL tail -f0n "$log_file" \
   | awk '/PATTERN/{system("touch "pattern.tmp") }' &

while true; do
    match=$(find . -type f  -iname "pattern.tmp" -newermt "-${threshold} seconds")
    if [[ -z "${match}" ]]; then
        echo "Error"
    else
        echo "Clear"
    fi
done

0voto

ghoti Points 14996

Cela me semble être un chien de garde. J'ai implémenté quelque chose de ce genre en forçant un processus d'arrière-plan à mettre à jour mon journal, de sorte que je n'ai pas à me préoccuper de read -t . Voici un exemple concret :

#!/usr/bin/env bash

threshold=10
grain=2

errorstate=0

while sleep "$grain"; do
        date '+[%F %T] watchdog timer' >> log
done &
trap "kill -HUP $!" 0 HUP INT QUIT TRAP ABRT TERM

printf -v lastseen '%(%s)T'
tail -F log | while read line; do
        printf -v now '%(%s)T'
        if (( now - lastseen > threshold )); then
                echo "ERROR"
                errorstate=1
        else
                if (( errorstate )); then
                        echo "Recovered, yay"
                        errorstate=0
                fi
        fi
        if [[ $line =~ .*PATTERN.* ]]; then
                lastseen=$now
        fi
done

Exécutez ceci dans une fenêtre, attendez $threshold secondes pour qu'il se déclenche, puis dans une autre fenêtre echo PATTERN >> log pour voir la récupération.

Bien qu'il soit possible d'effectuer un réglage aussi précis que vous le souhaitez (dans l'exemple, je l'ai fixé à 2 secondes), cela pollue votre fichier journal.

Oh, et notez que printf '%(%s)T' nécessite la version 4 ou supérieure de bash.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X