awk ile Apache Hata Loglarından Kritik Hata Kalıplarını Tespit Etme ve Zaman Bazlı Trend Analizi

Bir gece yarısı çağrısıyla uyanmak hiç kimsenin istemeyeceği bir şeydir. Ama o çağrı geldiğinde, Apache log dosyalarınızın içinde ne aradığınızı bilmiyorsanız, saatlerinizi tail -f ile ekrana bakarak geçirebilirsiniz. Ben de bir zamanlar öyle yapıyordum. Sonra awk ile tanıştım ve log analizi bambaşka bir boyut kazandı.

Bu yazıda size gerçek prodüksiyon ortamlarında kullandığım, test edilmiş ve zaman kazandırmış awk tekniklerini aktaracağım. Apache hata loglarından kritik kalıpları yakalamak, zaman bazlı trend analizi yapmak ve bu bilgiyi aksiyona dönüştürmek için ihtiyacınız olan her şey burada.

Apache Hata Log Formatını Anlamak

İşe temelden başlayalım. awk ile etkili çalışabilmek için önce hangi veriyle uğraştığınızı anlamanız gerekiyor. Apache error log satırları tipik olarak şöyle görünür:

[Wed Oct 11 14:32:20.123456 2023] [php:error] [pid 12345] [client 192.168.1.100:54321] PHP Fatal error: ...
[Wed Oct 11 14:32:21.654321 2023] [core:error] [pid 12346] [client 10.0.0.5:43210] AH00126: Invalid URI ...
[Wed Oct 11 14:32:22.111111 2023] [ssl:error] [pid 12347] [client 203.0.113.42:12345] AH02032: ...

Bu formatı awk gözüyle şöyle okuyun: Köşeli parantezler içinde zaman damgası, hata modülü ve seviyesi, process ID, istemci bilgisi ve hata mesajı. Alan ayırıcı olarak boşluk kullanılıyor ama köşeli parantezler işleri biraz karmaşık hale getiriyor. Bu yüzden awk‘ın -F seçeneğini ve regex’i birlikte kullanmayı öğrenmek kritik önem taşıyor.

Temel Hata Tespiti: İlk Adımlar

En basit ama en çok işe yarayan komutla başlayalım. Hata seviyelerini saymak:

awk '{ match($0, /[(.*?):error]/, arr); if (arr[1] != "") print arr[1] }' /var/log/apache2/error.log | sort | uniq -c | sort -rn

Bu komut size hangi modülün kaç adet hata ürettiğini verir. Çıktı şuna benzer:

    847 php
    234 core
     89 ssl
     12 authz_core
      3 rewrite

PHP’nin 847 hata ürettiğini görünce ne yaparsınız? Tabii ki daha derine inersiniz. İşte o zaman ikinci seviyeye geçiyoruz:

awk '/[php:error]/ { 
    match($0, /PHP (.*?):/, arr)
    if (arr[1] != "") print arr[1]
}' /var/log/apache2/error.log | sort | uniq -c | sort -rn | head -20

Bu size PHP hata tiplerinin dağılımını verir: Fatal error, Warning, Notice gibi. Prodüksiyonda bunu gördüğünüzde hangi hata tipinin gerçekten kritik olduğunu anında anlarsınız.

Zaman Bazlı Trend Analizi: İşin Kalbi

Şimdi asıl güce gelelim. Bir hatanın kaç kez oluştuğunu bilmek yeterli değil; ne zaman oluştuğunu bilmek, sorunu çözmenin anahtarıdır. Gece 03:00’te başlayan bir hata artışı, muhtemelen o saatte çalışan bir cron job’ı işaret eder.

Saatlik hata dağılımını çıkaran bir awk betiği:

awk '{
    match($0, /[([A-Za-z]+ [A-Za-z]+ [0-9]+ ([0-9]+):[0-9]+:[0-9]+)/, arr)
    if (arr[2] != "") {
        hour = arr[2]
        count[hour]++
    }
}
END {
    for (h in count) {
        printf "%s:00 --> %d hatan", h, count[h]
    }
}' /var/log/apache2/error.log | sort

Bu betiği bir adım daha ileri götürelim. Dakika bazında analiz yaparsak, trafiğin tam olarak hangi zaman diliminde patladığını görebiliriz:

awk '{
    match($0, /[([A-Za-z]+ [A-Za-z]+ [0-9]+ ([0-9]+:[0-9]+))/, arr)
    if (arr[2] != "") {
        minute = arr[2]
        errors[minute]++
        
        if (/[php:error]/) php_errors[minute]++
        if (/[ssl:error]/) ssl_errors[minute]++
        if (/[core:error]/) core_errors[minute]++
    }
}
END {
    print "ZamanttToplamtPHPtSSLtCore"
    print "--------------------------------------------"
    for (t in errors) {
        printf "%st%dt%dt%dt%dn", t, errors[t], 
               php_errors[t]+0, ssl_errors[t]+0, core_errors[t]+0
    }
}' /var/log/apache2/error.log | sort

Bunu çalıştırdığınızda, her dakika için hata tipi bazında bir breakdown elde edersiniz. Bir sabah standupında “14:23’te PHP hatalarımız normalin 40 katına çıktı, deploy tam o sıradaydı” diyebilmek, tahmin üzerine konuşmaktan çok daha güçlüdür.

Kritik IP Adreslerini İzole Etmek

Bazen sorun sunucu tarafında değil, belirli bir istemciden geliyordur. Özellikle brute force saldırılarında veya kötü configure edilmiş bir uygulama sunucusu bağlantısında bu pattern net görünür:

awk '{
    match($0, /[client ([0-9]+.[0-9]+.[0-9]+.[0-9]+)/, arr)
    if (arr[1] != "") {
        ip = arr[1]
        ip_count[ip]++
        
        if (/AH01797|AH02811|AH01630/) {
            auth_fail[ip]++
        }
    }
}
END {
    print "=== En Fazla Hata Üreten IP Adresleri ==="
    for (ip in ip_count) {
        if (ip_count[ip] > 50) {
            printf "IP: %-20s Toplam: %-8d Auth_Fail: %dn", 
                   ip, ip_count[ip], auth_fail[ip]+0
        }
    }
}' /var/log/apache2/error.log | sort -k4 -rn

Bu komutta dikkat etmeniz gereken nokta, AH01797, AH02811 ve AH01630 hata kodları. Bunlar Apache’nin authentication failure kodları. Bir IP’den bu kodlar yüksek sayıda geliyorsa, fail2ban kurallarınızı gözden geçirmeniz gerekiyor demektir.

Hata Sıklığı ile Alarm Eşiği Belirleme

Gerçek dünyada en çok işe yarayan şeylerden biri, hata sıklığının ne zaman “normal” sınırı aştığını otomatik olarak tespit etmektir. Şöyle bir senaryo düşünün: son 5 dakikada hata sayısı aniden 3 katına çıktı. Bunu awk ile nasıl yakalarsınız?

#!/bin/bash
# Son 10 dakikanın hata yoğunluğunu analiz et

LOGFILE="/var/log/apache2/error.log"
THRESHOLD=100

awk -v threshold="$THRESHOLD" '
{
    match($0, /[([A-Za-z]+ [A-Za-z]+ [0-9]+ [0-9]+:[0-9]+)/, arr)
    if (arr[1] != "") {
        timekey = arr[1]
        total[timekey]++
        
        if (/error|crit|alert|emerg/) {
            critical[timekey]++
        }
    }
}
END {
    for (t in total) {
        if (critical[t]+0 > threshold) {
            printf "[ALARM] %s --> %d kritik hata (esik: %d)n", 
                   t, critical[t], threshold
        }
    }
}' "$LOGFILE" | sort

Bu betiği cron’a ekleyip çıktıyı bir Slack webhook’una veya mail’e yönlendirirseniz, basit ama etkili bir monitoring sistemi kurmuş olursunuz. Datadog veya Grafana her ortamda olmayabilir ama awk ve cron her yerde vardır.

SSL Hatalarını Derinlemesine Analiz Etmek

SSL sorunları, özellikle prodüksiyon ortamlarında sessiz sedasız büyüyen ve bir anda patlayan türden sorunlardır. Sertifika yenileme süreci bozulmuş mu? Eski TLS versiyonlarına bağlanmaya çalışan istemciler var mı? Bunları awk ile tespit edebilirsiniz:

awk '/[ssl:error]/ {
    # AH02042: SSL handshake failure
    if (/AH02042/) handshake_fail++
    
    # AH02004: SSL certificate verify failed  
    if (/AH02004/) cert_verify_fail++
    
    # Protokol hatasi
    if (/tlsv1 alert|sslv3 alert/) protocol_err++
    
    # Genel SSL hatasi
    ssl_total++
    
    # Saati kaydet
    match($0, /[([A-Za-z]+ [A-Za-z]+ [0-9]+ ([0-9]+)):[0-9]+:[0-9]+/, arr)
    if (arr[2] != "") ssl_by_hour[arr[2]]++
    
} END {
    print "=== SSL Hata Ozeti ==="
    printf "Toplam SSL Hatasi  : %dn", ssl_total
    printf "Handshake Failure  : %dn", handshake_fail+0
    printf "Cert Verify Failed : %dn", cert_verify_fail+0
    printf "Protokol Hatasi    : %dn", protocol_err+0
    
    print "n=== Saatlik SSL Hata Dagilimi ==="
    for (h in ssl_by_hour) {
        printf "Saat %s:00 --> %d hatan", h, ssl_by_hour[h]
    }
}' /var/log/apache2/error.log | sort

Bunu çalıştırdıktan sonra gece 03:00-04:00 arasında handshake hatalarının yüksek olduğunu görürseniz, muhtemelen Let’s Encrypt yenileme sürecinde bir sorun var demektir. Certbot bazen yenileme sırasında kısa süreli de olsa servisi etkiler. Bu saatte yenileme yapıyor olması da ayrı bir sorundur.

Çok Dosyalı Analiz: Rotated Loglar ile Çalışmak

Prodüksiyonda çoğunlukla tek bir log dosyasıyla değil, rotate edilmiş onlarca dosyayla uğraşırsınız. error.log, error.log.1, error.log.2.gz şeklinde devam eden bir yapıda haftalık trend analizi yapmak istiyorsanız:

#!/bin/bash
# Tum rotate edilmis loglari analiz et

analyze_log() {
    local file=$1
    awk '{
        match($0, /[(Mon|Tue|Wed|Thu|Fri|Sat|Sun) ([A-Za-z]+) ([0-9]+)/, arr)
        if (arr[3] != "") {
            day_key = arr[2] " " arr[3]
            daily_count[day_key]++
            
            if (/[php:error]/) php_daily[day_key]++
            if (/[ssl:error]/) ssl_daily[day_key]++
            if (/crit|alert|emerg/) critical_daily[day_key]++
        }
    }
    END {
        for (day in daily_count) {
            printf "%s|%d|%d|%d|%dn", day, daily_count[day], 
                   php_daily[day]+0, ssl_daily[day]+0, critical_daily[day]+0
        }
    }' "$file"
}

echo "Tarih|Toplam|PHP|SSL|Kritik"
echo "================================"

# Normal log
if [ -f /var/log/apache2/error.log ]; then
    analyze_log /var/log/apache2/error.log
fi

# Rotate edilmis loglar
for i in {1..7}; do
    logfile="/var/log/apache2/error.log.$i"
    gzfile="${logfile}.gz"
    
    if [ -f "$logfile" ]; then
        analyze_log "$logfile"
    elif [ -f "$gzfile" ]; then
        # Gzip dosyasini decompress ederek analiz et
        zcat "$gzfile" | awk '{
            match($0, /[(Mon|Tue|Wed|Thu|Fri|Sat|Sun) ([A-Za-z]+) ([0-9]+)/, arr)
            if (arr[3] != "") {
                day_key = arr[2] " " arr[3]
                daily_count[day_key]++
                if (/[php:error]/) php_daily[day_key]++
                if (/[ssl:error]/) ssl_daily[day_key]++  
                if (/crit|alert|emerg/) critical_daily[day_key]++
            }
        }
        END {
            for (day in daily_count) {
                printf "%s|%d|%d|%d|%dn", day, daily_count[day],
                       php_daily[day]+0, ssl_daily[day]+0, critical_daily[day]+0
            }
        }'
    fi
done | sort

Bu betiği çalıştırdığınızda, son 7 günün günlük bazda hata trendini tek bir çıktıda görürsünüz. Hafta başına kıyasla Cuma günü belirgin bir artış varsa, CI/CD pipeline’ınızın deployment zamanlamasını gözden geçirmeniz gerekebilir.

Hata Mesajı Parmak İzi Çıkarmak

En gelişmiş tekniklerden biri, benzer hata mesajlarını gruplamaktır. Aynı hatanın farklı değişkenlerle üretildiği durumları (örneğin farklı dosya yolları veya farklı satır numaraları içeren aynı hata) tespit etmek için:

awk '/[php:error]/ {
    msg = $0
    
    # Dosya yollarini normaliz et
    gsub(//[a-zA-Z0-9/_.-]+.php(:[0-9]+)?/, "/PATH/FILE.php", msg)
    
    # IP adreslerini normaliz et
    gsub(/[0-9]+.[0-9]+.[0-9]+.[0-9]+/, "IP_ADDR", msg)
    
    # Sayilari normaliz et
    gsub(/line [0-9]+/, "line N", msg)
    
    # Zaman damgasini cikar
    gsub(/^[[^]]+] [[^]]+] [[^]]+] [[^]]+] /, "", msg)
    
    # Mesaj parmak izi
    fingerprint[msg]++
}
END {
    for (fp in fingerprint) {
        if (fingerprint[fp] > 5) {
            printf "SAYI: %-6d | %sn", fingerprint[fp], substr(fp, 1, 100)
        }
    }
}' /var/log/apache2/error.log | sort -rn | head -20

Bu teknik, loglarda “gürültüyü” azaltır ve gerçekten önemli olan benzersiz hata kalıplarına odaklanmanızı sağlar. Bir e-ticaret projesinde bu yöntemi kullanarak 15.000 log satırının aslında sadece 7 farklı hatanın tekrarından oluştuğunu keşfetmiştim. O 7 hatayı çözmek tüm gürültüyü ortadan kaldırdı.

Gerçek Dünya Senaryosu: Yavaş Yanıt Veren Uygulama Tespiti

Son olarak, pratik bir senaryo: uygulamanız yavaş yanıt veriyor ve hata loglarında AH00957 (proxy hatası) görüyorsunuz. Hangi backend sunucusunun sorun çıkardığını tespit etmek için:

awk '/AH00957|AH01102|proxy/ {
    # Backend sunucu adresini cek
    match($0, /proxy: ([A-Z]+) to ([^:]+:[0-9]+)/, arr)
    if (arr[2] != "") {
        backend = arr[2]
        backend_errors[backend]++
        backend_type[backend] = arr[1]
        
        # Saatlik dagilim
        match($0, /[([A-Za-z]+ [A-Za-z]+ [0-9]+ ([0-9]+)):[0-9]+:[0-9]+/, tarr)
        if (tarr[2] != "") {
            backend_hourly[backend ":" tarr[2]]++
        }
    }
}
END {
    print "=== Proxy Hata Raporu ==="
    for (b in backend_errors) {
        printf "nBackend  : %s (%s)n", b, backend_type[b]
        printf "Toplam   : %d hatan", backend_errors[b]
        printf "Dagilim  : "
        
        for (key in backend_hourly) {
            split(key, parts, ":")
            if (parts[1] ":" parts[2] == b) {
                printf "Saat %s-->%d  ", parts[3], backend_hourly[key]
            }
        }
        print ""
    }
}' /var/log/apache2/error.log

Bu komut, sorunlu backend’i ve hangi saatlerde yoğunlaştığını net biçimde ortaya koyar.

Pratik İpuçları ve Dikkat Edilmesi Gerekenler

awk ile log analizi yaparken birkaç noktaya dikkat etmek gerekiyor:

  • Büyük dosyalar için akıllı okuma: Birkaç GB’lık log dosyasında awk beklenenden yavaş çalışabilir. tail -n 50000 error.log | awk ... şeklinde son N satırla başlayın.
  • Zaman dilimi tutarsızlıkları: Apache logları sunucu yerel saatini kullanır. Eğer sunucularınız farklı zaman dilimlerindeyse veya UTC kullanıyorsanız, match pattern’lerinizi buna göre ayarlayın.
  • Özel karakterlerden kaçınma: Hata mesajlarında köşeli parantez, eğik çizgi ve nokta gibi karakterler sık görünür. awk regex’lerinde bunları [, /, . şeklinde escape etmeyi unutmayın.
  • gawk vs mawk: Ubuntu’da varsayılan awk genellikle mawk‘tır. match fonksiyonunun üçüncü parametresi (dizi yakalama) gawk‘a özgüdür. Bu özelliği kullanıyorsanız, script başına #!/usr/bin/gawk -f ekleyin veya gawk çağırın.
  • Bellek yönetimi: Milyonlarca satırlık loglarda büyük diziler oluşturmak bellek sorununa yol açabilir. Mümkün olduğunda sort | uniq -c kombinasyonunu awk‘ın array mekanizmasına tercih edin.

Sonuç

awk, log analizi için hala rakipsiz bir araçtır. Öğrenme eğrisi var, kabul ediyorum. Ama bir kez alıştığınızda, tek bir komut satırında saatlerce sürecek manuel analizleri dakikalar içinde yapabiliyorsunuz.

Bu yazıda gösterdiğim teknikleri üretim ortamınıza adapt ederken, önce küçük log örnekleri üzerinde test edin. Apache log formatı versiyon ve konfigürasyona göre farklılık gösterebilir; kendi ortamınızda birkaç satır örnek alıp awk '{print $1, $2, $3}' gibi basit komutlarla alanları incelemek, regex’lerinizi doğru kurgulamanızı sağlar.

Son olarak şunu söyleyeyim: awk bilmek, bir sistem yöneticisini müdahale eden biri olmaktan analiz eden birine dönüştürür. Gece yarısı çağrısı geldiğinde, log dosyasına körü körüne bakmak yerine, trend analizi yapıp “sorun şu saat aralığında başladı, şu bileşenden kaynaklanıyor” diyebilmek, hem sizi hem de ekibinizi çok farklı bir noktaya taşır.

Bir yanıt yazın

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