---
title: 'Yapılandırılmış Günlükleme'
source: 'https://academia.sh/tr/kurslar/gozlemlenebilirlik/yapilandirilmis-gunlukleme'
course: 'Gözlemlenebilirlik ve Güvenilirlik'
language: tr
updated: '2026-08-17T18:06:52+00:00'
license: 'CC BY-SA 4.0'
---

# Yapılandırılmış Günlükleme

Düz cümle günlüğün alan tabanlı kayda dönüştürülmesi ve isteğe süreç sınırını geçen bir bağıntı kimliği takılması: aynı sorunun kaç ayrıştırma ve süzme adımıyla yanıtlandığı, bir isteğin kaç serviste izlenebildiği ve kimliğin taşınmadan bırakıldığı çağrı yerlerinin sayılması.

Önceki ders beş yanıtsız soru bıraktı ve üçünün ortak nedeni tekti: kayıtlarda isteği tanımlayan bir
alan yok. Günlük satırı cümleydi, cümlede yalnız o sürecin bildiği şeyler vardı ve iki servisin
satırını birleştirecek hiçbir şey yoktu. Bu ders iki değişiklik yapar: kayıt cümle olmaktan çıkıp
alanlara bölünür, isteğe süreç sınırını geçen bir **bağıntı kimliği** takılır. İkisinin de bedeli
ölçülür.

**Yapılandırılmış günlükleme**, kaydın serbest metin yerine adı belli alanlardan oluşmasıdır.
**Bağıntı kimliği**, bir dış isteğe verilen ve o istekten doğan bütün iç isteklerde taşınan
değerdir. İkincisi birincisi olmadan işe yaramaz: kimlik de sonuçta bir alandır ve serbest cümlenin
içinde aranması gereken bir dize değil, adıyla süzülebilen bir değer olmalıdır.

## Alanlara Bölünen Kayıt

Günlükçü kendi yazılır ve tek işi vardır: sabit alanlarla çağrı anındaki alanları birleştirip tek
satır olarak eklemek.

```js
// gunlukcu.mjs — alan tabanli gunlukcu; her kayit tek satir, her alan adiyla durur
import { appendFileSync } from "node:fs";
export const gunlukcu = (dosya, sabit) => (alanlar) =>
  appendFileSync(dosya, JSON.stringify({ ...sabit, ...alanlar }) + "\n");
```

Servis her istekte **iki** kayıt yazar: önceki dersin düz cümlesi ve alan tabanlı karşılığı. İkisi
de aynı olguyu, aynı koşumda, aynı değerlerle anlatır; aradaki tek fark biçimdir, o yüzden ölçülen
adım farkı biçimin farkıdır.

**TL2 — bağıntı kimliği, dış isteği ilk karşılayan servis tarafından üretilir; başlıkta gelen bir
kimlik varsa üretilmez, olduğu gibi sürdürülür.** Gerekçe: kimliğin üretim yeri tek olmalıdır, yoksa
aynı istek her serviste yeni bir kimlik alır ve birleştirme yine yapılamaz. Üretim kuralı burada
nüsha numarasına bağlanmıştır, böylece ölçümdeki kimlikler koşumdan bağımsızdır.

```js
// servis2.mjs — <ad> <port> [ardil...]; ayni istek icin iki gunluk bicimi yazar
import { createServer } from "node:http";
import { writeFileSync, appendFileSync } from "node:fs";
import { gunlukcu } from "./gunlukcu.mjs";
const [ad, port, ...ardil] = process.argv.slice(2);
const BILDIRIM = "9205";
writeFileSync(`duz-${ad}.txt`, ""); writeFileSync(`alan-${ad}.txt`, "");
const alanYaz = gunlukcu(`alan-${ad}.txt`, { servis: ad });
let sayac = 0;
const bekle = (ms) => new Promise((c) => setTimeout(c, ms));
const uc = (p, u) => `http://127.0.0.1:${p}/is?uye=${u.get("uye")}&nusha=${u.get("nusha")}`;
const cagir = (p, u, baginti) => fetch(uc(p, u), { headers: { "x-baginti": baginti } });
const haberVer = (p, u) => fetch(uc(p, u));      // eski yardimci: baslik parametresi hic olmadi

createServer(async (istek, yanit) => {
  const u = new URL(istek.url, "http://y").searchParams;
  const uye = u.get("uye"), nusha = Number(u.get("nusha"));
  const baginti = istek.headers["x-baginti"] ?? `${ad}-${nusha}`;   // kimlik yoksa uretilir
  const t0 = performance.now(); sayac += 1;
  await bekle(ad === "katalog" && nusha % 5 === 0 ? 45 : 5);
  let durum = ad === "ucretlendirme" && uye === "4023" ? 402 : 200;
  for (const p of ardil) {
    const y = p === BILDIRIM ? await haberVer(p, u) : await cagir(p, u, baginti);
    if (y.status !== 200) durum = y.status;
  }
  const sure = Math.round(performance.now() - t0);
  appendFileSync(`duz-${ad}.txt`, `${ad}: uye ${uye} icin ${nusha} numarali nusha istegi ` +
    `${sure} ms surdu, sonuc ${durum}\n`);
  alanYaz({ baginti, uye, nusha, sure, durum });
  yanit.statusCode = durum; yanit.end("bitti");
}).listen(Number(port));
```

Kimliğin sınırı geçmesi tek satırda olur: `cagir` başlığı ekler. Yanındaki `haberVer` ise başlık
parametresi hiç almamış eski bir yardımcıdır ve bildirim çağrısı onunla yapılır. Bu, kurgu bir hata
değil, kimlik eklemenin tipik sonucudur: kimlik istemci yardımcısına eklenir, ama sistemde o
yardımcıyı kullanmayan bir çağrı yolu kalır. Ölçümün işi o yolu saymaktır.

## Ölçüm

Sorgu aracı iki soruyu iki biçimde sorar. Adım tanımı önceki dersle aynıdır: bir dosyayı okumak,
ayrıştırmak, süzmek ya da iki depoyu birleştirmeyi denemek birer adımdır. Düz metinde her servisin
satır kalıbı ayrıdır, bu yüzden ayrıştırma servis başına bir geçiştir; alan tabanlı kayıtta biçim
genel olduğu için ayrıştırma tek geçiştir.

```js
// sor2.mjs — ayni sorular iki gunluk biciminde; adim = bir depo gecisi
import { readFileSync } from "node:fs";
const SERVIS = ["odunc", "uyelik", "katalog", "ucretlendirme", "bildirim"];
const CAGRI = [["odunc", "uyelik"], ["odunc", "katalog"], ["odunc", "bildirim"], ["uyelik", "ucretlendirme"]];
const RE = /uye (\d+) icin (\d+) numarali nusha istegi (\d+) ms surdu, sonuc (\d+)/;
let adim = 0; const say = () => { adim += 1; };
const satir = (on, s) => { say(); return readFileSync(`${on}-${s}.txt`, "utf8").split("\n").filter(Boolean); };
const duzOku = () => {                       // her servisin satir kalibi ayri: servis basina bir ayristirma
  const o = {};
  for (const s of SERVIS) o[s] = satir("duz", s).map((l) => { const m = l.match(RE); return m && { uye: m[1], nusha: +m[2], sure: +m[3], durum: +m[4] }; });
  for (const s of SERVIS) say();
  return o;
};
const alanOku = () => {                      // alan tabanli: bicim genel, tek ayristirma gecisi
  const o = {}; for (const s of SERVIS) o[s] = satir("alan", s);
  say(); for (const s of SERVIS) o[s] = o[s].map((l) => JSON.parse(l));
  return o;
};
const yaz = (soru, bicim, yanit) => console.log(`${soru.padEnd(11)}${bicim.padEnd(13)}${String(adim).padStart(5)}  ${yanit}`);
console.log(`${"soru".padEnd(11)}${"bicim".padEnd(13)}${"adim".padStart(5)}  yanit`);

// S3 — hangi uye etkilendi (iki bicim de yanitlayabiliyor)
adim = 0; const d = duzOku(); say();
yaz("S3 kim", "duz metin", `uye ${[...new Set(d.odunc.filter((r) => r.durum !== 200).map((r) => r.uye))].join(",")}`);
adim = 0; const a = alanOku(); say();
yaz("S3 kim", "alan tabanli", `uye ${[...new Set(a.odunc.filter((r) => r.durum !== 200).map((r) => r.uye))].join(",")}`);

// S1 — bu istek nerede yavasladi; hedef: 5 numarali nushanin istegi
const HEDEF = "odunc-5";
adim = 0; duzOku(); say(); say();
yaz("S1 nerede", "duz metin", "yanitlanamadi (satirda kimlik alani yok, servisler baglanamiyor)");
adim = 0; const a2 = alanOku(); say();
const yol = SERVIS.filter((s) => a2[s].some((r) => r.baginti === HEDEF));
const enUzun = yol.filter((s) => s !== "odunc").sort((x, y) =>
  a2[y].find((r) => r.baginti === HEDEF).sure - a2[x].find((r) => r.baginti === HEDEF).sure)[0];
say(); yaz("S1 nerede", "alan tabanli", `${HEDEF}: ${yol.join(" ")} (${yol.length}/${SERVIS.length} servis), en uzun ardil ${enUzun}`);

console.log(`\n${"cagri yeri".padEnd(26)}${"kimlik".padEnd(8)}kimlikli kayit`);
let tasiyan = 0;
for (const [ust, alt] of CAGRI) {
  const kume = new Set(a[ust].map((r) => r.baginti));
  const ortak = a[alt].filter((r) => kume.has(r.baginti)).length;
  if (ortak > 0) tasiyan += 1;
  console.log(`${`${ust} -> ${alt}`.padEnd(26)}${(ortak > 0 ? "evet" : "hayir").padEnd(8)}${ortak}/${a[alt].length}`);
}
console.log(`kimlik tasiyan cagri yeri ${tasiyan}/${CAGRI.length}, tasimayan ${CAGRI.length - tasiyan}; ` +
  `bir istek ${yol.length}/${SERVIS.length} serviste izlenebiliyor`);
const bayt = (on) => Math.round(SERVIS.reduce((t, s) => t + readFileSync(`${on}-${s}.txt`, "utf8").length, 0) / 100);
console.log(`kayit basina ort. boy: duz metin ${bayt("duz")} bayt, alan tabanli ${bayt("alan")} bayt (100 kayit)`);
```

```bash
cat > kos.mjs <<'EOF'
const UYE = ["4021", "4022", "4023", "4024"];      // 4023 odenmemis ucreti olan uye
for (let i = 1; i <= 20; i += 1)
  await fetch(`http://127.0.0.1:9201/is?uye=${UYE[(i - 1) % 4]}&nusha=${i}`);
EOF
node servis2.mjs ucretlendirme 9204 &
node servis2.mjs katalog 9203 &
node servis2.mjs bildirim 9205 &
node servis2.mjs uyelik 9202 9204 &
node servis2.mjs odunc 9201 9202 9203 9205 &
sleep 1

node kos.mjs
node sor2.mjs
pkill -f "node servis2.mjs"
```

```
soru       bicim         adim  yanit
S3 kim     duz metin       11  uye 4023
S3 kim     alan tabanli     7  uye 4023
S1 nerede  duz metin       12  yanitlanamadi (satirda kimlik alani yok, servisler baglanamiyor)
S1 nerede  alan tabanli     8  odunc-5: odunc uyelik katalog ucretlendirme (4/5 servis), en uzun ardil katalog

cagri yeri                kimlik  kimlikli kayit
odunc -> uyelik           evet    20/20
odunc -> katalog          evet    20/20
odunc -> bildirim         hayir   0/20
uyelik -> ucretlendirme   evet    20/20
kimlik tasiyan cagri yeri 3/4, tasimayan 1; bir istek 4/5 serviste izlenebiliyor
kayit basina ort. boy: duz metin 71 bayt, alan tabanli 88 bayt (100 kayit)
```

## Dört Adım ve Bir Kör Nokta

Birinci karşılaştırma sıradan bir kazançtır. Aynı soru düz metinde on bir, alan tabanlı kayıtta yedi
adım sürdü. Dört adımın tamamı ayrıştırmadan geldi: düz metinde her servisin satır kalıbı ayrı
olduğu için düzenli ifade servis başına bir kez uygulanmak zorunda, alan tabanlı kayıtta biçim genel
olduğu için tek geçiş yetiyor. Bu fark servis sayısıyla büyür — beş yerine yirmi servis olsa düz
metin yirmi beş, alan tabanlı kayıt yirmi iki adım harcardı ve aradaki fark on dokuza çıkardı.
Ayrıştırmanın kırılganlığı da buradadır: satır kalıbı değişince düzenli ifade sessizce eşleşmeyi
bırakır, alan adı değişince kayıt açıkça o alanı kaybeder.

İkinci karşılaştırma dersin asıl noktasıdır. Önceki derste hiçbir sinyalin yanıtlayamadığı soru,
alan tabanlı kayıtla sekiz adımda yanıtlandı: `odunc-5` kimliği dört serviste görünüyor ve
ardıllardan en uzunu katalog. Düz metin aynı soruda hâlâ yanıtsız — sorun sürelerin eksikliği
değildi, süreleri birbirine bağlayacak alanın eksikliğiydi.

Üçüncü tablo kazancın sınırını gösteriyor. Dört çağrı yerinin üçü kimliği taşıyor, biri taşımıyor;
bildirim servisinin yirmi kaydının hiçbirinde ödünç isteğinin kimliği yok. Bunun ölçülen sonucu
şudur: bir istek beş servisten **dördünde** izlenebiliyor. Kimlik eklemenin bedeli tek satır, ama
kapsamı çağrı yolu sayısıyla ölçülür ve tek bir atlanan çağrı yeri bütün bir servisi haritanın
dışında bırakır. Bildirim burada rastgele seçilmedi: "bu bildirim neden gitmedi" bu sistemin en sık
sorulan sorusudur ve tam da o servis kör noktada kaldı.

Son satır bedeli veriyor. Alan tabanlı kayıt kayıt başına 88 bayt, düz metin 71 bayt: alan adları
her satırda yeniden yazıldığı için hacim dörtte bir arttı. Karşılığında sorgu adımı azaldı ve
yanıtlanamaz bir soru yanıtlanır oldu. Ölçülen takas budur — yazma tarafında bayt, okuma tarafında
adım.

## Özet

- Alan tabanlı kayıt aynı soruyu 11 yerine 7 adımda yanıtladı; farkın tamamı ayrıştırmadan geliyor
  ve servis sayısıyla büyüyor.
- Bağıntı kimliği, önceki dersin hiçbir sinyalle yanıtlanamayan sorusunu 8 adımda yanıtlanır hâle
  getirdi: `odunc-5` kimliği dört serviste izlendi, en uzun ardıl katalog çıktı.
- Kimliği taşıyan çağrı yeri 4'te 3; taşımayan tek çağrı yeri bildirim servisini bütünüyle haritanın
  dışında bıraktı, bir istek 5 servisten 4'ünde izlenebiliyor.
- Atlanan çağrı yeri kimlik eklemenin doğal artığıdır: kimlik istemci yardımcısına eklenir, o
  yardımcıyı kullanmayan eski çağrı yolu sessizce kimliksiz kalır.
- Bedel yazma tarafındadır: kayıt başına 71 bayttan 88 bayta çıkış, alan adlarının her satırda
  yinelenmesinden geliyor.

## Sonraki Adım

Günlük artık alanlara bölündü ve bir isteğin yolu dört serviste izlenebiliyor. Ama her sorgu hâlâ
bütün kayıtları okuyup süzmekle başlıyor: yirmi istek için yüz kayıt okundu, iki yüz istek için bin
kayıt okunacak. Önceki dersin ölçüt sinyali bu maliyetin dışındaydı, çünkü sorulacak soru kayıt
yazılırken seçilmişti. Sonraki ders o seçimin kendisine bakar: aynı olgu sayaç, ölçer ve histogram
olarak üç ayrı tiple ölçülür, her tipin yanıtlayabildiği ve kapattığı soru sayılır, histogramın kova
sayısına göre bellek maliyeti ile yüzdelik hatası karşılaştırılır.
