İçeriğe geç
Muhammet Şafak
en
Soran: Can Cevaplandı:

Loglarımda WARN ile ERROR seviyelerini ne zaman kullanacağıma dair net bir kural nasıl belirlerim?


Soru

Laravel API'lerimiz ve Go servislerimiz neredeyse her şeyi ERROR seviyesinde logluyor — yakalanan exception'lar, başarısız validation'lar, retry'lı HTTP çağrıları, hatta beklenen 404'ler bile ERROR olarak düşüyor. Sonuçta Sentry ve alert kanallarımız tamamen gürültüye döndü; gerçek bir sorun çıktığında binlerce anlamsız ERROR arasında kayboluyor. WARN ile ERROR arasında, ekibin tutarlı uygulayabileceği net ve uygulanabilir bir sınırı nasıl çizerim?

Cevap

Kısa cevap: Seviyeyi “log satırının içeriği” değil, “birinin harekete geçmesi gerekiyor mu” sorusu belirlemeli.

Kısa cevap

ERROR = kırdığınız bir söz; WARN = sistemin kendi kendine toparladığı beklenmedik bir durum. Yani seviyeyi satırın kaynağı değil, sonucu belirlesin. Gürültünün bir de hacim tarafı var; logların diski doldurup krize dönüştüğü senaryoyu log storm kaydında ayrıca ele almıştım.

Neden

  1. Eksen aksiyon alınabilirliktir. ERROR, bir isteğin veya job’ın sizin hatanızla başarısız olduğu ve birinin bakması gereken durumdur. WARN ise beklenmedik ama sistemin tolere ettiği bir şeydir: retry tuttu, fallback devreye girdi, soft limit’e yaklaşıldı. “Bu satır gece 3’te fire olsa birini uyandırır mıyım?” sorusuna evet diyorsanız ERROR’dır.
  2. Beklenen hata bug değildir. 404, validation hatası, kullanıcının yanlış girdisi — bunlar sizin kodunuzun kırılması değil, INFO ya da en fazla WARN’dır. Kaba kural: 4xx client’ın sorunudur, 5xx sizindir. ERROR’ı yalnızca kendi kodunuzun verdiği sözü tutamadığında kullanın.
  3. Retry ve fallback farklı sonuçlar üretir. Tekrar denenecek tek bir başarısız deneme WARN’dır; geçici bir titreme aksiyon gerektirmez. Ama tüm retry’lar tükendiğinde veya mesaj dead-letter’a düştüğünde artık ERROR’dır — çünkü iş kalıcı olarak yarım kaldı.
  4. ERROR ile FATAL/critical de aynı şey değildir. FATAL, sürecin devam edemediği durumdur (config eksik, boot başarısız); ERROR ise bir isteğin/job’ın başarısızlığıdır, süreç ayaktadır.

Ne yapmalı

  1. Alert’i yalnızca ERROR’a bağlayın, onu da oranla. Uyarılarınız ERROR (ve fatal) üzerinden tetiklensin; tek satıra değil eşik/oran üzerinden (“5 dakikada 50 ERROR”). WARN dashboard’u besler, pager’ı değil.

  2. Aynı hatayı beş kez loglamayın. Go’da her katmanda hem error return edip hem loglarsanız aynı başarısızlık beş satır olur. Kararın verildiği sınırda (handler) bir kez loglayın; alt katmanlar sadece error’ı wrap edip döndürsün. Laravel’de aynısı için Log::error’ı her yere serpmek yerine exception handler’daki report() seviyesini kullanın.

    if err := publish(ctx, msg); err != nil {
        if attempt < maxRetries {
            log.Warn("publish failed, will retry", "attempt", attempt, "err", err)
            return retry
        }
        // retry'lar tükendi: artık gerçekten aksiyon gerekiyor
        log.Error("publish failed permanently, sent to DLQ", "err", err)
    }
  3. Her ERROR satırını aksiyon alınabilir yapın. Her ERROR satırı, birinin gecenin bir yarısı bakacağını varsayarak yeterli context taşımalı: request/trace id, ilgili kimlikler ve wrap’lenmiş hata zinciri. Aksiyon alınamayan bir ERROR zaten ERROR değildir.

Sonuç: Ben olsam ekibe tek cümlelik bir kural verirdim: “Bu log gece 3’te fire olduğunda birinin uyanması gerekiyorsa ERROR, gerekmiyorsa WARN.” Buna ek olarak hatayı yalnızca sınırında bir kez loglama disiplinini koyar, alert’leri ERROR oranına bağlardım. Bu iki değişiklik gürültünün çoğunu tek başına eritir; kalanını da birkaç hafta boyunca yanlış seviyedeki logları düzelterek temizlersiniz. Amaç sıfır ERROR değil; her ERROR’ın gerçekten bir anlam taşıması.

Paylaş:

Yorumlar

Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.

Diğer Sorular

Tüm sorular

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi