Nginx Access Log Analizi ile API İzleme
Bir API’nin gerçekten ne yaptığını anlamak istiyorsanız, en dürüst kaynak her zaman access log’larıdır. Metrikler yalan söyleyebilir, monitoring araçları gözden kaçırabilir ama Nginx’in kaydettiği her satır, o ana kadar yaşananların ham gerçeğidir. Bu yazıda, Nginx access log’larını kullanarak API’lerinizi nasıl izleyeceğinizi, performans sorunlarını nasıl tespit edeceğinizi ve güvenlik tehditlerini nasıl erkenden fark edeceğinizi ele alacağız.
Nginx Log Formatını API İzleme İçin Yapılandırmak
Varsayılan Nginx log formatı, API izleme için yeterince zengin değildir. Özellikle $request_time, $upstream_response_time ve $status gibi alanlar olmadan anlamlı bir analiz yapmak zordur. İşe doğru bir log formatı tanımlamaktan başlayalım.
# /etc/nginx/nginx.conf - http bloğuna ekleyin
http {
log_format api_detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time '
'uct=$upstream_connect_time '
'uht=$upstream_header_time '
'urt=$upstream_response_time '
'cs=$upstream_cache_status '
'xff=$http_x_forwarded_for '
'api_key="$http_x_api_key"';
access_log /var/log/nginx/api_access.log api_detailed buffer=16k flush=5s;
}
Bu formatta birkaç kritik alan var:
- rt: Toplam istek süresi (saniye cinsinden)
- uct: Upstream bağlantı süresi
- uht: Upstream header alma süresi
- urt: Upstream yanıt süresi, backend performansını ölçmek için en önemli alan
- cs: Cache durumu, HIT/MISS/BYPASS değerlerini gösterir
- api_key: X-Api-Key header’ını loglamak, hangi istemcinin ne yaptığını takip etmenizi sağlar
buffer=16k flush=5s ayarı, log yazma işlemini tamponlayarak disk I/O baskısını azaltır. Yoğun trafikli API’lerde bu ayar olmadan log yazmak başlı başına bir performans sorunu haline gelebilir.
Log Rotasyonu ve Temel Yapılandırma
Log’ları düzgün döndürmeden önce, logrotate konfigürasyonunuzu API log hacmine göre ayarlamanız gerekir.
# /etc/logrotate.d/nginx-api
/var/log/nginx/api_access.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
Yoğun API trafiğinde daily yerine hourly da kullanabilirsiniz. kill -USR1 sinyali Nginx’i yeniden başlatmadan log dosyasını yeniden açmasını sağlar, bu nedenle zero-downtime için önemlidir.
Gerçek Zamanlı Log Analizi: Temel Komutlar
Bir sorun patlak verdiğinde hızlıca bilgi toplamak için birkaç temel komutu ezberlemeniz gerekir.
# Son 5 dakikada gelen istekleri endpoint'e göre say
tail -5000 /var/log/nginx/api_access.log |
awk '{print $7}' |
cut -d'?' -f1 |
sort | uniq -c | sort -rn | head -20
# 500 hata veren endpoint'leri bul
grep ' 500 ' /var/log/nginx/api_access.log |
awk '{print $7}' |
cut -d'?' -f1 |
sort | uniq -c | sort -rn | head -10
# Ortalama response time'ı hesapla
awk '/api_access/ {match($0, /rt=([0-9.]+)/, arr); if(arr[1]) sum+=arr[1]; count++} END {print "Avg RT:", sum/count "s"}'
/var/log/nginx/api_access.log
# Yavaş istekleri bul (1 saniyeden uzun)
grep -E 'rt=[1-9][0-9]*.' /var/log/nginx/api_access.log |
awk '{match($0, /rt=([0-9.]+)/, rt); match($0, /"[A-Z]+ ([^ ]+)/, url); print rt[1]"s", url[1]}' |
sort -rn | head -20
Özellikle cut -d'?' -f1 kısmını atlamamak önemli. Query string parametrelerini dahil ettiğinizde her istek ayrı bir satır haline gelir ve analiz anlamsızlaşır.
HTTP Status Code Dağılımı Analizi
Bir API’nin sağlık durumunu anlamanın en hızlı yolu status code dağılımına bakmaktır.
# Status code dağılımını göster
awk '{print $9}' /var/log/nginx/api_access.log |
sort | uniq -c | sort -rn
# Belirli bir zaman aralığındaki 4xx/5xx oranı
awk '
BEGIN { total=0; errors=0 }
{
total++
if ($9 >= 400) errors++
}
END {
printf "Toplam: %dn", total
printf "Hata: %dn", errors
printf "Hata Orani: %.2f%%n", (errors/total)*100
}' /var/log/nginx/api_access.log
# Saatlik hata trendi
grep ' 50[0-9] ' /var/log/nginx/api_access.log |
awk '{print $4}' |
cut -d: -f1-2 |
tr -d '[' |
sort | uniq -c
Saatlik hata trendi özellikle deploy sonrası izleme için kritik. Yeni bir sürüm çıktıktan sonra bu komutu çalıştırın; 5xx sayısında ani artış varsa deploy’u geri almanın zamanı gelmiş demektir.
IP Bazlı Analiz ve Rate Limit İzleme
API’nizi kimin ne kadar kullandığını ve kimin kötüye kullandığını anlamak için IP bazlı analiz şarttır.
# En çok istek yapan IP'ler
awk '{print $1}' /var/log/nginx/api_access.log |
sort | uniq -c | sort -rn | head -20
# Belirli bir IP'nin hangi endpoint'lere eriştiğini göster
grep "^192.168.1.100" /var/log/nginx/api_access.log |
awk '{print $9, $7}' |
cut -d'?' -f1 |
sort | uniq -c | sort -rn
# Rate limit aşımlarını tespit et (429 status)
grep ' 429 ' /var/log/nginx/api_access.log |
awk '{print $1}' |
sort | uniq -c | sort -rn | head -10
# Son 1 saatte dakika başına 100'den fazla istek yapan IP'leri bul
awk '{
match($4, /[([0-9]+/[A-Za-z]+/[0-9]+:[0-9]+:[0-9]+)/, t)
ip_minute[$1 " " t[1]]++
}
END {
for (key in ip_minute) {
if (ip_minute[key] > 100)
print ip_minute[key], key
}
}' /var/log/nginx/api_access.log | sort -rn
Bu son komut size gerçek bir rate limit implementasyonu için zemin hazırlar. Dakikada 100’den fazla istek yapan IP’leri tespit ettikten sonra bunları otomatik olarak nginx.conf‘a ekleyebilir ya da fail2ban ile engelleyebilirsiniz.
GoAccess ile Görsel Log Analizi
Komut satırı yeterli değilse GoAccess, Nginx log’larını gerçek zamanlı olarak görselleştiren mükemmel bir araçtır.
# GoAccess kurulumu (Ubuntu/Debian)
apt-get install goaccess
# Özel log formatımız için GoAccess konfigürasyonu
cat > /etc/goaccess/goaccess.conf << 'EOF'
time-format %H:%M:%S
date-format %d/%b/%Y
log-format %h - %^ [%d:%t %^] "%r" %s %b "%R" "%u" rt=%T %^
EOF
# Terminalde gerçek zamanlı izleme
goaccess /var/log/nginx/api_access.log
--config-file=/etc/goaccess/goaccess.conf
--real-time-html
--output=/var/www/html/report.html
--daemonize
# Sadece terminal çıktısı için
tail -f /var/log/nginx/api_access.log |
goaccess --config-file=/etc/goaccess/goaccess.conf -
GoAccess’in --real-time-html özelliği WebSocket üzerinden tarayıcıyı canlı olarak günceller. /var/www/html/report.html dosyasını Nginx üzerinden servis ederseniz ekibinizin herhangi bir yerden log analizine bakabilmesini sağlarsınız.
Upstream Performans Analizi
Nginx’in sadece bir kapı olmadığını, aynı zamanda backend’inizin performans monitörü olduğunu unutmayın.
# Upstream response time'ına göre endpoint sıralaması
grep -v '-' /var/log/nginx/api_access.log |
awk '{
match($0, /urt=([0-9.]+)/, urt)
match($0, /"[A-Z]+ (/[^ ?]+)/, url)
if (urt[1] != "" && url[1] != "") {
sum[url[1]] += urt[1]
count[url[1]]++
}
}
END {
for (endpoint in sum) {
printf "%.4f %s (%d req)n", sum[endpoint]/count[endpoint], endpoint, count[endpoint]
}
}' | sort -rn | head -15
# Cache hit/miss oranını hesapla
awk '{
match($0, /cs=([A-Z]+)/, cs)
if (cs[1] != "") cache_stats[cs[1]]++
total++
}
END {
for (status in cache_stats)
printf "%s: %d (%.1f%%)n", status, cache_stats[status], (cache_stats[status]/total)*100
}' /var/log/nginx/api_access.log
Cache hit oranı düşükse (MISS fazlaysa) cache stratejinizi gözden geçirmeniz gerekebilir. Özellikle GET isteklerinde proxy_cache_bypass kurallarınızı kontrol edin.
Otomatik Anomali Tespiti için Shell Script
Düzenli analiz yapmak için cron’a bağlı bir script yazmak, sorunları erken fark etmenizi sağlar.
#!/bin/bash
# /usr/local/bin/api_monitor.sh
# cron: */5 * * * * /usr/local/bin/api_monitor.sh
LOG_FILE="/var/log/nginx/api_access.log"
ALERT_EMAIL="[email protected]"
ERROR_THRESHOLD=5 # % cinsinden kabul edilebilir hata oranı
SLOW_THRESHOLD=2.0 # Yavaş istek eşiği (saniye)
WINDOW=300 # Son 5 dakika
# Son N dakikanın log'larını al
SINCE=$(date -d "$WINDOW seconds ago" +"%d/%b/%Y:%H:%M:%S")
RECENT_LOGS=$(awk -v since="$SINCE" '
{
match($4, /[(.*)/, t)
if (t[1] >= since) print
}' "$LOG_FILE")
# Toplam istek sayısı
TOTAL=$(echo "$RECENT_LOGS" | wc -l)
if [ "$TOTAL" -lt 10 ]; then
echo "Yeterli log yok, cikiyor"
exit 0
fi
# Hata oranı hesapla
ERRORS=$(echo "$RECENT_LOGS" | awk '$9 >= 500' | wc -l)
ERROR_RATE=$(echo "scale=2; ($ERRORS/$TOTAL)*100" | bc)
# Yavaş istek oranı
SLOW=$(echo "$RECENT_LOGS" |
awk -v threshold="$SLOW_THRESHOLD" '{
match($0, /rt=([0-9.]+)/, rt)
if (rt[1]+0 > threshold+0) count++
} END {print count+0}')
SLOW_RATE=$(echo "scale=2; ($SLOW/$TOTAL)*100" | bc)
# Alert koşulları
ALERT=""
if (( $(echo "$ERROR_RATE > $ERROR_THRESHOLD" | bc -l) )); then
ALERT+="KRITIK: Hata orani %${ERROR_RATE} (esik: %${ERROR_THRESHOLD})n"
fi
if (( $(echo "$SLOW_RATE > 10" | bc -l) )); then
ALERT+="UYARI: Yavas istek orani %${SLOW_RATE} (${SLOW_THRESHOLD}s uzeri)n"
fi
if [ -n "$ALERT" ]; then
echo -e "API Monitor Alarmi - $(date)nn${ALERT}nSon 5dk: $TOTAL istek, $ERRORS hata" |
mail -s "[API ALARM] $(hostname)" "$ALERT_EMAIL"
logger -t api_monitor "ALARM: $ALERT"
fi
echo "$(date): Total=$TOTAL Errors=$ERRORS ($ERROR_RATE%) Slow=$SLOW ($SLOW_RATE%)" >> /var/log/api_monitor.log
Bu script’i /usr/local/bin/api_monitor.sh olarak kaydedip çalıştırılabilir yapın:
chmod +x /usr/local/bin/api_monitor.sh
echo "*/5 * * * * root /usr/local/bin/api_monitor.sh" >> /etc/cron.d/api-monitor
Güvenlik Odaklı Log Analizi
API güvenliği için log analizi ayrı bir öneme sahiptir. Yaygın saldırı patterns’larını log’larda aramayı alışkanlık haline getirin.
# SQL injection denemelerini ara
grep -iE "(union|select|insert|drop|update|delete|script|eval)"
/var/log/nginx/api_access.log |
awk '{print $1, $7}' | sort | uniq -c | sort -rn | head -20
# Brute force denemelerini tespit et (401 alan IP'ler)
grep ' 401 ' /var/log/nginx/api_access.log |
awk '{print $1}' |
sort | uniq -c | sort -rn |
awk '$1 > 50 {print "Supheli IP:", $2, "- 401 sayisi:", $1}'
# User-agent analizi (bot tespiti)
awk '{
match($0, /"([^"]+)"$/, ua)
agents[ua[1]]++
}
END {
for (a in agents)
if (agents[a] > 100) print agents[a], a
}' /var/log/nginx/api_access.log | sort -rn | head -15
# API key olmayan istekleri bul
grep 'api_key=""' /var/log/nginx/api_access.log |
awk '{print $1, $7}' |
cut -d'?' -f1 |
sort | uniq -c | sort -rn | head -10
API key olmayan istekleri bulmak için log formatımıza eklediğimiz api_key="$http_x_api_key" alanı burada devreye giriyor. Authentication gerektiren endpoint’lerinize API key olmadan erişmeye çalışan IP’leri bu komutla hızlıca tespit edebilirsiniz.
Prometheus ve Grafana Entegrasyonu için Log Exporter
Modern altyapılarda log analizi sadece komut satırıyla sınırlı kalmamalı. nginx-log-exporter aracıyla Nginx log’larını Prometheus metriklerine dönüştürebilirsiniz.
# nginx-prometheus-exporter kurulumu
wget https://github.com/martin-helmich/prometheus-nginxlog-exporter/releases/latest/download/prometheus-nginxlog-exporter_linux_amd64
-O /usr/local/bin/nginx-log-exporter
chmod +x /usr/local/bin/nginx-log-exporter
# Konfigürasyon dosyası
cat > /etc/nginx-log-exporter.yml << 'EOF'
listen:
port: 4040
address: "0.0.0.0"
namespaces:
- name: api
format: "$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" rt=$request_time uct=$upstream_connect_time uht=$upstream_header_time urt=$upstream_response_time cs=$upstream_cache_status"
source:
files:
- /var/log/nginx/api_access.log
labels:
app: "api-gateway"
histogram_buckets: [0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]
relabel_configs:
- target_label: method
from: method
- target_label: status
from: status
EOF
# Systemd service
cat > /etc/systemd/system/nginx-log-exporter.service << 'EOF'
[Unit]
Description=Nginx Log Prometheus Exporter
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/nginx-log-exporter -config-file /etc/nginx-log-exporter.yml
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now nginx-log-exporter
Bu kurulumdan sonra Prometheus’unuzu http://sunucu-ip:4040/metrics adresini scrape edecek şekilde ayarlayın. Grafana tarafında api_http_response_count_total, api_http_response_size_bytes ve api_http_upstream_time_seconds metriklerini kullanarak dashboard oluşturabilirsiniz.
Gerçek Dünya Senaryosu: Yavaşlayan API Debugı
Bir gece saat 02:00’de “API çok yavaş” şikayetiyle uyandınız diyelim. İşte bu durumda izleyeceğiniz adımlar:
# 1. Son 30 dakikada ortalama response time'ı kontrol et
tail -50000 /var/log/nginx/api_access.log |
awk '{
match($0, /urt=([0-9.-]+)/, urt)
if (urt[1] != "-" && urt[1] != "") {
sum += urt[1]
count++
}
} END {printf "Backend avg RT: %.3fs (%d req)n", sum/count, count}'
# 2. Nginx vs backend arasındaki farkı bul
tail -10000 /var/log/nginx/api_access.log |
awk '{
match($0, /rt=([0-9.]+)/, rt)
match($0, /urt=([0-9.]+)/, urt)
if (rt[1] && urt[1]) {
nginx_overhead = rt[1] - urt[1]
printf "Nginx overhead: %.4fsn", nginx_overhead
}
}' | awk '{sum+=$3; count++} END {printf "Ort Nginx overhead: %.4fsn", sum/count}'
# 3. En yavaş 20 isteği bul ve detaylarını göster
grep -v 'urt=-' /var/log/nginx/api_access.log |
awk '{
match($0, /urt=([0-9.]+)/, urt)
match($0, /[([^]]+)]/, ts)
match($0, /"([^"]+)"/, req)
if (urt[1] != "") print urt[1], ts[1], req[1]
}' | sort -rn | head -20
# 4. Yavaşlamanın hangi saatten itibaren başladığını bul
awk '{
match($4, /[([^:]+:[0-9]+:[0-9]+)/, ts)
match($0, /urt=([0-9.]+)/, urt)
if (ts[1] && urt[1]) {
sum[ts[1]] += urt[1]
count[ts[1]]++
}
} END {
for (t in sum)
printf "%.3f %sn", sum[t]/count[t], t
}' /var/log/nginx/api_access.log | sort -k2 | tail -30
Bu komutlar sırasıyla size şunu söyler: Yavaşlık Nginx’ten mi yoksa backend’den mi kaynaklanıyor? Hangi saatten itibaren başladı? Hangi endpoint’ler etkilendi? Bu bilgilerle 10 dakika içinde sorunun kaynağına ulaşabilirsiniz.
Log Analizi için Önerilen Araç Seti
Sadece native araçlarla sınırlı kalmak zorunda değilsiniz. Aşağıdaki araçlar API log analizini önemli ölçüde kolaylaştırır:
- GoAccess: Gerçek zamanlı terminal ve HTML dashboard için
- lnav: Log dosyalarını SQL ile sorgulamak için mükemmel bir araç,
lnav /var/log/nginx/api_access.logile başlayın - gawk: Standart awk’dan daha güçlü regex desteği, karmaşık analizler için tercih edin
- jq: JSON formatlı log kullanıyorsanız vazgeçilmezdir
- Grafana Loki: Log aggregation için Prometheus ekosistemiyle tam entegrasyon
- Vector veya Fluentd: Log’ları birden fazla hedefe iletmek için, Elasticsearch veya S3’e göndermek gibi durumlarda
Sonuç
Nginx access log’ları, API’nizin gizli hikayesini anlatır. Doğru format, doğru araçlar ve düzenli analiz alışkanlığıyla hem performans sorunlarını proaktif olarak tespit edebilir hem de güvenlik tehditlerini erken aşamada engelleyebilirsiniz. Bu yazıda anlattığımız yaklaşımı sıfırdan kurarken şu sırayla gitmenizi öneririm: önce log formatını zenginleştirin, ardından temel shell scriptlerini kurun, son adımda Prometheus/Grafana entegrasyonunu ekleyin.
Bir sysadmin olarak en büyük hatam, yıllarca varsayılan log formatıyla çalışmak ve bir sorun çıktığında “keşke daha fazla veri kaydetseydim” demek oldu. Log formatını bir kez doğru kurduğunuzda, gelecekteki her soruşturmanız çok daha hızlı ve kesin sonuçlanır. Log’larınız dolu, uptime’ınız yüksek olsun.
