İçeriğe geç
Haydar Demir

ÇalışmalarMobil gözlemlenebilirlik

Uçtan Uca Mobil Gözlemlenebilirlik Altyapısı

Dağınık hata, ekran ve ağ sinyallerini tek bir kullanıcı zaman çizelgesinde birleştirerek üretim sorunlarının bağlamıyla analiz edilmesini sağlayan Flutter gözlemlenebilirlik altyapısı.

Neden böyle bir altyapıya ihtiyaç duyduk?

Uygulamada veri yok değildi; aksine farklı araçlarda çok sayıda sinyal vardı. Sorun, bu sinyallerin aynı hikâyeyi anlatmamasıydı.

Hataların ve uygulama loglarının bir bölümü Sentry’de görülüyordu. Kullanıcının geçtiği sayfalar ve bazı ürün olayları Firebase Analytics’te bulunuyordu. Ağ istekleri ise bu iki görünümün doğal bir parçası değildi. Geliştirici cihazında Chucker ile istekleri incelemek mümkündü, fakat üretimde sorun yaşayan kullanıcının telefonuna sonradan bağlanıp aynı kaydı açmak mümkün değildi. Oturum analizi araçları kullanıcının ekranda ne yaptığını gösterebilse de başarısız isteğin teknik nedenini veya uygulama durumunu açıklamıyordu.

Bu nedenle elimizde çoğu zaman şu parçalar bulunuyordu:

  • Hatanın türü ve stack trace’i,
  • Kullanıcının ziyaret ettiği ekranlar,
  • Ayrı bir yerde ürün analitiği,
  • Varsa kullanıcının sözlü olarak aktardığı son işlem.

Ancak bir hatayı çözmek için gereken asıl sıra görünmüyordu: Kullanıcı hangi akışı başlattı, hangi seçimleri yaptı, hangi ekranlardan geçti, son olarak hangi ağ isteği gönderildi, istek ne kadar sürdü, hangi durum koduyla döndü ve uygulama bundan sonra hangi hatayı üretti?

Farklı panelleri kullanıcı kimliği ve yaklaşık saat üzerinden eşleştirmeye çalışmak kesin bir analiz değil, tahmindi. Özellikle randevu oluşturma gibi çok adımlı ve ödeme içerebilen akışlarda “işlem başarısız oldu” bilgisi tek başına yeterli değildi. Başarısızlığın tesis seçiminde, uygun saat sorgusunda, yetkilendirmede, ödeme dönüşünde veya son kayıt adımında oluşması tamamen farklı aksiyonlar gerektiriyordu.

Hedef

Yeni katmanın amacı başka bir log ekranı oluşturmak değildi. Mevcut hata yakalama ve analitik araçlarının arasındaki bağlam boşluğunu kapatmak istedik.

Bir hata kaydı açıldığında aşağıdaki sorular tek bir paket üzerinden cevaplanabilmeliydi:

  1. Bu hata hangi uygulama oturumunda oluştu?
  2. Kullanıcı hangi iş akışının içindeydi?
  3. Hangi ekrandan hangi ekrana geçti?
  4. Hata öncesindeki kullanıcı ve iş olayları nelerdi?
  5. Son ağ isteğinin adresi, süresi ve sonucu neydi?
  6. Uygulama sürümü, platform, dil ve bağlantı durumu neydi?
  7. Aynı hata birden fazla katmandan tekrar raporlandı mı?

Temel yaklaşım: Her şeyi yerelde kaydet, yalnızca anlamlı anı yükle

Uygulamadaki her olayı anında sunucuya göndermek hem gereksiz trafik hem de büyük miktarda gürültü oluşturacaktı. Bunun yerine gezinme, kullanıcı aksiyonu, iş olayı, ağ isteği, durum değişikliği ve hata gibi sinyaller bellekte sınırlı kapasiteli bir zaman çizelgesine yazılıyor.

Bu yapı bir ring buffer gibi çalışıyor: kapasite dolduğunda en eski kayıt çıkarılıyor ve uygulamanın en güncel bağlamı korunuyor. Normal ilerleyen bir oturum için bu kayıtlar cihazdan dışarı çıkmıyor. Bir hata yakalandığında ise son olaylardan bir anlık görüntü oluşturulup hata bilgisiyle birlikte tek paket halinde yükleniyor.

Ekranlar + kullanıcı aksiyonları + iş olayları + ağ istekleri

                    Yerel zaman çizelgesi
                              ↓ hata oluşursa
             Bağlamlı hata anlık görüntüsü ve yükleme

Bu karar, tüm oturumları ayrıntılı biçimde saklamadan sorunlu oturumun hata öncesindeki hikâyesini korumamızı sağladı.

Üç seviyeli ilişkilendirme modeli

Tek bir kimlik bütün analiz ihtiyaçlarını karşılamıyordu. Bu nedenle bağlam üç ayrı seviyede modelleniyor.

Oturum kimliği, uygulamanın o kullanım süresini temsil ediyor. Destek ekibi aynı kullanıcının farklı zamanlardaki denemelerini birbirinden ayırabiliyor.

Yolculuk kimliği, randevu oluşturma gibi belirli bir iş akışının başlangıcıyla bitişi arasındaki olayları grupluyor. Kullanıcı uygulamada uzun süre kalmış olsa bile analiz yalnızca ilgili iş akışına daraltılabiliyor.

Trace kimliği, tek bir ağ isteğini onun sonucu ve ardından oluşan hatayla ilişkilendiriyor. Her istek için ayrı bir kimlik üretildiği için arka arkaya gönderilen çağrılar birbirine karışmıyor.

Bu kimliklere her hata için üretilen benzersiz hata kimliği de eklendiğinde, destek ve geliştirme ekibi aynı olaydan konuşurken ortak bir referans kullanabiliyor.

Ağ görünürlüğü

Ağ katmanındaki görünürlük, her servise elle log eklemek yerine merkezi Dio interceptor üzerinden sağlandı. Böylece modül sayısı arttıkça izleme kapsamının eksilmesi engellendi.

Her istek başladığında zaman ve trace bilgisi oluşturuluyor. Yanıt veya hata geldiğinde HTTP metodu, göreli adres, durum kodu ve geçen süre zaman çizelgesine ekleniyor. Başarısız isteklerde hata tipiyle birlikte güvenli hale getirilmiş istek ve yanıt özeti de kaydedilebiliyor. Dosya gibi uygun olmayan yanıt tiplerinde gövde kaydı alınmıyor.

Gözlemlenebilirlik paketini sunucuya gönderen tanılama isteği interceptor tarafından özellikle hariç tutuluyor. Aksi halde tanılama isteğinin kendisi başarısız olduğunda yeni bir log üretip sonsuz bir raporlama döngüsü başlatabilirdi.

Ekran takibinden kullanıcı yolculuğuna

Firebase Analytics ekran görüntülemelerini zaten topluyordu; fakat analitik verisi hata ayıklamak için tasarlanmamıştı. Yeni gözlemlenebilirlik katmanı aynı navigasyon kaynağını dinleyerek mevcut ve önceki ekranı yerel zaman çizelgesine ekledi. Böylece hata kaydının içinde ayrıca ekran bağlamı oluştu.

Yalnızca ekran adları da yeterli değildi. Bir randevu akışında kullanıcının hangi tesisi seçtiği, hangi saate geçtiği, özet ekranını açıp açmadığı veya onay düğmesine basıp basmadığı ekran isminden anlaşılamaz. Bu nedenle kritik akışlar için anlamlı iş olayları tanımlandı:

  • Yolculuğun başlaması,
  • Tesis, uzmanlık, sağlık profesyoneli, tarih ve saat seçimi,
  • Özet ekranının açılması,
  • Avantaj veya indirim seçimi,
  • Onay ve yetkilendirme adımları,
  • Ödeme, sonlandırma ve kayıt sonucunun başarılı ya da başarısız olması.

Bu olaylar genel analitik metriği olmaktan ziyade belirli bir işlem örneğinin kronolojisini oluşturuyor. Yolculuk ekran açıldığında başlıyor ve akıştan çıkıldığında kapatılıyor; böylece başka özelliklerde gerçekleşen olaylar aynı analize karışmıyor.

Hata anlık görüntüsü

Bir hata yakalandığında yalnızca exception metni gönderilmiyor. Oluşturulan anlık görüntü şu bağlamı bir araya getiriyor:

  • Hata, oturum, yolculuk ve trace kimlikleri,
  • Exception türü, mesajı ve stack trace,
  • Son ekran ile önceki ekran,
  • Son ağ isteği ve yanıt durumu,
  • Hata öncesindeki güncel zaman çizelgesi,
  • Kullanıcı referansı,
  • Uygulama sürümü, işletim sistemi, cihaz bilgisi ve dil,
  • O an bilinen bağlantı türleri.

Flutter framework hataları ve yakalanmamış platform hataları uygulama başlangıcında ortak hata facade’ine bağlanıyor. Ağ ve model dönüşüm hataları da aynı kapıdan geçtiği için özellik ekiplerinin her hata için ayrı raporlama mantığı yazması gerekmiyor.

Aynı exception nesnesinin kısa süre içinde farklı katmanlardan yeniden raporlanması ayrıca kontrol ediliyor. Yakın zaman penceresindeki tekrarlar elenerek tek olayın birden fazla tanılama kaydı üretmesi önleniyor.

Sağlık uygulamasında veri güvenliği

Gözlemlenebilirlik için daha fazla bağlam toplamak, kişisel veya sağlık verisini kontrolsüz biçimde loglamak anlamına gelmemeli. Bu nedenle olay verileri ve başarısız ağ gövdeleri merkezi bir temizleme katmanından geçiriliyor.

Token, kimlik numarası, telefon, e-posta, ad-soyad ve ödeme kartı alanları gibi hassas anahtarlar maskeleniyor. İç içe nesneler ve JSON biçimindeki metinler de aynı kuralla temizleniyor. Hata gövdelerine uzunluk sınırı uygulanarak büyük yanıtların log sistemini doldurması engelleniyor.

Bu merkezi yaklaşım önem taşıyor: Her geliştiricinin her olayda hassas alanları hatırlamasına güvenmek yerine güvenli varsayılan davranış altyapı tarafından uygulanıyor.

Örnek bir hata analizi

Eski durumda destek kaydında yalnızca “randevu tamamlanamadı” ve bir exception görülebilirdi. Yeni anlık görüntü aşağıdaki gibi bir kronoloji sağlayabiliyor:

Randevu yolculuğu başladı
→ tesis ve uzmanlık seçildi
→ saat seçildi
→ özet ekranı açıldı
→ onay düğmesine basıldı
→ yetkilendirme isteği başarılı oldu
→ ödeme isteği hata verdi
→ yolculuk başarısız olarak işaretlendi

Bu görünüm, sorunun kullanıcı navigasyonundan mı, istemci durumundan mı, ağ koşulundan mı yoksa belirli bir servis adımından mı kaynaklandığını ilk incelemede daraltıyor. Sentry’deki hata, Firebase Analytics’teki ekran ve yerel ağ kaydını ayrı ayrı tahminle birleştirmek yerine hata anı kendi teknik bağlamını taşıyor.

Mimari kararlar

Tek sözleşme, farklı kaynaklar. Özellik modülleri Sentry, Firebase veya backend tanılama servisini doğrudan bilmiyor. Gezinme, iş olayı, ağ ve hata kayıtları ortak ObservabilityManager sözleşmesi üzerinden ilerliyor.

Otomatik kapsama, seçici anlam. Ağ istekleri ve ekran geçişleri merkezi olarak otomatik yakalanıyor. İş olaylarıysa yalnızca ürün açısından kritik adımlara bilinçli biçimde ekleniyor. Her butonu loglamak yerine analizi değiştiren karar noktaları izleniyor.

Hata anında yükleme. Normal oturumun bütün ayrıntılarını sürekli göndermek yerine güncel bağlam yerelde tutuluyor ve yalnızca anlamlı hata oluştuğunda paketleniyor.

Kendini izlemeyen tanılama kanalı. Log yükleme isteği ağ gözlemcisinin dışında bırakılarak raporlama altyapısının kendi kendini tetiklemesi engelleniyor.

Bağımlılık sırası. Gözlemlenebilirlik yöneticisi ağ katmanından önce hazırlanıyor; ağ interceptor’ü ve navigasyon gözlemcisi daha sonra aynı örneğe bağlanıyor. Böylece uygulama açılışının erken aşamalarından itibaren tutarlı tek oturum korunuyor.

Sonuç

Dağınık izleme araçları kaldırılmadı; her biri güçlü olduğu alanda kullanılmaya devam etti. Asıl kazanım, hata analizinin araçlar arasında manuel korelasyon yapmaya bağlı olmaktan çıkması oldu. Üretimdeki bir sorun artık yalnızca stack trace olarak değil, kullanıcının son adımları, aktif iş akışı, ekran geçişleri, ağ çağrıları ve çalışma ortamıyla birlikte incelenebiliyor.

Bu yaklaşım geliştirme ekibinin “hata nerede oluştu?” sorusunun yanında “kullanıcı bu hataya nasıl geldi?” sorusunu da cevaplamasını sağladı. Destek kaydının yeniden üretilemediği durumlarda bile ilk analiz için gereken teknik bağlam korunmuş oldu.

Öğrendiklerim

  • Log miktarı gözlemlenebilirlik değildir. Birbiriyle ilişkilendirilemeyen çok sayıda kayıt, az ama bağlamlı bir zaman çizelgesinden daha az değerlidir.
  • Analitik ile hata ayıklama farklı amaçlara hizmet eder. Aynı ekran olayından yararlanabilirler, ancak hata analizi istek sonucu, süre, durum ve exception bağlamına da ihtiyaç duyar.
  • En değerli log, hatadan hemen önceki olaydır. Sınırlı ring buffer bu bağlamı düşük maliyetle korur.
  • Korelasyon kimlikleri ortak dil oluşturur. Oturum, yolculuk, istek ve hata seviyelerini ayrı modellemek analiz kapsamını doğru noktaya daraltır.
  • Gizlilik sonradan uygulanacak bir filtre değildir. Sağlık uygulamasında maskeleme ve veri sınırları gözlemlenebilirlik tasarımının başlangıç koşuludur.
  • Kritik akışlar teknik değil, iş adımlarıyla izlenmelidir. “POST başarısız” bilgisi ancak “ödeme başlatıldı” veya “randevu kaydı tamamlanamadı” bağlamıyla aksiyona dönüşür.

Aramak için yazın