Sıkıştırılmış Logları Döndürme ve Yönetme: logrotate ile Entegre Arşivleme
Yıllar önce bir müşterimizin sunucusunda disk dolduğunda ne oldu biliyor musunuz? Gece 2’de çağrı aldım, /var partisyonu %100 dolmuş, uygulama log dosyaları onlarca gigabayta ulaşmış ve hiçbir şekilde döndürülmemiş. O gece birkaç saatimi harcayarak el ile temizlik yaptım ve sabaha kadar logrotate konfigürasyonu yazdım. O günden beri log yönetimi konusunda obsesif bir titizlik geliştirdim.
Bu yazıda, logrotate‘i sadece temel kullanımıyla değil, sıkıştırma araçlarıyla entegre ederek gerçek anlamda verimli bir arşivleme sistemi kurmayı anlatacağım.
logrotate Nedir ve Neden Yeterli Değildir?
logrotate, Linux sistemlerinde log dosyalarını otomatik olarak döndüren, boyutlandıran ve yönetен bir araçtır. Çoğu dağıtımda /etc/logrotate.conf ana konfigürasyonu ve /etc/logrotate.d/ dizini altındaki servis bazlı konfigürasyonlarla gelir.
Ancak şunu fark etmek önemli: logrotate tek başına yeterli değildir. Varsayılan gzip sıkıştırması çoğu senaryoda yeterli görünse de, yüksek trafikli bir ortamda günde 500 MB log üreten bir uygulama düşünün. 30 günlük arşivle 15 GB disk alanı sadece loglara gidiyor. Bunu zstd veya xz ile sıkıştırdığınızda bu rakam dramatik biçimde düşebilir.
Önce temel bir logrotate konfigürasyonuna bakalım:
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0640 appuser appgroup
sharedscripts
postrotate
systemctl reload myapp > /dev/null 2>&1 || true
endscript
}
Bu konfigürasyondaki compress direktifi varsayılan olarak gzip kullanır. İşte burada devreye farklı sıkıştırma araçlarını entegre etme ihtiyacı doğuyor.
Özel Sıkıştırma Araçlarını logrotate ile Kullanmak
logrotate, compresscmd ve compressoptions direktifleriyle herhangi bir sıkıştırma aracını kullanmanıza izin verir. Bu direktifleri hem global konfigürasyona hem de servis bazlı konfigürasyonlara ekleyebilirsiniz.
zstd ile Entegrasyon
zstd, son yılların en popüler sıkıştırma algoritmasıdır. Hem sıkıştırma oranı hem de hız açısından gzip’e göre belirgin bir avantaj sunar. Özellikle yoğun log yazan sistemlerde I/O yükünü ciddi ölçüde azaltır.
# /etc/logrotate.d/nginx-zstd
/var/log/nginx/*.log {
daily
rotate 60
compress
compresscmd /usr/bin/zstd
compressoptions -19 --rm
compressext .zst
uncompresscmd /usr/bin/unzstd
delaycompress
missingok
notifempty
sharedscripts
postrotate
nginx -s reopen
endscript
}
Buradaki -19 parametresi maksimum sıkıştırma seviyesini kullanır. Hız ile sıkıştırma oranı arasında denge kurmak istiyorsanız -3 veya -6 daha makul bir seçimdir. --rm ise orijinal dosyayı sıkıştırma sonrası siler.
Sıkıştırılmış dosyaları okumak için:
# zstd ile sıkıştırılmış log dosyasını okuma
zstdcat /var/log/nginx/access.log.1.zst | tail -n 100
# Grep ile doğrudan arama
zstdcat /var/log/nginx/access.log.1.zst | grep "POST /api/login" | wc -l
xz ile Entegrasyon
Uzun vadeli arşivleme için xz mükemmel bir seçimdir. Sıkıştırma oranı yüksektir ama yavaştır. Günlük döndürülen ve sıkça erişilmeyecek loglar için idealdir.
# /etc/logrotate.d/postgresql-xz
/var/log/postgresql/*.log {
weekly
rotate 52
compress
compresscmd /usr/bin/xz
compressoptions -6 -T4
compressext .xz
uncompresscmd /usr/bin/unxz
delaycompress
missingok
notifempty
create 0600 postgres postgres
}
-T4 parametresi 4 thread kullanarak paralel sıkıştırma yapar. PostgreSQL logları genellikle büyük olduğu için bu ciddi zaman kazandırır.
bzip2 ile Klasik Entegrasyon
Eski sistemlerle uyumlu olmak durumundaysanız ya da her yerde bzip2 kurulu olduğunu biliyorsanız:
# /etc/logrotate.d/apache-bzip2
/var/log/apache2/*.log {
daily
rotate 14
compress
compresscmd /usr/bin/bzip2
compressoptions -9
compressext .bz2
uncompresscmd /usr/bin/bunzip2
delaycompress
missingok
notifempty
sharedscripts
postrotate
apache2ctl graceful > /dev/null 2>&1 || true
endscript
}
Global Konfigürasyonda Sıkıştırma Ayarları
Tek tek her servise yazmak yerine, /etc/logrotate.conf dosyasında global olarak sıkıştırma ayarı yapabilirsiniz:
# /etc/logrotate.conf
weekly
rotate 4
create
compress
compresscmd /usr/bin/zstd
compressoptions -6 --rm
compressext .zst
uncompresscmd /usr/bin/unzstd
include /etc/logrotate.d
Bu sayede tüm loglar varsayılan olarak zstd ile sıkıştırılır. Belirli bir servis için farklı bir davranış istiyorsanız o servisin konfigürasyon dosyasında nocompress veya farklı compresscmd belirtebilirsiniz.
Boyut Tabanlı Döndürme ve Sıkıştırma
Zaman bazlı değil boyut bazlı döndürme, bazı uygulamalar için çok daha mantıklıdır. Özellikle trafik yoğunluğuna göre değişken büyüklükte log üreten sistemlerde:
# /etc/logrotate.d/java-app
/opt/myapp/logs/*.log {
size 100M
rotate 10
compress
compresscmd /usr/bin/zstd
compressoptions -3 --rm
compressext .zst
uncompresscmd /usr/bin/unzstd
copytruncate
missingok
notifempty
}
copytruncate direktifi dikkat çekicidir. Dosyayı taşımak yerine içeriği kopyalayıp orijinal dosyayı sıfırlar. Java uygulamaları gibi dosyayı açık tutan ve yeniden açamayan uygulamalar için zorunludur. Ancak çok kısa bir süre için log kaybı riski vardır; bunu bilerek kullanın.
Logrotate’i Manuel Tetiklemek ve Test Etmek
Konfigürasyonunuzu yazdıktan sonra test etmek kritik öneme sahiptir:
# Kuru çalıştırma (debug) modu - hiçbir şeyi gerçekten yapmaz
logrotate -d /etc/logrotate.d/myapp
# Zorla çalıştırma - durum dosyasını görmezden gelir
logrotate -f /etc/logrotate.d/myapp
# Verbose mod ile çalıştırma
logrotate -v /etc/logrotate.d/myapp
# Belirli bir state dosyası ile çalıştırma
logrotate -s /var/lib/logrotate/myapp.status /etc/logrotate.d/myapp
-d seçeneği konfigürasyon hatalarını bulmak için vazgeçilmezdir. Çıktısını dikkatle okuyun, hangi dosyaları döndüreceğini ve hangi komutları çalıştıracağını açıkça gösterir.
Arşivlenmiş Loglarda Arama Yapmak
Sıkıştırılmış log arşivlerinde arama yapmak, ham dosyalarla çalışmaktan farklıdır. Doğru araçları kullanmak hem zamandan hem de işlem gücünden tasarruf sağlar.
# Tüm sıkıştırılmış nginx loglarında belirli IP'yi arama
for f in /var/log/nginx/access.log.*.zst; do
echo "=== $f ==="
zstdcat "$f" | grep "192.168.1.100"
done
# zgrep ile gzip arşivlerinde arama (tek komut)
zgrep "ERROR" /var/log/myapp/app.log.*.gz
# xzgrep ile xz arşivlerinde arama
xzgrep "FATAL" /var/log/postgresql/postgresql.log.*.xz
# Tarih aralığına göre birden fazla arşivden arama
ls /var/log/myapp/app.log.{1..7}.zst | xargs -I{} zstdcat {} | grep "OutOfMemoryError"
Bu arama senaryoları gerçek hayatta çok işinize yarayacak. Bir müşteride geçen ay yaşadığımız bir olayda, production sunucusunda 3 haftalık log arşivini taramak gerekti. xzgrep komutuyla 20 dakikada bulduğumuz şeyi başka türlü saatlerce uğraşmamız gerekirdi.
Özel Arşivleme Script’i ile logrotate Entegrasyonu
logrotate’in postrotate ve prerotate bloklarını kullanarak daha sofistike arşivleme senaryoları oluşturabilirsiniz:
#!/bin/bash
# /usr/local/bin/archive-logs.sh
# logrotate postrotate bloğundan çağrılır
LOG_DIR="/var/log/myapp"
ARCHIVE_DIR="/mnt/backup/logs/myapp"
DATE=$(date +%Y/%m)
RETENTION_DAYS=365
# Arşiv dizinini oluştur
mkdir -p "${ARCHIVE_DIR}/${DATE}"
# Döndürülen ve sıkıştırılan dosyaları arşive taşı
find "${LOG_DIR}" -name "*.zst" -newer "${LOG_DIR}/app.log" | while read -r file; do
filename=$(basename "$file")
datestamp=$(date +%Y%m%d)
dest="${ARCHIVE_DIR}/${DATE}/${datestamp}_${filename}"
if cp "$file" "$dest"; then
rm "$file"
echo "$(date): Archived $file to $dest" >> /var/log/archive-logs.log
else
echo "$(date): ERROR: Failed to archive $file" >> /var/log/archive-logs.log
fi
done
# Eski arşivleri temizle
find "${ARCHIVE_DIR}" -name "*.zst" -mtime +${RETENTION_DAYS} -delete
find "${ARCHIVE_DIR}" -type d -empty -delete
Bu script’i logrotate konfigürasyonuna ekleyin:
# /etc/logrotate.d/myapp-advanced
/var/log/myapp/*.log {
daily
rotate 7
compress
compresscmd /usr/bin/zstd
compressoptions -6 --rm
compressext .zst
uncompresscmd /usr/bin/unzstd
delaycompress
missingok
notifempty
create 0640 appuser appgroup
sharedscripts
postrotate
systemctl reload myapp > /dev/null 2>&1 || true
/usr/local/bin/archive-logs.sh
endscript
}
Birden Fazla Sunucuda Merkezi Log Arşivleme
Birden fazla sunucu yönetiyorsanız, logları merkezi bir arşiv sunucusuna göndermek isteyebilirsiniz. logrotate’in postrotate bloğuyla rsync entegrasyonu bu işi kolaylaştırır:
# /etc/logrotate.d/centralized-archive
/var/log/nginx/*.log {
daily
rotate 3
compress
compresscmd /usr/bin/zstd
compressoptions -19 --rm
compressext .zst
delaycompress
missingok
notifempty
sharedscripts
postrotate
nginx -s reopen
# Sıkıştırılmış logları merkezi sunucuya gönder
HOSTNAME=$(hostname -s)
ARCHIVE_SERVER="backup.internal"
ARCHIVE_PATH="/archives/nginx/${HOSTNAME}/$(date +%Y/%m/)"
rsync -az --remove-source-files
/var/log/nginx/access.log.*.zst
/var/log/nginx/error.log.*.zst
"backup@${ARCHIVE_SERVER}:${ARCHIVE_PATH}" 2>/dev/null ||
echo "$(date): Rsync failed for ${HOSTNAME}" >> /var/log/archive-errors.log
endscript
}
logrotate Durum Dosyası ve İzleme
logrotate, hangi dosyaları ne zaman döndürdüğünü /var/lib/logrotate/status dosyasında tutar. Bu dosyayı izlemek, bir şeylerin ters gittiğini erken fark etmenizi sağlar:
# Durum dosyasını görüntüle
cat /var/lib/logrotate/status
# Belirli bir log için son döndürme zamanını kontrol et
grep "nginx" /var/lib/logrotate/status
# 7 günden fazla döndürülmemiş logları tespit et
awk '{
gsub(/"/, "", $1)
cmd = "date -d ""$2" "$3"" +%s"
cmd | getline timestamp
close(cmd)
now = systime()
if ((now - timestamp) > 604800) {
print "WARNING: " $1 " son 7 günde döndürülmemiş! Son: " $2 " " $3
}
}' /var/lib/logrotate/status
Bunu bir cron job’a ekleyip e-posta ile bildirim gönderebilirsiniz:
# /etc/cron.daily/check-logrotate
#!/bin/bash
THRESHOLD=604800 # 7 gün
awk -v threshold="$THRESHOLD" '
NR > 1 {
gsub(/"/, "", $1)
cmd = "date -d "" $2 " " $3 "" +%s 2>/dev/null"
cmd | getline timestamp
close(cmd)
now = systime()
if (timestamp && (now - timestamp) > threshold) {
print $1
}
}' /var/lib/logrotate/status | mail -s "Logrotate Uyarısı: $(hostname)" [email protected]
Disk Alanı Tasarrufu Analizi
Hangi sıkıştırma algoritmasının ne kadar tasarruf sağladığını ölçmek için pratik bir yaklaşım:
#!/bin/bash
# Sıkıştırma algoritmalarını karşılaştır
LOG_SAMPLE="/var/log/nginx/access.log"
if [ ! -f "$LOG_SAMPLE" ]; then
echo "Log dosyası bulunamadı"
exit 1
fi
ORIGINAL=$(wc -c < "$LOG_SAMPLE")
echo "Orijinal boyut: $(numfmt --to=iec $ORIGINAL)"
# gzip
time gzip -c "$LOG_SAMPLE" > /tmp/test.gz
GZ=$(wc -c < /tmp/test.gz)
echo "gzip -6: $(numfmt --to=iec $GZ) ($(( (ORIGINAL - GZ) * 100 / ORIGINAL ))% tasarruf)"
# zstd seviyeleri
for level in 3 6 19; do
time zstd -$level -c "$LOG_SAMPLE" > /tmp/test.zst 2>/dev/null
ZST=$(wc -c < /tmp/test.zst)
echo "zstd -$level: $(numfmt --to=iec $ZST) ($(( (ORIGINAL - ZST) * 100 / ORIGINAL ))% tasarruf)"
done
# xz
time xz -6 -c "$LOG_SAMPLE" > /tmp/test.xz
XZ=$(wc -c < /tmp/test.xz)
echo "xz -6: $(numfmt --to=iec $XZ) ($(( (ORIGINAL - XZ) * 100 / ORIGINAL ))% tasarruf)"
# Temizlik
rm -f /tmp/test.{gz,zst,xz}
Bu script’i gerçek bir sunucuda çalıştırdığımda nginx access logları için şu sonuçları aldım: gzip %68, zstd-3 %65, zstd-19 %72, xz-6 %74 sıkıştırma oranı. zstd-3 neredeyse xz ile aynı oranı çok daha kısa sürede elde ediyor.
Sık Yapılan Hatalar ve Çözümleri
Yıllar içinde hem kendim hem de çevremdeki sysadmin’lerin yaptığı hatalar:
- delaycompress’i unutmak:
compressvedelaycompressbirlikte kullanılmalı. Özelliklecopytruncatekullanmıyorsanız ve uygulama hala eski dosyaya yazabiliyorsa, yeni döndürülen dosya hemen sıkıştırılmamalı.
- compressext belirtmemek:
compresscmddeğiştirdiğinizdecompressext‘i de değiştirmeyi unutmayın. Yoksa logrotate eski uzantıyla dosya arar ve döndürmede sorun çıkar.
- postrotate bloğunda hata kontrolü yapmamak: Servis reload başarısız olsa da logrotate devam eder.
|| trueeklemek, reload başarısız olsa bile döndürmenin tamamlanmasını sağlar.
- Test etmeden production’a almak:
-dflag’ini kullanmadan konfigürasyon deploy etmek. Her zaman önce debug modunda test edin.
- State dosyasını silmek:
/var/lib/logrotate/statusdosyasını yanlışlıkla silmek, logrotate’in tüm dosyaları sıfırdan döndürmesine neden olur. Yedekleyin.
Sonuç
logrotate ile entegre sıkıştırma yönetimi, disk alanı tasarrufu açısından göz ardı edilemeyecek bir kazanım sağlar. Gzip’ten zstd’ye geçmek bile ciddi fark yaratabilir; ancak asıl önemli olan doğru konfigürasyonla sistematik bir yaklaşım benimsemektir.
Birkaç pratik öneri ile bitirelim: Geliştirme ortamında log boyutlarını izleyin ve hangi servisin ne kadar log ürettiğini anlayın. Kritik servisler için merkezi arşivleme kurun, logları tek bir sunucuda bırakmayın. logrotate -d ile konfigürasyonlarınızı düzenli test edin ve durum dosyasını izleyen bir alarm mekanizması kurun.
Disk dolduğunda çağrı almak yerine, loglar zaten sıkıştırılmış ve arşivlenmiş olsun. Gece 2’de uyandırılmak kimsenin tercih ettiği bir iş değil.
