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
awkbeklenenden 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,
matchpattern’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.
awkregex’lerinde bunları[,/,.şeklinde escape etmeyi unutmayın.
gawkvsmawk: Ubuntu’da varsayılanawkgenelliklemawk‘tır.matchfonksiyonunun üçüncü parametresi (dizi yakalama)gawk‘a özgüdür. Bu özelliği kullanıyorsanız, script başına#!/usr/bin/gawk -fekleyin veyagawkç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 -ckombinasyonunuawk‘ı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.
