
Sunucu yönetimi yapan herkesin er ya da geç karşılaştığı bir problem vardır: /var/log dizini şişer, disk alanı biter, sistem “disk full” hatası vermeye başlar. Bu noktada çoğu kişinin ilk refleksi rm -rf /var/log/* yazmak olur. Ama bu yanlış bir yaklaşımdır. Çünkü log dosyaları çoğu zaman çalışan servisler (nginx, mysql, journald vb.) tarafından açık tutulur. Dosyayı silmek, o servisin yazmaya devam ettiği ama artık dizin ağacında görünmeyen bir inode oluşturur ve disk alanı serbest kalmaz. Servis yeniden başlatılana kadar log akışı bozulur, ayrıca sıkıştırılmış eski loglar (.gz) genelde arşiv amaçlıdır ve kör silme riskli olabilir.
Bunun yerine doğru yöntem, dosyayı silmeden içeriğini sıfırlamaktır. Buna “truncate” denir. Dosya aynı inode’da kalır, aynı dosya tanımlayıcısını (file descriptor) kullanan servis kesintisiz yazmaya devam eder, sadece dosyanın boyutu anında 0 olur ve disk alanı geri kazanılır.
Adım 1: Doğru Dizine Geç
cd /var/log
Her komutta tam yolu tekrar tekrar yazmak yerine önce log dizinine geçiyoruz. Bu sadece pratiklik için; find komutlarını bulunduğun dizin anlamına gelen . ile de çalıştırabilirsin. Böylece hem komutlar kısalır hem de yanlışlıkla başka bir dizini hedef almış olma riski azalır.
Adım 2: Komutun Tamamı
find /var/log -type f \( -name "*.log" -o -name "*.log.[0-9]*" \) -exec truncate -s 0 {} \; ; find /var/log -type f -name "*.gz" -delete
cd /var/log yaptıysan yolları kısaltabilirsin:
find . -type f \( -name "*.log" -o -name "*.log.[0-9]*" \) -exec truncate -s 0 {} \; ; find . -type f -name "*.gz" -delete
Adım 3: Komutun Parça Parça Açıklaması
find /var/log
Aramanın nereden başlayacağını belirtir; /var/log ve altındaki tüm alt klasörler (nginx/, mysql/, apache2/ vb.) dahil taranır.
-type f
Sadece normal (regular) dosyaları hedef alır, klasörleri, sembolik linkleri veya özel dosyaları (soket, pipe vb.) dışarıda bırakır.
\( -name "*.log" -o -name "*.log.[0-9]*" \)
İki koşuldan biri sağlanan dosyaları bulur. *.log ifadesi app.log, access.log, error.log gibi düz, henüz rotasyona uğramamış aktif log dosyalarını kapsar. *.log.[0-9]* ifadesi ise app.log.1, access.log.2 gibi logrotate tarafından numaralandırılmış, rotasyona uğramış eski logları kapsar. -o (OR) operatörü bu iki koşulu birleştirir, parantezler ise find’ın öncelik sırasını doğru yorumlaması için zorunludur.
-exec truncate -s 0 {} \;
Bulunan her dosya için truncate komutunu çalıştırır. {} bulunan dosyanın yolunun otomatik yerleştiği yerdir, -s 0 dosya boyutunu 0 byte’a indirir (dosyayı silmeden sadece içeriğini boşaltır), \; ise -exec bloğunun bittiğini find’a bildiren zorunlu kapanıştır.
İki find komutu arasındaki ; işareti kabuğa (shell) “birinci komut bitince, sonucundan bağımsız olarak ikinci komutu da çalıştır” der. && kullanılsaydı, birinci komut herhangi bir sebeple hata verirse ikinci komut hiç çalışmazdı.
find /var/log -type f -name "*.gz"
/var/log altında adı .gz ile biten tüm sıkıştırılmış dosyaları bulur, örneğin app.log.3.gz veya syslog.4.gz gibi.
-delete
Bulunan bu .gz dosyalarını doğrudan siler. Bu dosyalar zaten sıkıştırılmış arşiv olduğu için truncate mantıklı değildir, ya tamamen saklanır ya da tamamen silinir; burada silme tercih edilmiştir çünkü genelde diski dolduran asıl büyük dosyalar bunlardır.
Neden Silmek Yerine Truncate Etmek Daha Güvenli
rm dosya.log
Bu komut dosyayı dizinden kaldırır ama servis dosyayı hâlâ açık tutuyorsa disk alanı process yeniden başlatılana kadar geri gelmez.
truncate -s 0 dosya.log
Bu komut ise dosyayı aynı yerde, aynı inode ve aynı file descriptor ile bırakır; servis kesintisiz yazmaya devam eder ve disk alanı anında geri kazanılır. Bu yüzden aktif olarak servisler tarafından yazılan .log dosyaları için truncate, arşivlenmiş ve artık kimsenin dokunmadığı .gz dosyaları için ise doğrudan delete tercih edilir.
Dikkat Edilmesi Gerekenler
Bu komut geri alınamaz. Truncate sonrası log içeriği kurtarılamaz, delete sonrası .gz dosyası kurtarılamaz. Önce hangi dosyaların etkileneceğini görmek için -exec veya -delete olmadan sadece find çalıştırıp listeyi gözden geçirmek iyi bir alışkanlıktır:
find /var/log -type f \( -name "*.log" -o -name "*.log.[0-9]*" \)
find /var/log -type f -name "*.gz"
Bu komut sadece .log uzantılı dosyaları kapsar. syslog, messages, wtmp gibi .log uzantısı taşımayan sistem dosyalarına dokunmaz, onlar için ayrı bir kural gerekir.
wtmp, btmp, lastlog gibi ikili (binary) login kayıt dosyalarını asla bu tarz bir komuta dahil etmeyin, login geçmişi anında kaybolur.
Düzenli ve otomatik temizlik için elle çalıştırmak yerine logrotate kullanmak, uzun vadede çok daha güvenli ve yönetilebilir bir çözümdür.
Özet
cd /var/log
find . -type f \( -name "*.log" -o -name "*.log.[0-9]*" \) -exec truncate -s 0 {} \; ; find . -type f -name "*.gz" -delete
Bu iki satır aktif ve rotasyona uğramış tüm .log dosyalarını dosyayı silmeden sıfırlar, sıkıştırılmış eski .gz arşivlerini ise tamamen siler. Sunucunuzda disk doluluğu log kaynaklı ise, servisleri durdurmadan ve kesinti yaratmadan hızlıca alan açmanın en pratik yollarından biridir.