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.log ile 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.

Bir yanıt yazın

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