Herhangi bir sistemin veya uygulamanın sorunsuz çalıştığını anlamak için loglara bakmak kritik. Bu konuda iki ana yaklaşım var: Unstructured (yapısal olmayan) ve Structured (yapısal) logging. Benim için loglar, bir uygulamanın beyni gibi; ne düşündüğünü, ne yaşadığını ve nerede takıldığını bana anlatan bir günlük. Geçtiğimiz 20 yılda, binlerce sunucunun, yüzlerce uygulamanın logunu inceledim ve bu süreçte iki yaklaşımın da kendine göre avantajları ve dezavantajları olduğunu gördüm.
Özellikle bir üretim firmasının ERP’sini geliştirirken, anlık stok hareketlerinden faturalandırma süreçlerine kadar her adımın loglanması gerekiyordu. Başlangıçta geleneksel unstructured loglar kullandık, ancak sistem büyüdükçe bu logların yönetimi kabusa dönüştü. Nerede ne oldu, hangi siparişte hata var, hangi kullanıcı hangi işlemi ne zaman yaptı gibi soruların cevabını bulmak saatler sürüyordu. Bu yüzden, gözlemlenebilirliği artırmak ve sorunları daha hızlı çözmek adına structured logging’e geçiş kaçınılmaz oldu.
Unstructured Logging: Kolay Başlangıç, Zor Bakım
Unstructured logging, en basit tabirle, serbest metin formatında yazılan loglardır. Yani, uygulamanızın “şu oldu”, “bu hata”, “işlem tamamlandı” gibi mesajları doğrudan bir dosyaya yazdırmasıdır. Apache veya Nginx’in varsayılan access.log kayıtları buna iyi bir örnektir. Okuması ilk bakışta kolay gibi görünse de, özellikle problem anlarında veya belirli kalıpları ararken işler zorlaşır.
Benim deneyimimde, küçük projelerde veya hızlı prototiplemelerde unstructured loglar yeterli olabilir. Örneğin, kendi yan ürünlerimden birinin ilk versiyonlarında, sadece print() komutlarıyla loglama yapıyordum. Ancak sistem büyüyüp karmaşıklaştığında, “geçen hafta saat 03:00’te hangi kullanıcının hangi API’yi çağırdığını” bulmak için grep komutlarıyla saatlerce uğraşmak zorunda kaldım. Bu durum, özellikle yüzlerce GB log dosyası olan bir üretim ortamında tam bir eziyete dönüşebiliyor.
Bir keresinde, büyük bir TR e-ticaret sitesinde ödeme ağ geçidi entegrasyonunda bir sorun yaşadık. Loglarda “Payment failed” mesajı vardı, ancak neden başarısız olduğunu anlamak için ilgili transaction ID’sini, kullanıcı ID’sini ve hata kodunu aynı satırda bulmak gerekiyordu. Bu bilgileri içeren yüzlerce satırı tek tek grep -i "payment failed" | grep "TXN_12345" gibi komutlarla aramak, MTTR süremizi uzatıyordu. İşte bu noktada unstructured logların yetersiz kaldığını acı bir şekilde tecrübe ettim.
Structured Logging: Veri Tabanı Gibi Loglamak
Structured logging ise logları belirli bir formatta, genellikle anahtar-değer (key-value) çiftleri veya JSON gibi standart veri yapıları kullanarak kaydetmektir. Bu format, logların hem insanlar tarafından okunmasını kolaylaştırır hem de makine tarafından çok daha etkin bir şekilde işlenmesini sağlar. Her log kaydı, bir veri tabanındaki bir satır gibi, belirli alanlara (field) sahiptir.
Ben genellikle JSON formatını tercih ediyorum çünkü hem okunabilirliği yüksek hem de çoğu log toplama aracı (Loki, Elasticsearch, Splunk) tarafından doğal olarak destekleniyor. Bir ERP uygulamasında, her bir operasyonu (örneğin, “sipariş oluşturma”, “ürün sevkiyatı”) ayrı ayrı loglarken, bu operasyonla ilgili tüm detayları (kullanıcı ID’si, sipariş ID’si, işlem süresi, etkilenen ürünler) structured log olarak kaydettim. Bu sayede, “son 24 saat içinde hangi siparişler 10 saniyeden uzun sürdü?” gibi sorulara saniyeler içinde cevap bulabildik.
{
"timestamp": "2026-05-22T10:30:00Z",
"level": "INFO",
"service": "order-management",
"event": "order_created",
"user_id": "USR-12345",
"order_id": "ORD-67890",
"item_count": 3,
"total_amount": 150.75,
"latency_ms": 120
}
Yukarıdaki gibi bir JSON log kaydı, sadece bir mesajdan çok daha fazlasıdır; sorgulanabilir bir veri noktasıdır. Bu bana, “PostgreSQL’de N+1 sorununu tespit ettiğimde” veya “Redis OOM eviction policy seçimlerinde hatalar” gibi durumlarda çok yardımcı oldu. Özellikle finansal işlem loglarının structured olması, regülasyon uyumluluğu ve denetim süreçleri için hayati önem taşır; hangi kullanıcının hangi saatte hangi işlemi yaptığını saniyeler içinde raporlayabilmek bu tür ortamlarda doğrudan bir gereksinimdir.
Neden Structured Logging Tercih Edilmeli? Pragmatik Yaklaşımım
Structured logging’i tercih etmemin temel nedeni, operasyonel verimlilik. Problemlerle karşılaştığımda, “nerede ve ne oldu?” sorusuna hızlıca cevap verebilmek, sistemin uptime’ını doğrudan etkiler. Benim için MTTR, yani ortalama çözüm süresi, her zaman en önemli metriklerden biri olmuştur. Structured loglar bu süreyi önemli ölçüde kısaltıyor.
Üretim bandındaki bir sensörden gelen anomaliyi tespit etmek gerektiğinde, loglar unstructured olsaydı yüzlerce sensörden gelen milyonlarca log satırında grep yapmak imkansıza yakındı. Ancak structured loglar sayesinde, sensor_id: "X" AND value > threshold gibi basit bir sorguyla anormalliği anında tespit edip otomatik bir uyarı tetikleyebildik. Bu sayede üretim hattının durma süresini belirgin biçimde azalttık.
Ayrıca, structured loglar sayesinde “gerçek-zamanlı dashboard tasarımı” yapmak çok daha kolay hale geliyor. Log toplama araçları, structured logları otomatik olarak parse edip grafiklere dökebilir. Bu sayede, anlık hataları, performans düşüşlerini veya belirli bir API’ye gelen istek sayısını canlı olarak izleyebiliyorum. Daha önce observability metrikleri ile sistem sağlığını izleme konusunda bahsettiğim gibi, görselleştirme, operasyonel zeka için olmazsa olmazdır.
Structured Logging Uygulama Stratejileri
Structured logging’i sistemlerime entegre etmek için farklı stratejiler izledim. Bu stratejiler genellikle uygulamanın büyüklüğüne, karmaşıklığına ve mevcut altyapıya göre değişir. Hangi yöntemi seçeceğiniz, projenizin ihtiyaçlarına ve ekibinizin yeteneklerine bağlıdır.
-
Uygulama Seviyesinde Loglama: En doğrudan yöntemdir. Uygulama kodunuz içinde, log mesajlarını doğrudan JSON gibi structured bir formatta oluşturursunuz. Python’da
loggingmodülü veya Java’da Logback/Log4j gibi kütüphaneler bu konuda gelişmiş destek sunar. Ben FastAPI ve Vue.js tabanlı bir ERP backend’inde genelliklepython-json-loggergibi kütüphaneler kullandım.import logging import json_log_formatter formatter = json_log_formatter.JsonFormatter() handler = logging.StreamHandler() handler.setFormatter(formatter) logger = logging.getLogger(__name__) logger.addHandler(handler) logger.setLevel(logging.INFO) # Örnek log kaydı logger.info("Order processed successfully", extra={ "order_id": "ORD-123", "customer_id": "CUST-456", "amount": 99.99, "payment_method": "CreditCard" }) -
Sidecar veya Log Agent Kullanımı: Bu yöntemde, uygulamanız hala unstructured loglar üretebilir, ancak ayrı bir “agent” (örneğin Fluentd, Filebeat veya Logstash) bu logları okuyup structured formata dönüştürür ve merkezi bir log sistemine gönderir. Özellikle legacy uygulamalarla çalışırken veya uygulamanın kendisini değiştirmek istemediğinizde bu yaklaşım kurtarıcıdır. Kendi VPS’imde, Nginx access loglarını Filebeat ile parse edip Loki’ye gönderiyorum. Bu, container orkestrasyonunda log yönetimi konusunda da önemli bir yaklaşımdır.
-
Merkezi Log Yönetim Sistemleri: Toplanan structured logları depolamak, indekslemek, sorgulamak ve görselleştirmek için Loki, Elasticsearch (ELK Stack), Splunk gibi çözümler kullanılır. Bu sistemler, büyük ölçekli ve dağıtık mimarilerde gözlemlenebilirliğin temelini oluşturur. Ben genellikle Loki’yi tercih ediyorum çünkü hem resource dostu hem de Promtail ile entegrasyonu çok kolay.
Her stratejinin kendine göre bir maliyeti ve karmaşıklığı var. Uygulama seviyesinde loglama en esnek olanıdır ama kodda değişiklik gerektirir. Sidecar yaklaşımı daha az kod değişikliğiyle eski sistemleri entegre ederken, bir agent çalıştırma maliyeti getirir. Merkezi sistemler ise kurulum ve bakım açısından yatırım gerektirir.
Gerçek Dünya Senaryolarında Karşılaştığım Zorluklar
Structured logging’e geçmek her zaman güllük gülistanlık olmadı. Bu süreçte bazı beklenmedik zorluklarla karşılaştım. Bunlardan en önemlisi, log schema’sının evrimiydi. Bir uygulamayı geliştirirken, log’a eklemek istediğim alanlar zamanla değişebiliyor. Örneğin, başlangıçta order_id yeterliyken, daha sonra tracking_number veya carrier_id gibi alanlara da ihtiyaç duyulabiliyor.
Bu durum, log toplama sistemlerindeki indekslerin veya parse kurallarının sürekli güncellenmesini gerektirdi. Özellikle Elasticsearch gibi schema-on-read yerine schema-on-write çalışan sistemlerde, schema değişiklikleri indeks yenileme veya veri kaybı gibi sorunlara yol açabiliyordu. Bu yüzden, log schema’sını baştan iyi tasarlamak ve esneklik payı bırakmak gerektiğini öğrendim. Benim tavsiyem, her zaman minimum gerekli alanı loglamak ve daha sonra ihtiyaç duyulursa eklemeler yapmaktır, ancak bunu yaparken geriye dönük uyumluluğu gözetmek şart.
Bir diğer zorluk da log hacmiydi. Structured loglar, unstructured loglara göre genellikle daha fazla yer kaplar. Yüksek hacimli bir üretim ortamında günlük log üretimi ciddi boyutlara ulaştığında, depolama ve işleme maliyetleri ciddi bir problem haline geldi. Bu durumda, log seviyelerini optimize etmek (DEBUG loglarını sadece geliştirme ortamında tutmak), gereksiz alanları loglamamak ve log retention politikalarını sıkı tutmak gibi önlemler almak zorunda kaldım.
Journald ve Systemd’nin Rolü: Hibrit Yaklaşım
Linux sistemlerinde systemd ve journald ikilisi, structured logging konusunda bize doğal bir avantaj sunar. journald, tüm sistem loglarını ikili (binary) bir formatta, ancak structured bir şekilde depolar. Yani, her log kaydı otomatik olarak _SYSTEMD_UNIT, _PID, MESSAGE, _HOSTNAME gibi alanlarla etiketlenir. Bu, uygulama loglarınızı journald’ye göndererek ek bir agent’a ihtiyaç duymadan structured loglamanın faydalarından yararlanabileceğiniz anlamına gelir.
Ben, çoğu zaman uygulamalarımın loglarını standart çıktıya (stdout/stderr) yazdırıp, systemd servis tanımında StandardOutput=journal veya StandardOutput=syslog kullanarak journald’ye yönlendiriyorum. Bu sayede, journalctl komutuyla uygulamamın loglarına kolayca filtre uygulayabiliyorum.
# Sadece bir servise ait logları filtrele
journalctl -u my-web-app.service
# Belirli bir PID'ye ait logları ve sadece hataları göster
journalctl _PID=12345 -p err
# JSON formatında çıktı al
journalctl -u my-web-app.service -o json
journalctl -o json çıktısı, uygulamanızın stdout’a yazdığı metin loglarını da içeren, zengin structured veriler sunar. Bu hibrit yaklaşım, hem basit hem de güçlüdür. Özellikle container ortamlarında docker logs çıktılarının journald’ye yönlendirilmesi, log yönetimini büyük ölçüde kolaylaştırıyor. Benim için bu, bare-metal sunucular ile container’ları bir arada kullandığım hibrit dağıtım mimarilerinde vazgeçilmez bir yaklaşım oldu.
Sonuç
Structured logging, modern sistemlerin gözlemlenebilirlik gereksinimlerini karşılamak için vazgeçilmez bir araç. Başlangıçta biraz daha fazla çaba gerektirse de, uzun vadede sorun giderme süresini kısaltır, operasyonel maliyetleri düşürür ve sistemlerinizin sağlığı hakkında daha derinlemesine bilgi edinmenizi sağlar. Unstructured loglarla boğuştuğum zamanları düşününce, structured logging’e geçiş kararımın ne kadar doğru olduğunu bir kez daha anlıyorum.
Eğer hala sistemlerinizde unstructured loglar kullanıyorsanız, structured logging’e geçişi ciddi şekilde düşünmenizi tavsiye ederim. Küçük adımlarla başlayabilir, kritik uygulamalarınızdan birinde denemeler yapabilirsiniz. Unutmayın, iyi loglanmış bir sistem, karanlıkta yolunu bulmaya çalışan bir mühendis için fener gibidir. Bir sonraki yazıda, log metriklerini kullanarak anomali tespiti üzerine konuşacağız.