Comment limiter la taille du fichier journal à l'aide de >>

24

Comment puis-je limiter la taille d'un fichier journal écrit >>à 200 Mo?

$ run_program >> myprogram.log
David
la source
1
Voulez-vous que le programme soit tué après 200 Mo? Ou voulez-vous les derniers 200 Mo avec tout ce qui est plus ancien dans le seau de bits?
Aaron D. Marasco,
non, le processus ne peut pas s'arrêter avant d'être tué manuellement
david
a décidé d'opter pour logrotate, merci à tous pour les précieuses contributions
david

Réponses:

9

Si votre application (c.-à-d. run_program) Ne prend pas en charge la limitation de la taille du fichier journal, vous pouvez vérifier périodiquement la taille du fichier en boucle avec une application ou un script externe.

Vous pouvez également utiliser logrotate(8)pour faire pivoter vos journaux, il a un sizeparamètre que vous pouvez utiliser pour votre objectif:

Avec cela, le fichier journal pivote lorsque la taille spécifiée est atteinte. La taille peut être spécifiée en octets (par défaut), kilo-octets (sizek) ou mégaoctets (sizem).

Emre Yazici
la source
1
+1 Les fichiers journaux contenant des informations répétées peuvent souvent être compressés par ordre de grandeur.
utilisateur inconnu
Est-ce que logrotate tronque les fichiers, ou simplement les copie ou les déplace? Parce que cela ne fonctionnera que si le fichier associé au fd est tronqué. S'il est mv'd, le fichier continuera de croître, s'il n'est pas lié, il restera simplement ouvert et continuera de croître jusqu'à ce que le processus se termine ... L'IIRC copie à tour de rôle, dissocie et crée un nouveau fichier, c'est pourquoi il faut souvent envoyer SIGHUP aux démons lorsque leurs rondins ont été tournés.
Michael Trausch,
Notez que même s'il est tronqué, il y a un problème si le fichier n'a pas été ouvert en mode ajout (les fichiers journaux doivent toujours être ouverts en mode ajout, mais selon mon expérience, ce n'est souvent pas le cas)
Random832
Logrotate peut pivoter une fois que le fichier a atteint une certaine taille, tous les jours, toutes les semaines, etc. Il peut également être compressé et vous pouvez utiliser l' postscriptoption pour que la configuration logrotate soit envoyée SIGHUPau programme.
laebshade
12

Si votre programme n'a pas besoin d'écrire d'autres fichiers qui seraient plus grands que cette limite, vous pouvez informer le noyau de cette limite en utilisant ulimit. Avant d'exécuter votre commande, exécutez ceci pour configurer une limite de taille de fichier de 200 Mo pour tous les processus exécutés dans votre session shell actuelle:

ulimit -f $((200*1024))

Cela protégera votre système, mais cela pourrait être gênant pour le programme qui écrit le fichier. Comme le suggère eyazici , envisagez de configurer la logrotatetaille des fichiers journaux une fois qu'ils atteignent une certaine taille ou un certain âge. Vous pouvez supprimer les anciennes données ou les archiver pendant une période de temps dans une série de fichiers compressés.

Caleb
la source
cela limite la taille de tout fichier écrit par le programme
Kim
Vrai. Si le programme avait un besoin légitime d'écrire d'autres gros fichiers, vous auriez besoin d'une solution différente.
Caleb
6

Vous pouvez créer une nouvelle image de système de fichiers, la monter à l'aide d'un périphérique de boucle et placer le fichier journal sur ce système de fichiers:

dd if=/dev/zero of=./200mb.img bs=1024 count=200000 # create new empty 200MB file
mkfs.ext2 200mb.img # or ext3, or whatever fits your needs
mkdir logs
sudo mount -t ext2 -o loop 200mb.img logs # only root can do '-o loop' by default
run_program >>logs/myprogram.log

Vous pouvez également utiliser à la tmpfsplace d'un fichier, si vous avez suffisamment de mémoire.

alex
la source
Idée créative ... qui laisse le soin au programme de savoir quoi faire quand il sera épuisé.
Aaron D. Marasco
6

Vous pouvez tronquer la sortie avec head:

size=$((200*1024*1024-$(stat -c %s myprogram.log)))
run_program | head -c ${size} >> myprogram.log
smoking
la source
Très créatif. Juste une note que cela ne fonctionnerait que pour limiter les NOUVELLES données écrites dans le fichier, cela ne prendrait pas en compte la taille ou la taille du fichier.
Caleb
2
Notez qu'il est probable que cela tue le programme (avec SIGPIPE) une fois qu'il a atteint la taille limite, plutôt que de supprimer les données.
Random832
1
Je pensais la même ddchose avec de la magie, mais oui, @ Random832 a raison, vous obtiendrez un SIGPIPEas head/ dd/ whateverdrops it.
Aaron D.Marasco,
Qu'en est-il de l'ignorer avec un trap '' SIGPIPE?
smoking le
Ou à la place { head -c "$size" >> log; cat > /dev/null; }.
Stéphane Chazelas
5

Dans le package apache2-utilsest un utilitaire appelé rotatelogs, il peut être utile pour vous.

Synopsis:

rotatelogs [-l] [-L linkname ] [-p program ] [-f] [-t] [-v] [-e] [-c] [-n nombre-de-fichiers ] logfile rotationtime | taille du fichier (B | K | M | G) [ décalage ]

Exemple:

your_program | rotatelogs -n 5 /var/log/logfile 1M

Manuel complet que vous pouvez lire sur ce lien .

PRIHLOP
la source
Le lien est inexistant.
Alexander Gonchiy
1

Je suis certain que l'affiche originale a trouvé une solution. Voici un autre pour ceux qui peuvent lire ce fil ...

Curtail limite la taille de la sortie d'un programme et préserve les 200 derniers Mo de sortie avec la commande suivante:

$ run_program | curtail -s 200M myprogram.log

Les références

REMARQUE: je suis le responsable du dépôt ci-dessus. Partageons simplement la solution ...

Dave Wolaver
la source
J'adore l'idée de réduire. Je ne suis pas aussi familier avec C, donc y a-t-il une chance de fournir un binaire pour cela? ou au moins des instructions détaillées sur la façon de l'installer?
Felipe
0

Puisqu'il s'agit de texte, j'écrirais un script dans votre langue préférée et le dirigerais vers cela. Demandez-lui de gérer les E / S du fichier (ou conservez-les tous en mémoire, puis videz-le SIGHUPou similaire). Pour cela, au lieu de 200 Mo, je pense à un nombre «raisonnable» de lignes à suivre.

Aaron D. Marasco
la source
Garder 200 Mo de données de journal en mémoire pour aucune autre raison que de pouvoir les tronquer n'est pas une très bonne utilisation des ressources système. Le décompte de lignes sur un gros fichier journal n'est pas non plus effectué. Je recommanderais d'utiliser des outils conçus pour cela comme sysloget logrotate.
Caleb
0

Le script suivant devrait faire le travail.

LOG_SIZE=500000
NUM_SEGM=2
while getopts "s:n:" opt; do
  case "$opt" in
    s)
      LOG_SIZE=$OPTARG
      ;;
    n)
      NUM_SEGM=$OPTARG
      ;;
  esac
done
shift $((OPTIND-1))
if [ $# == 0 -o -z "$1" ]; then
    echo "missing output file argument"
    exit 1
fi
OUT_FILE=$1
shift
NUM=1
while :; do
    dd bs=10 count=$(($LOG_SIZE/10)) >> $OUT_FILE 2>/dev/null
    SZ=`stat -c%s $OUT_FILE`
    if [ $SZ -eq 0 ]; then
        rm $OUT_FILE
        break
    fi
    echo -e "\nLog portion finished" >> $OUT_FILE
    mv $OUT_FILE $OUT_FILE.n$NUM
    NUM=$(($NUM + 1))
    [ $NUM -gt $NUM_SEGM ] && NUM=1
done

Il a quelques raccourcis évidents, mais dans l'ensemble, il fait ce que vous avez demandé. Il divisera le journal en morceaux d'une taille limitée et la quantité de morceaux est également limitée. Tout peut être spécifié via les arguments de la ligne de commande. Le fichier journal est également spécifié via la ligne de commande.

Notez un petit problème si vous l'utilisez avec le démon qui passe en arrière-plan. L'utilisation d'un pipe empêchera le démon de passer en arrière-plan. Dans ce cas, il existe une syntaxe (probablement spécifique à bash) pour éviter le problème:

my_daemon | ( logger.sh /var/log/my_log.log <&0 & )

Notez <&0que, bien qu'apparemment redondant, cela ne fonctionnera pas sans cela.

stsp
la source