Ich habe hier ein Konto erstellt, um @BobC für seine Antwort (und seine Frage) zu danken. Es war der Katalysator, den ich brauchte, um unser langjähriges Problem mit Solr-Protokollen zu lösen.
Ich habe das Skript von BobC geändert, um es ein wenig für den logrotate-Anwendungsfall zu optimieren (mit $xfer_block_size
for ibs
und einem beliebig großen (8M) obs
, gefolgt von einem tr -d "\000"
, um die verbleibenden Nullen zu entfernen), und habe es dann im firstaction
Abschnitt meiner logrotate
Konfiguration verwendet.
Ich denke, meine Lösung ist etwas hässlich, aber es ist viel besser, als kritische Produktionsservices abprallen zu müssen, wenn eine Protokolldatei von über 80 GB die Festplatte zu füllen droht.
Dies ist, was ich endete mit:
#! /bin/bash # truncat.sh # Adapted from @BobC's script http://superuser.com/a/836950/539429 # # Efficiently cat log files that have been previously truncated. # They are sparse -- many null blocks before the interesting content. # This script skips the null blocks in bulk (except for the last) # and then uses tr to filter the remaining nulls. # for f in $@; do fields=( `stat -c "%o %B %b %s" $f` ) xfer_block_size=$ alloc_block_size=$ blocks_alloc=$ size_bytes=$ bytes_alloc=$(( $blocks_alloc * $alloc_block_size )) alloc_in_xfer_blocks=$(( ($bytes_alloc + ($xfer_block_size - 1))/$xfer_block_size )) size_in_xfer_blocks=$(( ($size_bytes + ($xfer_block_size - 1))/$xfer_block_size )) null_xfer_blocks=$(( $size_in_xfer_blocks - $alloc_in_xfer_blocks )) null_xfer_bytes=$(( $null_xfer_blocks * $xfer_block_size )) non_null_bytes=$(( $size_bytes - $null_xfer_bytes )) if [ "$non_null_bytes" -gt "0" -a "$non_null_bytes" -lt "$size_bytes" ]; then cmd="dd if=$f ibs=$xfer_block_size obs=8M skip=$null_xfer_blocks " $cmd | tr -d "\000" else cat $f fi done
Die Verwendung größerer Blöcke macht dd
Größenordnungen schneller. dd
macht einen ersten Schnitt und schneidet dann tr
den Rest der Nullen ab. Als Bezugspunkt für eine 87 GiB-Datei mit geringer Dichte (die 392 MiB-Daten enthält):
# ls -l 2015_10_12-025600113.start.log -rw-r--r-- 1 solr solr 93153627360 Dec 31 10:34 2015_10_12-025600113.start.log # du -shx 2015_10_12-025600113.start.log 392M 2015_10_12-025600113.start.log # # time truncat.sh 2015_10_12-025600113.start.log > test1 93275+1 records in 45+1 records out 382055799 bytes (382 MB) copied, 1.53881 seconds, 248 MB/s real 0m1.545s user 0m0.677s sys 0m1.076s # time cp --sparse=always 2015_10_12-025600113.start.log test2 real 1m37.057s user 0m8.309s sys 1m18.926s # ls -l test1 test2 -rw-r--r-- 1 root root 381670701 Dec 31 10:07 test1 -rw-r--r-- 1 root root 93129872210 Dec 31 10:11 test2 # du -shx test1 test2 365M test1 369M test2
Wenn ich das logrotate
verarbeiten lasse copytruncate
, dauerte es fast eine Stunde und führte zu einer vollständig materialisierten, nicht spärlichen Feile - die dann über eine Stunde dauerte gzip
.
Hier ist meine endgültige logrotate
Lösung:
/var/log/solr/rotated.start.log { rotate 14 daily missingok dateext compress create firstaction # this actually does the rotation. At this point we expect # an empty rotated.start.log file. rm -f /var/log/solr/rotated.start.log # Now, cat the contents of the log file (skipping leading nulls) # onto the new rotated.start.log for i in /var/log/solr/20[0-9][0-9]_*.start.log ; do /usr/local/bin/truncat.sh $i >> /var/log/solr/rotated.start.log > $i # truncate the real log done endscript }
Das Hacker-Bit ist, dass Sie beim ersten Einrichten eine leere rotated.start.log
Datei erstellen müssen. Andernfalls logrotate
wird sie niemals abgerufen und das firstaction
Skript ausgeführt.
Ich habe Ihr logrotate
Bug-Ticket gesehen, für das ein Update veröffentlicht wurdelogrotate 3.9.0
. Wenn ich es richtig lese, behebt das implementierte Update leider nur einen Teil des Problems. Die spärliche Protokolldatei wird korrekt kopiert, um eine weitere spärliche Datei zu erstellen. Aber wie Sie bemerkt haben, wollen wir das nicht. Die Kopie soll alle irrelevanten Nullblöcke ausschließen und nur die Protokolleinträge beibehalten. Nachdem die copytruncate
, hat logrotate
immer noch gzip
die Datei, und gzip
behandelt spärliche Dateien nicht effizient (es liest und verarbeitet jedes null Byte).
Unsere Lösung ist besser als die copytruncate
Korrektur, logrotate 3.9.x
da saubere Protokolle erstellt werden, die leicht komprimiert werden können.