Bu makalede7 bölüm
- Teknoloji
- Nginx, Apache, PHP-FPM, logrotate, rsyslog, Grafana Loki, Elasticsearch/OpenSearch, jq
- Konu
- Web loglarının formatı, rotasyonu ve merkezi toplanması
- Seviye
- Orta
- Ön koşullar
- Linux komut satırı bilgisi
- Nginx veya Apache yapılandırma deneyimi
Gece 03:00’te site 502 veriyor ve elinizdeki tek kanıt web sunucusu logları. O anda işe yarayıp yaramayacakları üç şeye bağlıdır: doğru alanları içeriyorlar mı, disk dolmadan döndürülüyorlar mı, aradığınızı dakikalar içinde bulabileceğiniz bir yerde mi duruyorlar? Aşağıda Nginx, Apache ve PHP-FPM loglarının formatını, logrotate ayarını, merkezi toplama seçeneklerini ve olay anında çalıştırdığımız sorguları anlatıyoruz. Okur, bir veya birkaç Linux web sunucusunu yöneten sistem yöneticileri ve DevOps ekipleri.
Web katmanındaki log türleri
Bir istek yol boyunca birkaç katmandan geçer ve her katman kendi kaydını tutar. Hangi soruyu hangi logda arayacağınızı bilmek, olay anında dakikalar kazandırır:
| Log | Tipik konum | Hangi soruyu yanıtlar |
|---|---|---|
| Nginx/Apache erişim logu | /var/log/nginx/access.log |
Kim, neyi, ne zaman istedi; yanıt kodu ve süresi |
| Nginx/Apache hata logu | /var/log/nginx/error.log |
Upstream bağlantı hataları, izin ve yapılandırma sorunları |
| PHP-FPM süreç logu | /var/log/php8.2-fpm.log |
Havuz doldu mu, worker’lar yeniden başlatıldı mı |
| PHP-FPM slowlog | Havuz yapılandırmasında tanımlı | Yavaş isteklerin hangi fonksiyonda beklediği |
| PHP uygulama hata logu | error_log ayarıyla belirlenen dosya |
Uyarılar, fatal error’lar, uygulama istisnaları |
Konumlar dağıtıma ve panel yazılımına göre değişir; Virtualmin gibi panellerde her sanal sunucunun logları genellikle kendi ev dizini altındadır. Sahada sık karşılaştığımız durum: panelin açtığı site logları paketle gelen logrotate tanımının kapsamı dışında kalır ve aylarca büyür. Her sitenin tüm loglarının nerede olduğunu belgeleyin ve hepsinin aynı rotasyon politikasına dahil olduğunu kontrol edin.
PHP-FPM tarafında iki ayar sık unutulur. request_slowlog_timeout tanımlanmadıkça slowlog yazılmaz. catch_workers_output = yes ise worker’ların standart çıktıya yazdığı hataların FPM loguna düşmesini sağlar. Havuz doluluğu ve yavaş istekleri, performans ayarlarıyla birlikte PHP-FPM ve MariaDB performans sorunları yazısında ele aldık.
Log formatı ve JSON loglama
Varsayılan combined formatı istemci adresi, istek satırı, durum kodu, boyut, referrer ve user agent bilgisini yazar. Sorun gidermede en çok aranan iki bilgi ise yoktur: isteğin ne kadar sürdüğü ve arkadaki uygulamanın ne kadar sürede yanıt verdiği. Süre yoksa yavaşlık tartışması tahmine döner. Reverse proxy veya CDN arkasında istemci adresi doğru aktarılmamışsa tüm istekler aynı IP’den geliyormuş gibi görünür; bunu Nginx reverse proxy yapılandırması yazısında real_ip başlığı altında anlattık.
Merkezi toplama planlıyorsanız logları baştan JSON formatında yazın; ayrıştırma (parsing) için düzenli ifade yazma derdi ortadan kalkar. Nginx 1.11.8 ve sonrasında escape=json parametresi değerlerdeki özel karakterleri JSON’a uygun şekilde kaçırır:
log_format json_log escape=json '{'
'"time":"$time_iso8601",'
'"host":"$host",'
'"remote_addr":"$remote_addr",'
'"request_id":"$request_id",'
'"method":"$request_method",'
'"uri":"$uri",'
'"status":$status,'
'"bytes":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_time":"$upstream_response_time",'
'"upstream_status":"$upstream_status",'
'"referer":"$http_referer",'
'"user_agent":"$http_user_agent"'
'}';
access_log /var/log/nginx/access.json json_log;
Buradaki seçimler bilinçlidir. $status, $body_bytes_sent ve $request_time her zaman sayısal olduğu için tırnaksız yazılır; sorgu araçları bunları sayı olarak karşılaştırabilir. $upstream_response_time ise upstream’e hiç gidilmediğinde -, birden fazla upstream denendiğinde virgülle ayrılmış liste olabildiği için tırnak içinde tutulur. $request_uri yerine $uri kullanmak sorgu dizesini (query string) dışarıda bırakır; nedeni aşağıdaki hassas veri bölümünde. $request_id isteğe özgü bir kimlik üretir; bunu proxy_set_header X-Request-ID $request_id; ile uygulamaya iletip uygulama loglarına da yazdırırsanız, tek bir isteği tüm katmanlar boyunca izleyebilirsiniz.
Apache’de aynı amaçla LogFormat içine %D (isteğin mikrosaniye cinsinden süresi) alanını eklemek, en azından yanıt süresini kayda geçirir.
logrotate yapılandırması
Döndürülmeyen bir erişim logu, yoğun bir sitede diski birkaç hafta içinde doldurabilir. Disk dolduğunda yalnız loglama durmaz; veritabanı ve oturum dosyaları da yazılamaz hale gelir. Site tamamen düşer. Paketlerle gelen logrotate tanımları varsayılan dizinleri kapsar; özel dizinlere yazılan loglar için ayrı tanım gerekir:
# /etc/logrotate.d/nginx-json
/var/log/nginx/*.json {
daily
rotate 30
missingok
notifempty
compress
delaycompress
dateext
create 0640 www-data adm
sharedscripts
postrotate
[ -f /run/nginx.pid ] && kill -USR1 "$(cat /run/nginx.pid)"
endscript
}
USR1 sinyali Nginx’e log dosyalarını yeniden açmasını söyler; süreç yeniden başlatılmaz. Sinyal gönderilmezse Nginx adı değiştirilmiş eski dosyaya yazmaya devam eder, yeni dosya boş kalır. delaycompress bir önceki dosyanın sıkıştırılmasını bir tur geciktirir; sinyal işlenene kadar yazmaya devam eden süreç sorun yaşamaz. PHP-FPM için de aynı amaçla USR1 sinyali kullanılır. Kullanıcı ve grup adları dağıtıma göre değişir (Debian/Ubuntu’da www-data, RHEL tabanlı sistemlerde nginx); kendi sisteminize göre düzenleyin.
Yapılandırmayı canlıya almadan önce deneme modunda doğrulayın:
logrotate -d /etc/logrotate.d/nginx-json # yalnızca ne yapacağını gösterir
logrotate -f /etc/logrotate.d/nginx-json # zorla bir rotasyon çalıştırır
rotate 30 sunucuda tutulacak dosya sayısını belirler; saklama politikanızın tamamı bu olmamalı. Uzun saklama merkezi sistemde yapılır, yerel diskte yalnız hızlı erişim için kısa bir pencere kalır.
Merkezi toplama seçenekleri
Tek sunucuda grep ve awk iş görür. Birden fazla sunucu, yük dengeleyici arkasında birden fazla düğüm ya da ele geçirilen bir sunucuda saldırganın logları silme ihtimali işin içine girdiğinde merkezi toplama gerekir. Sunucuda duran log, saldırgana da açıktır. Üç yaygın yaklaşım:
| Seçenek | Güçlü yanı | Sınırlaması |
|---|---|---|
| rsyslog ile merkezi syslog sunucusu | Neredeyse her Linux’ta hazır; basit ve hafif | Sorgulama ve görselleştirme yok; dosya olarak saklar |
| Grafana Loki | Yalnızca etiketleri indekslediği için depolama maliyeti düşük; Grafana ile entegre | Tam metin aramada indeksli sistemlerden yavaş |
| Elasticsearch/OpenSearch (ELK) | Güçlü tam metin arama ve analiz | Bellek ve disk ihtiyacı yüksek; işletim yükü fazla |
Nginx logları doğrudan syslog’a da gönderebilir: access_log syslog:server=10.0.20.5:514,tag=nginx json_log;. Ancak UDP üzerinden syslog iletimi teslim garantisi vermez; ağ sorununda loglar sessizce kaybolur. Bu yüzden önerdiğimiz düzen, logları yerel dosyaya yazmaya devam edip bir toplayıcı ajanla (rsyslog imfile modülü, Grafana Alloy, Filebeat veya Fluent Bit) dosyadan okuyarak göndermektir. Merkezi sistem erişilemez olduğunda ajan kaldığı yerden devam eder.
Küçük ve orta ölçekli bir web altyapısı için Loki + Grafana, maliyet ve işletim yükü açısından genellikle dengeli bir başlangıçtır; erişim loglarındaki yanıt kodu dağılımı ve yanıt süresi, uptime ve performans panolarıyla yan yana gösterilebilir. Bu panoları uyarı kurallarıyla birlikte web izleme ve uptime monitoring kapsamında tasarlayabilirsiniz.
Sorun gidermede log sorguları
Aşağıdaki sorgular JSON formatındaki Nginx loguyla çalışır ve olay anında ilk sorulan soruları yanıtlar: hangi kodlar dönüyor, hangi URL patlıyor, ne yavaş, kim yüklüyor? jq çoğu dağıtımın paket deposunda bulunur.
# Son logda durum kodu dağılımı
jq -r '.status' /var/log/nginx/access.json | sort | uniq -c | sort -rn
# 5xx dönen en sık URI'ler
jq -r 'select(.status >= 500) | .uri' /var/log/nginx/access.json \
| sort | uniq -c | sort -rn | head -20
# 2 saniyeden uzun süren istekler
jq -c 'select(.request_time > 2) | {time, uri, request_time, upstream_time}' \
/var/log/nginx/access.json | tail -50
# En çok istek yapan istemci adresleri
jq -r '.remote_addr' /var/log/nginx/access.json | sort | uniq -c | sort -rn | head
Loki kullanıyorsanız aynı soruları LogQL ile zaman aralığına göre sorabilirsiniz:
{job="nginx"} | json | status >= 500
sum by (status) (count_over_time({job="nginx"} | json [5m]))
Yorumlarken şuna dikkat edin: 502 ve 504 gibi kodlarda Nginx erişim logu yalnız sonucu gösterir. Neden (bağlantı reddedildi, zaman aşımı, upstream erken kapattı) hata logundadır. 5xx artışında konsolda ilk bakılacak yer, erişim logundaki zaman damgasıyla aynı penceredeki hata logu satırlarıdır; ardından PHP-FPM logunda “max_children reached” uyarısı aranır. Arama motoru tarayıcılarının davranışını loglardan analiz etmek ayrı bir konu; sunucu loglarıyla Googlebot tarama analizi yazısında anlattık.
Saklama süresi ve hassas veri kontrolü
Erişim logları IP adresi, kullanıcı ajanı ve ziyaret edilen URL’leri içerdiği için kişisel veri niteliği taşıyabilir. Bu durumda saklama süresi teknik bir tercih olmaktan çıkar; kurumun veri işleme envanterinde tanımlanması gereken bir karar olur. Türkiye’de 6698 sayılı KVKK’nın genel ilkeleri ile, hizmetin niteliğine göre 5651 sayılı Kanun kapsamındaki trafik bilgisi saklama yükümlülükleri birlikte değerlendirilmelidir. Süreyi hukuk birimiyle belirleyin; yerel rotasyonu ve merkezi saklamayı buna göre yapılandırın.
Saklama süresi kadar önemli olan, loglara istemeden yazılan verilerdir. Kontrol listesi:
- Sorgu dizesinde parola sıfırlama anahtarı, oturum kimliği, API anahtarı veya e-posta adresi taşınıyor mu? Taşınıyorsa erişim logunda
$request_uriyerine$urikullanın ya da uygulamayı bu bilgileri sorgu dizesinde taşımayacak şekilde düzeltin. AuthorizationveyaCookiebaşlıkları log formatına eklenmiş mi? Hata ayıklama için eklenip unutulmuş başlıkları kaldırın.- Uygulama, hata durumunda istek gövdesini (form verileri dahil) loglara döküyor mu?
- PHP
display_errorsüretimde kapalı,log_errorsaçık mı? Hata mesajları veritabanı bağlantı bilgilerini içerebilir. - Log dosyalarının izinleri yalnız yetkili kullanıcı ve gruba okuma hakkı veriyor mu? Web kökü altında log dosyası var mı?
- Merkezi log sistemine erişim rol bazlı mı ve erişimler kayıt altında mı?
- Saklama süresi dolan loglar hem sunucudan hem merkezi sistemden gerçekten siliniyor mu?
Nginx log değişkenlerinin tam listesi için ngx_http_log_module dokümantasyonu, LogQL sözdizimi için Grafana Loki dokümantasyonu başvuru kaynağıdır. Loglama, reverse proxy ve güvenlik ayarlarının birlikte gözden geçirilmesi gerekiyorsa Nginx web sunucusu ve reverse proxy hizmet sayfasına bakabilirsiniz.
Sık sorulan sorular
Erişim loglarını JSON formatına geçirmek performansı etkiler mi?
Genellikle belirgin bir etkisi yoktur; Nginx’in log satırını formatlama maliyeti istek işleme maliyetinin yanında küçüktür. Asıl fark diskte: alan adları her satırda tekrarlandığı için JSON loglar daha büyüktür, ama sıkıştırma bu farkı büyük ölçüde kapatır.
Rotasyondan sonra Nginx neden boş log dosyasına yazmıyor?
Nginx açık dosya tanıtıcısı üzerinden yazar; logrotate dosyanın adını değiştirdiğinde süreç eski dosyaya yazmaya devam eder. postrotate bölümünde Nginx ana sürecine USR1 sinyali gönderilmezse yeni dosya açılmaz. Sinyal adımını ve pid dosyasının yolunu kontrol edin.
Loki mi ELK mı tercih edilmeli?
Ana ihtiyaç zaman aralığı ve etiketlerle filtreleyip sayım ve oran çıkarmaksa Loki bu işi daha az kaynakla görür. Serbest metin içinde sık arama, karmaşık analiz ve büyük hacimli güvenlik analizi gerekiyorsa Elasticsearch veya OpenSearch tabanlı bir yapı daha uygundur; ama daha fazla bellek, disk ve işletim emeği ister.
Web sunucusu loglarını ne kadar süre saklamalıyım?
Tek bir doğru süre yok. Süreyi KVKK’daki ölçülülük ilkesi, hizmetin niteliğine göre 5651 sayılı Kanun yükümlülükleri, güvenlik olaylarını geriye dönük inceleme ihtiyacı ve sözleşme şartlarına bakarak hukuk birimiyle belirleyin. Teknik tarafta yaygın yaklaşım, yerel sunucuda kısa, merkezi sistemde politikaya uygun süre tutmaktır.
- Teknoloji
- Nginx, Apache, PHP-FPM, logrotate, rsyslog, Grafana Loki, Elasticsearch/OpenSearch, jq
- Konu
- Web loglarının formatı, rotasyonu ve merkezi toplanması
- Seviye
- Orta
- Ön koşullar
- Linux komut satırı bilgisi
- Nginx veya Apache yapılandırma deneyimi
Web Sunucuları ve DevOps