Quand tee
se termine, la commande qui l'alimente continuera à s'exécuter jusqu'à ce qu'il tente d'écrire plus de sortie. Ensuite, il obtiendra un SIGPIPE (13 sur la plupart des systèmes) pour avoir essayé d'écrire dans un tube sans lecteur.
Si vous modifiez votre script pour piéger SIGPIPE et prendre des mesures appropriées (par exemple, arrêter d'écrire la sortie), vous devriez pouvoir le faire continuer après la fin de tee.
Mieux encore, plutôt que de tuer tee
du tout, utilisez logrotate
avec le copytruncate
option pour plus de simplicité.
Pour citer logrotate(8)
:
copytruncate
Tronquez le fichier journal d'origine après avoir créé une copie, au lieu de déplacer l'ancien fichier journal et éventuellement d'en créer un nouveau. Il peut être utilisé lorsqu'un programme ne peut pas être invité à fermer son fichier journal et peut donc continuer à écrire (ajouter) au fichier journal précédent pour toujours. Notez qu'il y a une très petite tranche de temps entre la copie du fichier et sa troncature, donc certaines données de journalisation peuvent être perdues. Lorsque cette option est utilisée, l'option de création n'aura aucun effet, car l'ancien fichier journal reste en place.
Expliquer le "pourquoi"
En bref :si les écritures échouent, ne l'ont pas fait provoquer la fermeture d'un programme (par défaut), nous aurions un gâchis. Considérez find . | head -n 10
-- vous ne voulez pas find
pour continuer à fonctionner, en analysant le reste de votre disque dur, après head
a déjà pris les 10 lignes dont il avait besoin et a continué.
Faire mieux :faire pivoter l'intérieur de votre enregistreur
Considérez ce qui suit, qui n'utilise pas tee
du tout, à titre d'exemple démonstratif :
#!/usr/bin/env bash
file=${1:-debug.log} # filename as 1st argument
max_size=${2:-100000} # max size as 2nd argument
size=$(stat --format=%s -- "$file") || exit # Use GNU stat to retrieve size
exec >>"$file" # Open file for append
while IFS= read -r line; do # read a line from stdin
size=$(( size + ${#line} + 1 )) # add line's length + 1 to our counter
if (( size > max_size )); then # and if it exceeds our maximum...
mv -- "$file" "$file.old" # ...rename the file away...
exec >"$file" # ...and reopen a new file as stdout
size=0 # ...resetting our size counter
fi
printf '%s\n' "$line" # regardless, append to our current stdout
done
Si exécuté en tant que :
/mnt/apps/start.sh 2>&1 | above-script /tmp/nginx/debug_log
... cela commencera par ajouter à /tmp/nginx/debug_log
, en renommant le fichier en /tmp/nginx/debug_log.old
lorsque plus de 100 Ko de contenu sont présents. Étant donné que l'enregistreur effectue lui-même la rotation, il n'y a pas de tuyau cassé, pas d'erreur et pas de fenêtre de perte de données lors de la rotation ; chaque ligne sera écrite dans un fichier ou un autre.
Bien sûr, implémenter cela dans bash natif est inefficace, mais ce qui précède est un exemple illustratif. Il existe de nombreux programmes disponibles qui mettront en œuvre la logique ci-dessus pour vous. Considérez :
svlogd
, le service logger de la suite Runit.s6-log
, une alternative activement maintenue de la suite skanet.multilog
de DJB Daemontools, l'ancêtre de cette famille d'outils de supervision et de surveillance des processus.