---
title: 'Hata İzleme'
source: 'https://academia.sh/tr/kurslar/frontend-kalitesi/hata-izleme'
course: 'Frontend Kalitesi'
language: tr
updated: '2026-08-17T18:09:22+00:00'
license: 'CC BY-SA 4.0'
---

# Hata İzleme

İstemci hatalarının yakalandığı noktalar, kaynak haritasıyla yığıt izinin okunur kılınması, parmak izi üreterek gruplama, bir grubun etkisinin ölçülmesi ve gürültü ile gizlilik kararları.

Ölçütler uygulamanın ne kadar hızlı olduğunu söyler; çalışıp çalışmadığını söylemez. Ölçüm
tablosu çizilirken bir istisna fırlarsa, o oturumun süre ölçütleri iyi görünmeyi sürdürür.
Kullanıcı boş bir ekrana bakar ve çoğu zaman kimseye haber vermez.

Bu ders, o sessiz başarısızlıkları görünür kılan düzeneği kurar: hatanın yakalanması,
gönderilmesi ve binlerce olayın tek tek değil, aynı kökene inen gruplar hâlinde okunması.

## Yakalama Noktaları

İstemci hataları tek bir yerden gelmez. Dört ayrı kaynak vardır ve her birinin kendi
sınırı bulunur.

Yakalanmayan istisnalar belge düzeyindeki `error` olayıyla bildirilir; olay nesnesi bir
`ErrorEvent` örneğidir ve iletiyi, kaynağı, konumu ve hata nesnesini taşır. Reddedilmiş
sözlerin işlenmemiş olanları `unhandledrejection` olayıyla gelir — Eşzamansız JavaScript
kursunda tanımlanan işlenmeyen reddetme kavramının tarayıcıdaki karşılığı budur. Kaynak
yükleme hataları kabarmaz; yalnız yakalama evresinde dinlenerek görülebilir. Dördüncüsü
uygulamanın kendi bildirdiği hatalardır: yakalanmış ama kurtarılamamış durumlar.

```js
// hata-toplayici.js — istemci hatalarinin toplanmasi
const uc = '/hata';
const ortak = { surum: '2.4.1', yol: location.pathname };

function bildir(tur, ileti, yigitIzi) {
  navigator.sendBeacon(uc, JSON.stringify({ ...ortak, tur, ileti, yigitIzi }));
}

addEventListener('error', (olay) => {
  if (olay.target !== window) {           // kaynak yukleme hatasi
    bildir('kaynak', `${olay.target.tagName} yuklenemedi`, olay.target.src ?? '');
    return;
  }
  bildir('istisna', olay.message, olay.error?.stack ?? '');
}, true);

addEventListener('unhandledrejection', (olay) => {
  const neden = olay.reason;
  bildir('reddetme', String(neden?.message ?? neden), neden?.stack ?? '');
});
```

Bir sınır baştan bilinmelidir. Farklı bir kaynaktan yüklenen bir betikten fırlayan hata,
tarayıcı tarafından ayrıntısız verilir: ileti yalnızca betik hatası olduğunu söyler, yığıt
izi boştur. Bunun nedeni kaynak yalıtımıdır — Kaynaklar Arası Paylaşım dersindeki kurallar
burada da işler. Ayrıntının açılması için betiğin kaynaklar arası olarak istenmesi ve
sunucunun buna izin veren başlığı göndermesi gerekir.

İkinci sınır, bileşen düzeyidir. Bileşen Tabanlı Arayüz Geliştirme kursundaki hata sınırı,
çizim sırasında fırlayan hatayı yakalayıp yedek bir arayüz gösterir; bu hatalar belge
düzeyindeki dinleyiciye ulaşmaz ve ayrıca bildirilmeleri gerekir.

## Yığıt İzini Okunur Kılmak

Üretim yapısındaki kod küçültülmüştür: fonksiyon adları tek harfe inmiş, satırlar
birleşmiştir. Böyle bir yığıt izi okunamaz. Çözüm Modüller, Araçlar ve Ekosistem kursunda
tanımlanan **kaynak haritasıdır**: küçültülmüş konumu özgün dosya, satır ve ada geri
eşleyen tablo.

Eşleme istemcide değil, hataları toplayan tarafta yapılır. Kaynak haritası yayımlanan
varlıklarla birlikte dağıtılmaz — özgün kaynağı okunur kılar. Yapı sırasında ayrıca
üretilip yalnız toplama tarafına yüklenir.

## Gruplama

Tek bir kusur binlerce olay üretir. Aynı satırdaki bir hata, listeyi açan her kullanıcıda
bir kez fırlar; okunabilir olması için olayların aynı kökene inenlerinin tek bir grupta
toplanması gerekir. Bunun anahtarına **parmak izi** denir.

Parmak izi, olayın kararlı parçalarından üretilir ve kararsız parçalar dışarıda bırakılır.
Yapı özeti taşıyan dosya adı, satır ve sütun numaraları, sorgu dizgileri, iletideki kimlik
ve sayı değerleri her yayımda ya da her olayda değişir; bunlar anahtara girerse aynı kusur
onlarca gruba dağılır.

```js
// parmak-izi.mjs — yigit izinden gruplama anahtari uretir
const CERCEVE = /^\s*at\s+(?:(.+?)\s+\()?([^()]+?)\)?$/;

export function cerceveler(yigitIzi) {
  return yigitIzi
    .split('\n')
    .slice(1)
    .map((satir) => satir.match(CERCEVE))
    .filter(Boolean)
    .map((e) => ({ islev: e[1] ?? '<anonim>', kaynak: e[2] }));
}

export function kaynagiNormallestir(kaynak) {
  if (kaynak === '<anonymous>' || kaynak.startsWith('node:')) return kaynak;
  return kaynak
    .replace(/^[a-z]+:\/\/[^/]+/, '')           // koken
    .replace(/[?#][^:]*$/, '')                  // sorgu ve parca
    .replace(/:\d+:\d+$/, '')                   // satir ve sutun
    .replace(/\.[0-9a-f]{6,}\.(m?js)$/, '.$1'); // yapi ozeti
}

export function iletiyiNormallestir(ileti) {
  return ileti
    .replace(/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi, '<kimlik>')
    .replace(/\b\d+\b/g, '<sayi>');
}

function ozet(metin) {
  let h = 0x811c9dc5;
  for (const kod of metin) {
    h ^= kod.codePointAt(0);
    h = Math.imul(h, 0x01000193) >>> 0;
  }
  return h.toString(16).padStart(8, '0');
}

export function parmakIzi(olay, { derinlik = 3 } = {}) {
  const [ilkSatir] = olay.yigitIzi.split('\n');
  const [tur, ...kalan] = ilkSatir.split(': ');
  const anahtar = [
    tur,
    iletiyiNormallestir(kalan.join(': ')),
    ...cerceveler(olay.yigitIzi)
      .slice(0, derinlik)
      .map((c) => `${c.islev}@${kaynagiNormallestir(c.kaynak)}`),
  ].join('|');
  return { anahtar, ozet: ozet(anahtar) };
}

export function grupla(olaylar) {
  const gruplar = new Map();
  for (const olay of olaylar) {
    const { anahtar, ozet: kimlik } = parmakIzi(olay);
    const grup = gruplar.get(kimlik) ?? { kimlik, anahtar, sayi: 0, oturumlar: new Set(), surumler: new Set() };
    grup.sayi += 1;
    grup.oturumlar.add(olay.oturum);
    grup.surumler.add(olay.surum);
    gruplar.set(kimlik, grup);
  }
  return [...gruplar.values()].sort((a, b) => b.sayi - a.sayi);
}
```

Aşağıdaki altı olay, aynı kusurun farklı yayımlardan ve farklı oturumlardan gelen
örneklerini içeriyor.

```js
// rapor.mjs — alti hata olayinin gruplanmasi
import { grupla } from './parmak-izi.mjs';

const OLAYLAR = [
  { oturum: 's-1', surum: '2.4.0', yigitIzi:
`TypeError: Cannot read properties of undefined (reading 'deger')
    at satirCiz (https://kuzey-yamac.ornek/varlik/tablo.4f2a9c.js:12:31)
    at Array.map (<anonymous>)
    at OlcumTablosu (https://kuzey-yamac.ornek/varlik/tablo.4f2a9c.js:40:22)` },
  { oturum: 's-2', surum: '2.4.1', yigitIzi:
`TypeError: Cannot read properties of undefined (reading 'deger')
    at satirCiz (https://kuzey-yamac.ornek/varlik/tablo.9b1d70.js:12:47)
    at Array.map (<anonymous>)
    at OlcumTablosu (https://kuzey-yamac.ornek/varlik/tablo.9b1d70.js:41:22)` },
  { oturum: 's-3', surum: '2.4.1', yigitIzi:
`TypeError: Cannot read properties of undefined (reading 'deger')
    at satirCiz (https://kuzey-yamac.ornek/varlik/tablo.9b1d70.js:12:47?v=3)
    at Array.map (<anonymous>)
    at OlcumTablosu (https://kuzey-yamac.ornek/varlik/tablo.9b1d70.js:41:22)` },
  { oturum: 's-2', surum: '2.4.1', yigitIzi:
`Error: olcum 84213 kaydedilemedi (400)
    at gonder (https://kuzey-yamac.ornek/varlik/form.1c8e55.js:88:11)` },
  { oturum: 's-4', surum: '2.4.1', yigitIzi:
`Error: olcum 91007 kaydedilemedi (400)
    at gonder (https://kuzey-yamac.ornek/varlik/form.1c8e55.js:88:11)` },
  { oturum: 's-5', surum: '2.4.1', yigitIzi:
`TypeError: sozlesme.gonder is not a function
    at kaydet (https://kuzey-yamac.ornek/varlik/form.1c8e55.js:120:8)` },
];

for (const g of grupla(OLAYLAR)) {
  console.log(`${g.kimlik}  olay=${g.sayi}  oturum=${g.oturumlar.size}  surum=${[...g.surumler].join(',')}`);
  console.log(`          ${g.anahtar}`);
}
```

```sh
node rapor.mjs
```

```
1c081b4b  olay=3  oturum=3  surum=2.4.0,2.4.1
          TypeError|Cannot read properties of undefined (reading 'deger')|satirCiz@/varlik/tablo.js|Array.map@<anonymous>|OlcumTablosu@/varlik/tablo.js
bb0e50c8  olay=2  oturum=2  surum=2.4.1
          Error|olcum <sayi> kaydedilemedi (<sayi>)|gonder@/varlik/form.js
8a4701e6  olay=1  oturum=1  surum=2.4.1
          TypeError|sozlesme.gonder is not a function|kaydet@/varlik/form.js
```

Altı olay üç gruba indi. Birinci grubun üç örneği farklı yapı özetleri, farklı satır ve
sütun numaraları ve birinde bir sorgu dizgisi taşıyordu; normalleştirme bunları eledi.
İkinci grubun iki örneği farklı ölçüm numaraları içeriyordu; sayılar yer tutucuya çevrildiği
için tek kusur olarak göründüler.

Gruplama iki yönde yanlış ayarlanabilir. **Aşırı gruplama**, birbirinden bağımsız kusurları
tek satırda toplar: iletiyi bütünüyle atıp yalnız hata türüne bakmak buna yol açar. **Yetersiz
gruplama** ise tek kusuru yayım başına ayrı gruplara böler ve hiçbirinin etkisi görünmez
olur. Ayarın ölçüsü kullanışlılıktır: bir grup, tek bir düzeltmeyle kapanabiliyorsa doğru
çizilmiştir.

## Bir Grubun Okunması

Grubun taşıdığı sayılar önceliklendirmeyi belirler. **Olay sayısı** kusurun ne sıklıkta
fırladığını, **etkilenen oturum sayısı** kaç kişiye dokunduğunu söyler. İkisi ayrılmalıdır:
tek bir oturumda döngü içinde binlerce kez fırlayan bir hata, olay sayısında listenin
başına çıkar ama bir kullanıcıyı ilgilendirir. Sıralama oturum sayısına göre yapılır.

Sürüm dağılımı ikinci bilgidir. Bir grup yalnız son sürümde görünüyorsa, kusur o yayımla
gelmiştir ve geri alma bir seçenektir. İlk görülme ve son görülme zamanları aynı soruyu
zaman ekseninde yanıtlar.

Gürültü ayrı bir iştir. Tarayıcı eklentilerinden ve dış betiklerden gelen hatalar
uygulamanın kodunda değildir; yığıt izinin ilk çerçevesi uygulamanın alan adına ait değilse
süzülebilir. Kullanıcı sayfadan ayrılırken iptal edilen isteklerin ürettiği hatalar da
gerçek kusur değildir.

Hacim denetlenmelidir. Bir döngü içinde fırlayan hata tek oturumdan binlerce olay
gönderebilir; oturum başına hız sınırı ve örnekleme bunu keser. Örnekleme yapılırken
gönderilmeyen olayların sayısı da iletilir, yoksa etki ölçüsü bozulur.

Gizlilik son karardır. Hata iletisi kullanıcının yazdığı metni içerebilir, adres kimlik
taşıyabilir. Toplayıcı, bilinen kimlik biçimlerini ve serbest metni gönderimden önce
maskeler. Kişisel veri, toplandıktan sonra silinmesi zor olan veridir.

## Özet

- İstemci hataları dört noktadan gelir: yakalanmayan istisnalar, işlenmeyen söz reddetmeleri,
  kaynak yükleme hataları ve uygulamanın kendi bildirdikleri.
- Farklı kaynaktan gelen betiğin hatası ayrıntısız verilir; ayrıntı için kaynaklar arası
  istek ve izin başlığı gerekir. Yığıt izi kaynak haritasıyla toplama tarafında çözülür.
- Parmak izi, hata türü ile normalleştirilmiş ileti ve ilk birkaç çerçeveden üretilir; yapı
  özeti, satır ve sütun numarası, sorgu dizgisi ve iletideki sayılar dışarıda bırakılır.
- Altı olay üç gruba indi: farklı yayımlardan ve farklı ölçüm numaralarından gelen örnekler
  tek kusur olarak göründü.
- Önceliklendirme olay sayısına değil etkilenen oturum sayısına göre yapılır; gürültü süzülür,
  hacim sınırlanır ve kişisel veri gönderimden önce maskelenir.

## Kurs Kapanışı

Frontend Kalitesi kursu dört konuyu aynı ilkeye bağladı: **ölçülmeyen kalite iddiası
yoktur.** Başarım konusu kullanıcı merkezli ölçütleri tanımladı ve bunları bir bütçeye
bağladı. Erişilebilirlik konusu ölçütleri standart düzeyinde ele aldı ve otomatik denetimin
nerede bitip elle doğrulamanın nerede başladığını gösterdi. Güvenlik konusu istemci
tarafındaki riskleri savunma katmanlarına dönüştürdü. Bu son konu ise üçünün de ortak
sorusunu yanıtladı: kurulan şey bozulduğunda bunu ne haber verir? Yanıt iki yönlüydü —
değişiklikten önce çalışan testler ve yayımdan sonra çalışan izleme. İkisi arasında bir
döngü vardır: alanda görülen bir kusur, onu bir daha geçirmeyecek bir teste dönüşür;
testin gözden kaçırdığı bir durum, alanda bir hata grubu olarak geri gelir.

Bu kursla birlikte Frontend Geliştirme müfredatı da kapanıyor. Yol belgeden başladı — HTML
ile yapının kurulması ve tarayıcının o yapıyı nasıl işlediği. Sonra biçeme geçti: basamaklama,
kutu modeli ve görsel özellikler. Düzen sistemleri ve duyarlı tasarım, yapının farklı ekran
ve girdi koşullarına uyarlanmasını ele aldı. Tarayıcı ve web platformu, sayfayı bir belge
olmaktan çıkarıp davranışı olan bir uygulamaya çevirdi. Bileşen tabanlı geliştirme bu
davranışı yeniden kullanılabilir parçalara böldü; uygulama mimarisi o parçaları yönlendirme,
durum ve veri erişimiyle bir bütün hâline getirdi. Oluşturma stratejileri, aynı uygulamanın
sunucuda mı istemcide mi, ne zaman ve hangi maliyetle üretileceğini sordu. Ve bu son kurs,
bütün bu kararların doğru kaldığının nasıl bilineceğini gösterdi: belgeden biçeme, düzenden
davranışa, bileşenden mimariye, oluşturmadan kaliteye.

Müfredat boyunca bir soru bilerek dışarıda bırakıldı. Bir düğmenin nasıl çalışacağı, hangi
rolü taşıyacağı, hangi durumlarda hangi ölçüte uyacağı anlatıldı; o düğmenin **neden o
boyutta, o renkte ve orada** durduğu anlatılmadı. Aralık ölçeğinin, tipografik ölçeğin, renk
rollerinin ve durum tasarımının gerekçeleri kendi başına bir alandır. Arayüz Tasarımı ve
Tasarım Sistemleri müfredatı bu soruyu ele alır: görsel ve etkileşimsel kararları
gerekçelendirilebilir ilkelere bağlar ve bu kararları ölçeklenen bir sisteme dönüştürür. İlk
kursu olan Arayüz Tasarımının Temelleri, bu müfredatla birlikte okunmaya uygundur — burada
kurulan bileşenlerin görünüşüne dair kararlar orada gerekçesini bulur.
