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: compress ve delaycompress birlikte kullanılmalı. Özellikle copytruncate kullanmıyorsanız ve uygulama hala eski dosyaya yazabiliyorsa, yeni döndürülen dosya hemen sıkıştırılmamalı.
  • compressext belirtmemek: compresscmd değiştirdiğinizde compressext‘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. || true eklemek, reload başarısız olsa bile döndürmenin tamamlanmasını sağlar.
  • Test etmeden production’a almak: -d flag’ini kullanmadan konfigürasyon deploy etmek. Her zaman önce debug modunda test edin.
  • State dosyasını silmek: /var/lib/logrotate/status dosyası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.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir