PYTHON STRUCTURED LOGGING

Python structured logging için tek bir yapısal log kaydı kartı INFO etiketi ve yılan logo eşliğinde giriş görseli

Sabah 03:42, ödeme servisi hata fırlatıyor. Geliştirici SSH ile sunucuya bağlanıyor, tail -f app.log diyor ve ekranda yüzlerce satır görüyor: "burada", "x=", "geldim mi?", bir traceback, sonra yine "test123". Hangi kullanıcı? Hangi istek? Hangi servis? Bilinmiyor. Çünkü kod, print() ile geliştirilmiş, dosyaya yönlendirilmiş ve production'a öyle çıkmış. Bu yazı, o gecenin bir daha yaşanmaması için Python'da structured logging'i nasıl kuracağınızı anlatıyor.

print() Neden Production'da Yetmez?

print() hızlı bir geliştirme aracıdır — anlık kontrol için iyidir, kalıcı kayıt için değil. Sebepleri sıralarsak.

  • Seviye yok: DEBUG, INFO, WARNING, ERROR ayrımı yapılmaz. Her şey eşit gürültüdür.
  • Bağlam yok: Zaman damgası, modül adı, process ID, request ID otomatik gelmez.
  • Yapısı yok: Düz metindir; grep ile arayabilirsiniz ama analiz edemezsiniz.
  • Yönlendirme zayıf: stdout'a yazar; dosyaya, syslog'a veya merkezi log toplayıcıya kanal kuramazsınız.
  • Performans: Senkron stdout I/O, yüksek trafikte yanıt süresini kötü etkiler.

Standart logging Modülü ile Temel

Python'un kendi logging modülü çoğu ihtiyacı karşılar ve handler, formatter, filter gibi tüm bileşenlere resmi dokümantasyondan ulaşabilirsiniz. Minimum bir kurulum şöyle.

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s %(message)s",
    handlers=[
        logging.FileHandler("app.log"),
        logging.StreamHandler(),
    ],
)

log = logging.getLogger(__name__)
log.info("Sipariş oluşturuldu: id=%s tutar=%s", order_id, total)

Bu seviye için yeterli — ama "id=42 tutar=199.90" düz metni, log toplayıcı bir sisteme (Elastic, Loki, CloudWatch) gittiğinde aranabilir alanlar üretmez. Burada yapısal log'a geçmek gerekir.

Beş log seviyesinin DEBUG INFO WARN ERROR CRITICAL renk şiddetiyle yukarı doğru yükselen yatay merdiveni

structlog ile Yapısal Log

structlog kütüphanesi, log satırlarını anahtar-değer çiftleri olarak modeller. Çıktıyı geliştirme ortamında insan-okur renkli, production'da JSON formatında alırsınız.

import structlog

structlog.configure(
    processors=[
        structlog.contextvars.merge_contextvars,
        structlog.processors.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.JSONRenderer(),
    ],
)

log = structlog.get_logger()
log.info("order_created", order_id=42, amount=199.90, user_id=771)

Çıktı:

{"event": "order_created", "order_id": 42, "amount": 199.9,
 "user_id": 771, "level": "info", "timestamp": "2026-05-24T09:14:02Z"}

Artık user_id=771 filtresiyle bir kullanıcının tüm hareketlerini tek sorguyla çekebilirsiniz. Python ekosistemini daha derinden tanımak için kapsamlı Python eğitimi içeriğinden yararlanabilirsiniz.

Request Bağlamı: contextvars

Bir HTTP isteğinin başında request_id üretip log bağlamına bağlarsanız, o istek boyunca yazılan her log satırı bu kimliği taşır. FastAPI / Flask middleware örneği.

import uuid, structlog
from structlog.contextvars import bind_contextvars, clear_contextvars

@app.middleware("http")
async def add_request_id(request, call_next):
    clear_contextvars()
    bind_contextvars(request_id=str(uuid.uuid4()), path=request.url.path)
    response = await call_next(request)
    return response

Bu noktadan sonra servis katmanında çağırdığınız log.info("payment_failed", reason="insufficient_funds") satırı bile request_id alanını otomatik içerir. Geceleyin debug yaparken tek bir kimlikle isteğin tüm yolculuğunu izlersiniz.

Log Seviyelerini Doğru Kullanmak

  1. DEBUG: Sadece geliştirme. Değişken değerleri, ara hesaplar.
  2. INFO: Beklenen iş olayları — "kullanıcı kayıt oldu", "sipariş onaylandı".
  3. WARNING: Anormal ama kurtarılan durum — "cache miss, DB'ye düştük".
  4. ERROR: İstek/iş başarısız oldu, kullanıcı etkilendi.
  5. CRITICAL: Servis çalışmıyor — DB bağlantısı yok, disk dolu.

Production'da varsayılan seviye INFO; DEBUG açılırsa dosya saniyede yüzlerce satır şişer, hem maliyet hem okunabilirlik düşer.

Log Rotasyonu ve Dosya Yönetimi

Tek bir app.log büyüyüp diski doldurur. RotatingFileHandler veya TimedRotatingFileHandler kullanın.

from logging.handlers import TimedRotatingFileHandler

handler = TimedRotatingFileHandler(
    "app.log", when="midnight", backupCount=14, encoding="utf-8"
)

Production'da daha temiz yaklaşım: uygulamanız sadece stdout'a JSON yazar, log toplayıcı (Fluent Bit, Vector, Promtail) dosya rotasyonu ve gönderimi üstlenir. 12-Factor App felsefesinin önerdiği yol budur.

Uygulama kutusundan stdout JSON çıkışıyla toplayıcı kutusu üzerinden merkezi log deposuna akan yatay log boru hattı

Hassas Veriyi Loglara Sızdırmamak

Bir log satırı, kullanıcı şifresini ya da kart numarasını içeriyorsa, tüm sisteminizin güvenlik sınıfı log toplayıcıya devredilmiş demektir. Önlem.

  • Dict halinde gelen request body'sini doğrudan loglamayın; alan filtresi geçirin.
  • structlog içine bir processor ekleyip password, token, card_number anahtarlarını *** ile maskeleyin.
  • Exception loglarken exc_info=True kullanın ama bağlama sırlı veri eklemeyin.
  • PII içeren alanlar için hash'leme (kullanıcı izleme için) yeterli olabilir.

Test Edilebilir Logging

Önemli iş olaylarının loglandığını test etmek mümkündür. pytest ile caplog fikstürü, structlog için structlog.testing.capture_logs() kullanılır. Loglar artık sadece "debug çıktısı" değil, doğrulanabilir davranıştır. Hangi olayların loglanması gerektiğini belirlerken Python'un genel ekosistem alışkanlıklarına dair detaylı içerikleri inceleyebilirsiniz.

Üç stilize log kaydı kartının yanına yerleştirilmiş büyük yeşil onay işareti pytest caplog doğrulama metaforu

Sonuç olarak print() bir geliştirme refleksidir; production bir kayıt sistemi ister. logging + structlog + stdout JSON üçlüsü, bir gece yarısı "ne oldu?" sorusunu beş saniyede yanıtlanabilir hale getirir. Bir sonraki deploy'unuza geçmeden önce, kodunuzdaki tüm print çağrılarını arayıp seviyeli, bağlamlı, yapısal log satırlarına dönüştürmek; ödeyeceğiniz en küçük teknik borçtur.