Günde yüzlerce gigabyte log üreten bir sunucuda bir problemi elle aramaya çalışmak, samanlıkta iğne aramaktan farksızdır. Ama doğru araçları biliyorsan, o iğneyi birkaç saniyede bulabilirsin. grep ve awk ikilisi, Linux dünyasının en güçlü metin işleme araçlarından ikisi. Ayrı ayrı da güçlüler ama birlikte kullandığında log analizini bambaşka bir seviyeye taşıyorsun. Bu yazıda gerçek dünya senaryolarıyla bu ikilinin nasıl kullanılacağını anlatacağım.
grep ve awk Nedir, Ne Zaman Hangisini Kullanırsın?
Önce kısa bir özet yapalım. grep (Global Regular Expression Print), bir dosyada ya da stdin’de pattern aramak için kullanılan bir araç. Bir satırın içinde belirli bir kelime ya da regex pattern varsa o satırı döndürür. Hızlıdır, basittir, çoğu zaman ilk filtreleme için idealdir.
awk ise daha güçlü bir metin işleme dili. Satırları sütunlara böler, matematiksel işlemler yapar, koşullu mantık uygular, toplama yapar, saydırır. grep “bu satırı ver” diyorsa, awk “bu satırdaki şu alanı al, şu koşulu karşılıyorsa şunu yap” diyor.
İkisini pipe (|) ile birleştirdiğinde ortaya çıkan şey şu: önce grep ile alakasız satırları ayıklarsın, sonra awk ile kalan satırlar üzerinde derinlemesine analiz yaparsın. Bu kombinasyon, hem performans hem de okunabilirlik açısından tek bir karmaşık awk komutundan genellikle daha iyidir.
Temel Söz Dizimi ve Parametreler
Önce kullanacağımız temel parametreleri gözden geçirelim.
grep için sık kullanılan parametreler:
- -i: Büyük/küçük harf duyarsız arama yapar
- -v: Pattern ile eşleşmeyen satırları döndürür (invert match)
- -E: Extended regular expression kullanımını aktif eder
- -o: Sadece eşleşen kısmı döndürür, satırın tamamını değil
- -c: Eşleşen satır sayısını döndürür
- -n: Satır numarasını gösterir
- -A [n]: Eşleşmeden sonra n satır daha gösterir
- -B [n]: Eşleşmeden önce n satır daha gösterir
- -r: Dizin içinde recursive arama yapar
- –color: Eşleşen kısmı renkli gösterir
awk için temel yapı:
- -F: Alan ayırıcısını (field separator) belirler, örneğin
-F:iki nokta ile ayırır - NR: Geçerli satır numarası
- NF: Geçerli satırdaki alan (sütun) sayısı
- $1, $2…: Birinci, ikinci alan gibi belirli sütunlara erişim
- $0: Satırın tamamı
- BEGIN: Dosya işlenmeden önce çalışacak blok
- END: Dosya işlendikten sonra çalışacak blok
Nginx/Apache Access Log Analizi
Web sunucusu logları, sysadminlerin en çok uğraştığı log türlerinden biri. Tipik bir Nginx access log satırı şöyle görünür:
192.168.1.105 - - [15/Jan/2024:10:23:45 +0300] "GET /api/users HTTP/1.1" 200 1234 "-" "Mozilla/5.0"
Önce sadece HTTP 500 hatalarını listeleyelim:
grep ' 500 ' /var/log/nginx/access.log | awk '{print $1, $7, $9}' | sort | uniq -c | sort -rn | head -20
Bu komut şunu yapıyor: önce grep ile 500 durum kodu içeren satırları filtreler, sonra awk ile IP adresi ($1), istek path’i ($7) ve durum kodunu ($9) alır, sort | uniq -c ile tekrarları sayar ve en fazla hata üreten kombinasyonları listeler.
Belirli bir zaman aralığındaki hataları bulmak için:
grep '15/Jan/2024:10' /var/log/nginx/access.log | grep -E ' (4[0-9]{2}|5[0-9]{2}) ' | awk '{print $9}' | sort | uniq -c | sort -rn
Bu komutta önce saat 10:xx bandındaki tüm kayıtları çekiyoruz, sonra 4xx ve 5xx hatalarını filtreliyoruz, son olarak awk ile durum kodunu alıp hangi hata kodundan kaç tane geldiğini sayıyoruz.
Peki en çok istek atan IP adreslerini bulmak istersen? DDoS tespiti ya da rate limiting için oldukça kullanışlı:
awk '{print $1}' /var/log/nginx/access.log | grep -E '^[0-9]+.[0-9]+.[0-9]+.[0-9]+$' | sort | uniq -c | sort -rn | head -10
Burada awk‘ı önce kullandık çünkü sadece IP sütununu almak istedik, sonra grep ile geçerli IP formatını doğruladık.
Syslog ve Authentication Log Analizi
/var/log/auth.log veya /var/log/secure, başarısız SSH giriş denemelerini, sudo kullanımlarını ve diğer kimlik doğrulama olaylarını tutar. Brute force saldırılarını tespit etmek için:
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -15
$(NF-3) ifadesi, sondan üçüncü alanı verir. Auth log formatında bu genellikle IP adresidir. Bu komutu çalıştırdığında en çok başarısız deneme yapan IP’leri görürsün.
Belirli bir IP’nin hangi kullanıcı adlarını denediğini görmek için:
grep "Failed password" /var/log/auth.log | grep "192.168.1.50" | awk '{print $9}' | sort | uniq -c | sort -rn
Başarılı girişleri listelemek de güvenlik denetimi için kritik:
grep "Accepted password|Accepted publickey" /var/log/auth.log | awk '{print $1, $2, $3, $9, $11}' | tail -50
Bu komut tarih, saat, kullanıcı adı ve IP adresini güzel bir formatta listeler.
Uygulama Loglarından Hata Analizi
Birçok uygulama kendi format loglarını üretir. Örneğin bir Java uygulamasının log dosyasında ERROR ve WARN seviyesindeki mesajları analiz edelim:
grep -E "^[0-9]{4}-[0-9]{2}-[0-9]{2}.*s(ERROR|WARN)s" /var/log/myapp/application.log |
awk '{
date=$1;
time=$2;
level=$3;
msg="";
for(i=4;i<=NF;i++) msg=msg" "$i;
print date, time, level, substr(msg,1,80)
}' | tail -100
Bu biraz daha karmaşık bir awk kullanımı. for döngüsüyle dördüncü alandan itibaren tüm kelimeleri birleştirerek mesajı oluşturuyoruz, substr ile de 80 karakterle kısıtlıyoruz.
Belirli bir zaman aralığında kaç ERROR olduğunu saymak için:
grep "2024-01-15" /var/log/myapp/application.log | grep " ERROR " | awk '{print substr($2,1,2)}' | sort | uniq -c
Bu komut, saate göre gruplandırılmış ERROR sayısını verir. substr($2,1,2) saat:dakika:saniye formatındaki ikinci alandan sadece ilk iki karakteri (saat) alır. Hangi saatte hata yoğunlaştığını görmek için harika.
Gerçek Dünya Senaryosu: Yavaş Sorgu Tespiti
MySQL slow query log’u analiz etmek, veritabanı performans sorunlarını çözmede kritik öneme sahip. Tipik bir slow query log girişi birden fazla satır içerir:
grep -A 4 "Query_time:" /var/log/mysql/mysql-slow.log |
grep -E "Query_time: [5-9].|Query_time: [0-9]{2,}" |
awk -F'[:=]' '{print $3}' |
awk '{print int($1)" saniye"}' |
sort -n | uniq -c | sort -rn | head -20
Bu örnekte grep -A 4 ile sorgunun tamamını alıyoruz, sonra 5 saniyeden uzun süren sorguları filtreliyoruz, son olarak awk ile zamanı parse edip analiz ediyoruz.
Daha basit ama etkili bir yaklaşım: hangi veritabanının yavaş sorgu ürettiğini bulmak:
grep "^# Schema:" /var/log/mysql/mysql-slow.log |
awk '{print $3}' |
sort | uniq -c | sort -rn
Büyük Log Dosyalarında Performans İpuçları
Production ortamında loglar gigabyte boyutlarına ulaşabilir. Performans için birkaç kritik ipucu:
grep‘i her zaman önce kullan. awk‘a büyük bir dosya vermek yerine önce grep ile dosyayı küçült:
# Yavaş yol:
awk '/ERROR/ {print $0}' /var/log/app/huge.log
# Hızlı yol:
grep "ERROR" /var/log/app/huge.log | awk '{print $0}'
Birden fazla log dosyasını aynı anda işlemek için:
grep -h "ERROR" /var/log/app/app.log* | awk '{print $1, $2, $NF}' | sort | uniq -c | sort -rn
-h parametresi dosya adını çıktıya eklemez, temiz bir sonuç elde edersin.
Sıkıştırılmış log dosyalarını doğrudan işlemek için zgrep ve zcat kullanabilirsin:
zgrep "CRITICAL" /var/log/app/app.log.*.gz | awk -F: '{print $1}' | sort | uniq -c
awk ile İstatistik Üretmek
awk‘ın en güçlü yanlarından biri matematiksel işlemler yapabilmesidir. Nginx loglarından toplam transfer edilen veriyi hesaplayalım:
grep "200" /var/log/nginx/access.log | awk '{sum += $10} END {printf "Toplam transfer: %.2f MBn", sum/1024/1024}'
$10 alanı Nginx loglarında byte cinsinden response boyutunu tutar. END bloğu tüm satırlar işlendikten sonra çalışır ve toplamı yazdırır.
Saatlik istek dağılımını grafiksel olarak göstermek için küçük bir trick:
grep "15/Jan/2024" /var/log/nginx/access.log |
awk -F'[/:]' '{print $4}' |
sort | uniq -c |
awk '{bar=""; for(i=0;i<$1/100;i++) bar=bar"#"; printf "%s:00 [%5d] %sn", $2, $1, bar}'
Bu komut saatlik istek sayısını hash karakterleriyle basit bir bar chart olarak gösterir. Her 100 istek için bir # koyar. Production’da bunu görünce meslektaşların mutlu olur.
Ortalama response time hesaplamak için (Nginx logunda $NF veya özel format kullanıyorsan):
grep "api/v1/users" /var/log/nginx/access.log |
awk '{sum+=$NF; count++} END {if(count>0) printf "Ortalama: %.3f ms, Toplam istek: %dn", sum/count, count}'
Multiline Log Parsing: Gelişmiş Teknikler
Bazı uygulamalar stack trace gibi çok satırlı loglar üretir. Bu durumda grep -A ile birlikte kullanmak işe yarar:
grep -n "NullPointerException" /var/log/app/application.log |
awk -F: '{print $1}' |
while read linenum; do
sed -n "${linenum},$((linenum+15))p" /var/log/app/application.log
echo "---"
done
Bu bash script yaklaşımı, grep ile satır numaralarını buluyor, sonra her bir eşleşme için sed ile 15 satırlık context alıyor.
Belirli bir exception’ın günlük kaç kez göründüğünü saymak için:
grep "Exception" /var/log/app/application.log |
grep -v "^[[:space:]]" |
awk '{match($0, /[A-Za-z]+Exception/); if(RSTART>0) print substr($0,RSTART,RLENGTH)}' |
sort | uniq -c | sort -rn | head -10
grep -v "^[[:space:]]" ile girintili satırları (stack trace içindeki satırlar) eliyoruz, sadece exception’ı içeren ana satırları tutuyoruz.
Canlı Log Takibi ile Kombinasyon
tail -f ile grep ve awk’ı birleştirerek canlı log takibi yapabilirsin. Özellikle deployment sırasında ya da bir incident anında çok işe yarar:
tail -f /var/log/nginx/access.log | grep --line-buffered " 5[0-9][0-9] " | awk '{print strftime("%H:%M:%S"), $1, $7, $9}'
--line-buffered parametresi kritik. Olmadan grep çıktıyı buffer’layabilir ve canlı takip bozulur. strftime ile mevcut zamanı da ekliyoruz.
Birden fazla log dosyasını aynı anda canlı takip etmek için:
tail -f /var/log/nginx/error.log /var/log/app/application.log |
grep --line-buffered -E "ERROR|CRITICAL|alert" |
awk '{print FILENAME, $0}'
Pratik Alias ve Script Önerileri
Bu komutları her seferinde yazmak yerine .bashrc veya .bash_aliases dosyana ekleyebileceğin birkaç alias:
# Son 1 saatteki HTTP hatalarını listele
alias weberrors='grep "$(date +%d/%b/%Y:%H)" /var/log/nginx/access.log | grep -E " [45][0-9]{2} " | awk '"'"'{print $9, $7, $1}'"'"' | sort | uniq -c | sort -rn'
# SSH brute force kontrolü
alias sshattack='grep "Failed password" /var/log/auth.log | awk '"'"'{print $(NF-3)}'"'"' | sort | uniq -c | sort -rn | head -20'
# Top 10 en büyük istek yapan IP
alias topip='awk '"'"'{print $1}'"'"' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10'
Alias’larda tek tırnak içinde tek tırnak kullanmak zahmetli. Bu yüzden daha karmaşık kombinasyonları bir script dosyasına almak çok daha temiz:
#!/bin/bash
# /usr/local/bin/logcheck.sh
LOG_FILE="${1:-/var/log/nginx/access.log}"
DATE="${2:-$(date +%d/%b/%Y)}"
echo "=== $DATE tarihi için log analizi ==="
echo ""
echo "--- HTTP Hata Dağılımı ---"
grep "$DATE" "$LOG_FILE" | grep -E " [45][0-9]{2} " |
awk '{print $9}' | sort | uniq -c | sort -rn
echo ""
echo "--- Top 10 IP ---"
grep "$DATE" "$LOG_FILE" |
awk '{print $1}' | sort | uniq -c | sort -rn | head -10
echo ""
echo "--- Toplam İstek Sayısı ---"
grep -c "$DATE" "$LOG_FILE"
Bu scripti chmod +x /usr/local/bin/logcheck.sh yapıp her yerden çağırabilirsin.
Logrotate Sonrası Dönemsel Analiz
Logrotate ile döndürülmüş dosyaları analiz etmen gerektiğinde, tüm dönemsel dosyalara toplu bakmak için:
ls -t /var/log/nginx/access.log* | head -7 |
xargs grep -h "ERROR|error" |
awk '{print $1}' |
sort | uniq -c | sort -rn
Son 7 log dosyasındaki hataları birleştirip tarihe göre gruplayan bu komut, haftalık trend analizi için işe yarar.
Sonuç
grep ve awk kombinasyonu, bir sysadmin’in toolbox’ındaki en kıymetli ikililerden biri. grep hızlı filtreleme yaparak işlenecek veriyi küçültürken, awk üzerine gerçekten güçlü analiz ve raporlama ekler. Bu ikisini pipe ile bağladığında ortaya çıkan araç zinciri, çoğu log analizi senaryosunu kolaylıkla karşılar.
Önemli birkaç noktayı vurgulayalım:
- Her zaman önce
grepile filtrele, sonraawkile işle. Bu yaklaşım büyük dosyalarda ciddi performans farkı yaratır. --line-bufferedparametresini canlı log takibinde unutma.- Sık kullandığın komutları alias veya script olarak kaydet, zamanla kendi kütüphaneni oluştur.
- Regex pattern’lerini önce küçük test dosyalarında dene, production’da doğrudan büyük dosyalara uygulamadan önce doğrula.
- Karmaşık
awkbloklarını tek satırda yazmak yerine script dosyasına al, okunabilirlik önemli.
Bu araçları ne kadar çok kullanırsan, log analizinde o kadar hızlanırsın. Bir süre sonra log dosyasına bakıp saniyeler içinde problemi tespit etmeye başlarsın. O noktaya geldiğinde, “grep ve awk öğrendiğim gün hayatım değişti” diye düşünebilirsin.