---
title: 'Gözlemlenebilirlik ve İşletim'
source: 'https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik'
language: tr
updated: '2026-08-17T04:40:36+00:00'
license: 'CC BY-SA 4.0'
lessons: 18
outcomes:
    - 'Ölçüt, günlük ve iz toplama hattını uçtan uca kurar'
    - 'Uyarıları belirti temelli ve eyleme dönük tasarlar'
    - 'Olay müdahalesini süreç ve belgeyle yönetir'
---

# Gözlemlenebilirlik ve İşletim

Hangi sorunun yanıtlanacağına karar verilmesi ve verinin o soruya göre toplanması: çekme ve itme temelli ölçüt toplama, etiket kardinalitesi ve saklama, sorgu ve toplulaştırmayla gösterge üretme, aracı, tampon ve dizinleme katmanlarıyla günlük toplama, günlüğün aranabilir alanlara ayrıştırılması, ayrıntı düzeyi ile maliyet dengesi, dağıtık izleme altyapısı, ortak telemetri sözleşmesi, soruya yanıt veren gösterge tabloları, eşik, oran ve anomali temelli uyarı kuralları, uyarı yorgunluğu, sentetik izleme, sürdürülebilir nöbet düzeni, olay sınıflandırma ve tırmandırma, çalışma yordamları, suçsuz olay sonrası inceleme, hata bütçesiyle değişim hızının düzenlenmesi ve kapasite ile maliyetin izlenmesi.

## Ölçüt ve Günlük Hattı

Verinin toplandığı yol: çekme ve itme temelli toplamanın kapsam ve gecikme farkı, zaman serisinde etiket kardinalitesinin çarpımsal büyümesi ve saklama, ölçütlerden gösterge üretmek için sorgu ve toplulaştırma, aracı, tampon ve dizinleme katmanlarıyla günlük toplama, günlüğün aranabilir alanlara ayrıştırılması ve ayrıntı düzeyi ile maliyet arasındaki denge.

### Ölçüt Toplama Modelleri

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/olcut-toplama-modelleri

Çekme ve itme temelli toplama aynı pencerede koşturulur ve işletimde gerçekten sorulan on iki sorudan oluşan bir kümeye uygulanır: hangi model kaç soruyu yanıtlıyor, kısa ömürlü iş çekmede neden kaçıyor, itmede kaynak kimliği neden karışıyor, keşif gecikmesi ve soru başına bayt ne kadar.

Bir önceki kursun kapanışı altyapının kayda bağlandığı, her değişikliğin bir gözden geçirmeden ve
bir kapıdan geçtiği noktada bitti. Ama kapıdan geçtikten sonra sistemin koşarken ne yaptığını
kimse görmüyordu. Bu kursun ilk sorusu oradan devralınır ve bir adım daha ileri gider: **neyin
ölçüleceğine kim karar veriyor?**

Bu kursun ölçü birimi veri değil, **sorudur**. Bir toplama kurulumunun iyi olup olmadığı kaç
gigabayt biriktirdiğiyle değil, işletimde gerçekten sorulan sorulardan kaçını yanıtladığıyla
ölçülür. Bu ders o soru kümesini kurar ve iki toplama modelini — **çekme temelli** ve **itme
temelli** — aynı pencerede koşturup kümeye uygular.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir: su sayaçlarından okuma toplayan, okumaları
doğrulayan, faturaya çeviren ve saha ekiplerine iş emri açan bir yazılım. Ağ da, ölçülen sayılar
da **kurgudur**; gerçek bir toplayıcı koşturulmaz, sayılan şey `node` ile kurulmuş bir
**modeldir**.

**OG1.** On iki soru kurgudur ve önceden yazılıdır; her sorunun gerektirdiği kaynak sınıfı, ölçüt
ve etiketler de öyle.
**OG2.** Envanter kurgudur: üç ortamda 29 uzun ömürlü örnek, bir saatlik pencerede 11 yeniden
başlatma ve 42 gecelik doğrulama koşumu.
**OG3.** Çekme temelli toplayıcı 15 saniyede bir kazır, hedef envanterini 30 saniyede bir
yeniler; itme temelli gönderici uzun ömürlü süreçte 10 saniyede bir boşaltır, toplu iş her adım
bitiminde gönderir.
**OG4.** Bir kayıt 16 bayt, bir seri künyesi 120 bayttır.
**OG5.** Bir kaynak sınıfı ancak ömürlerinin en az yüzde 90'ından ikişer ölçüm alınabiliyorsa
kapsam içinde sayılır; tek ölçüm bir değişimi göstermez.
**OG6.** Yeniden başlatma zamanları ve koşum süreleri kendi üretecimizle üretilir, tohum
`20260901`.

#### İşletimde Sorulan On İki Soru

Soru kümesi ölçüm aracının değil, işletimin ürünüdür: nöbet sırasında, sabah raporunda ve olay
incelemesinde gerçekten sorulmuş cümlelerdir. Her soru üç şeye bağlanır — hangi **kaynak
sınıfından** veri gerekiyor, hangi **ölçüt**, hangi **etiketler**.

```js
// ag.mjs — bolgesel olcum agi modeli ve isletim soru kumesi. Ikisi de kurgudur.
export const ORNEK = {                               // ortam -> servis -> uzun omurlu ornek
  uretim: { "okuma-toplayici": 8, dogrulayici: 6, faturalama: 4, "is-emri": 3 },
  sinama: { "okuma-toplayici": 2, dogrulayici: 2, faturalama: 1, "is-emri": 1 },
  gelistirme: { "okuma-toplayici": 1, dogrulayici: 1, faturalama: 0, "is-emri": 0 } };
export const UZUN_SAYISI = Object.values(ORNEK)
  .reduce((t, o) => t + Object.values(o).reduce((a, b) => a + b, 0), 0);

export const OLCUT_UZUN = { "istek-sayisi": { sonuc: 5 }, "istek-suresi": { dilim: 12 },
  "kuyruk-boyu": { kuyruk: 3 }, "islenen-okuma": { bolge: 11, sonuc: 5 },
  "surec-baslangic-zamani": {}, "cop-toplama-duraklamasi": { kova: 8 }, "dosya-tanitici-sayisi": {} };
export const OLCUT_KISA = { "is-adimi-suresi": { adim: 6 }, "is-islenen-kayit": {} };
export const seri = (o) => Object.values(o)
  .reduce((t, e) => t + Object.values(e).reduce((c, k) => c * k, 1), 0);

// isletimde gercekten sorulan on iki soru: [kimlik, metin, kaynak sinifi, olcut, gereken alanlar]
export const SORU = [
  ["S1", "hangi servis yavasladi", "uzun", "istek-suresi", ["servis"]],
  ["S2", "gecikmenin ust dilimi ne", "uzun", "istek-suresi", ["servis", "dilim"]],
  ["S3", "hangi ortamda hata artti", "uzun", "istek-sayisi", ["ortam", "sonuc"]],
  ["S4", "hangi surumden sonra bozuldu", "uzun", "istek-sayisi", ["surum"]],
  ["S5", "gecelik is kac okuma isledi", "kisa", "is-islenen-kayit", ["is"]],
  ["S6", "gecelik is dun neden gec bitti", "kisa", "is-adimi-suresi", ["is", "adim"]],
  ["S7", "hangi bolgenin okumasi dogrulanmadi", "uzun", "islenen-okuma", ["bolge", "sonuc"]],
  ["S8", "hangi ornek yeniden basladi", "uzun", "istek-sayisi", ["ornek"]],
  ["S9", "hangi dogrulama kosumu yavasti", "kisa", "is-adimi-suresi", ["is", "ornek"]],
  ["S10", "hangi hata kodu artti", "uzun", "istek-sayisi", ["sonuc"]],
  ["S11", "is emri kuyrugu neden birikti", "uzun", "kuyruk-boyu", ["servis", "kuyruk"]],
  ["S12", "bir fatura hangi okumadan uretildi", "istek", "-", ["islem-kimligi"]],
];
export const yanit = (kapsam, alan) =>
  SORU.filter(([, , k, , a]) => kapsam.includes(k) && a.every((e) => alan.includes(e)));

export const uretec = (t) => () => (t = (t * 1103515245 + 12345) % 2147483648) / 2147483648;
export const KAYIT_BAYT = 16, SERI_BAYT = 120;
export const mb = (b) => (b / 1024 ** 2).toFixed(1);
```

Üç kaynak sınıfı vardır. **Uzun ömürlü** olan, saatlerce koşan servis örneğidir. **Kısa ömürlü**
olan, gecelik toplu işin her koşumudur; ortalama yarım dakika yaşar. **İstek** sınıfı tek bir
işlemin kendisidir ve hiçbir ölçüt onu taşıyamaz, çünkü işlem kimliğinin kardinalitesi sınırsızdır.
S12 bu yüzden baştan işaretlidir: bir ölçüt hattı onu ne kadar veri toplarsa toplasın yanıtlayamaz.

#### Çekme ve İtme Aynı Pencerede

İki model aynı bir saatlik pencerede koşturulur. Fark üç yerde toplanır: **neyin görüldüğü**
(kapsam), **ne zaman görüldüğü** (keşif gecikmesi) ve **kimin gördüğü olarak kaydedildiği**
(kaynak kimliği).

```js
// topla.mjs — cekme ve itme temelli toplama ayni pencerede kosturulur ve soru kumesine uygulanir.
import { ORNEK, UZUN_SAYISI, OLCUT_UZUN, OLCUT_KISA, seri, SORU, yanit, uretec, KAYIT_BAYT, SERI_BAYT, mb }
  from "./ag.mjs";

const PENCERE = 3600, KAZIMA = 15, ENVANTER = 30, ITME = 10;   // saniye
const rast = uretec(20260901);                                 // tohum gorunur
const omur = [];                                               // 29 ornek pencere basindan, 11 yeniden baslatma
for (let i = 0; i < UZUN_SAYISI; i++) omur.push({ sinif: "uzun", bas: 0, bit: PENCERE });
for (let i = 0; i < 11; i++) {
  const h = omur[Math.floor(rast() * UZUN_SAYISI)], t = 300 + Math.floor(rast() * 3000);
  h.bit = t; omur.push({ sinif: "uzun", bas: t + 20, bit: PENCERE });
}
const kosum = Array.from({ length: 42 }, (_, i) => {           // gecelik dogrulama kosumlari
  const bas = 60 + i * 80 + Math.floor(rast() * 30);
  return { sinif: "kisa", bas, bit: bas + 6 + Math.floor(rast() * 33) };
});
const hepsi = [...omur, ...kosum];

const cekme = (o) => {                                         // envanter yenilendikten sonraki kazimalar
  const t = [], gorunur = Math.ceil(o.bas / ENVANTER) * ENVANTER;
  for (let s = Math.ceil(gorunur / KAZIMA) * KAZIMA; s < o.bit; s += KAZIMA) t.push(s);
  return t;
};
const itme = (o) => {                                          // surec kendi gonderir; kesif turu yok
  const t = [];
  if (o.sinif === "kisa") {                                    // toplu is her adim bitiminde gonderir
    for (let a = 1; a <= 6; a++) t.push(o.bas + Math.round(((o.bit - o.bas) * a) / 6));
    return t;
  }
  for (let s = o.bas + ITME; s < o.bit; s += ITME) t.push(s);
  return t;
};
const kapsanan = (f, s) => hepsi.filter((o) => o.sinif === s && f(o).length >= 2).length;
const toplam = (s) => hepsi.filter((o) => o.sinif === s).length;
const kesif = (f) => {                                         // yalniz pencere icinde baslayan omurler
  const g = omur.filter((o) => o.bas > 0).map((o) => f(o)[0] - o.bas);   // yeniden baslayan ornekler
  return [(g.reduce((a, b) => a + b, 0) / g.length).toFixed(1), Math.max(...g)];
};

const ALAN = ["servis", "ortam", "surum", "sonuc", "dilim", "kuyruk", "bolge", "is", "adim"];
const MODEL = [["cekme", cekme, UZUN_SAYISI, kapsanan(cekme, "kisa")],  // kimlik envanterden gelir
  ["itme", itme, omur.length, 3]];                             // kimlik surecin kendi bildirimi, is sablonu sabit
console.log(`bolgesel olcum agi (kurgu): ${UZUN_SAYISI} uzun omurlu ornek, ${Object.keys(ORNEK).length} ortam,` +
  ` ${omur.length - UZUN_SAYISI} yeniden baslatma, ${kosum.length} gecelik dogrulama kosumu`);
console.log(`ornek basina ${seri(OLCUT_UZUN)} seri, kosum basina ${seri(OLCUT_KISA)} seri; pencere ${PENCERE} sn\n`);
console.log("model  uzun omur  kisa omur   kesif ort/azami   kimlik uzun  kimlik kisa");
const ozet = [];
for (const [ad, f, kimlikU, kimlikK] of MODEL) {
  const [ort, azami] = kesif(f), ku = kapsanan(f, "uzun"), kk = kapsanan(f, "kisa");
  const olcum = hepsi.reduce((t, o) => t + f(o).length * seri(o.sinif === "uzun" ? OLCUT_UZUN : OLCUT_KISA), 0);
  const seriSayisi = kimlikU * seri(OLCUT_UZUN) + kimlikK * seri(OLCUT_KISA);
  ozet.push([ad, ku, kk, olcum, seriSayisi, kimlikU === UZUN_SAYISI]);   // kimlik yeniden baslatmada korunuyor mu
  console.log(`${ad.padEnd(7)}${String(`${ku}/${toplam("uzun")}`).padStart(9)}` +
    `${String(`${kk}/${toplam("kisa")}`).padStart(11)}${String(`${ort} / ${azami} sn`).padStart(18)}` +
    `${String(`${kimlikU}/${omur.length}`).padStart(14)}${String(`${kimlikK}/${kosum.length}`).padStart(13)}`);
}

console.log("\nsoru kumesine karsi (12 soru)");
console.log("model  yanitlanan  bayt/saat  soru basina  yanitsiz kalan");
for (const [ad, ku, kk, olcum, seriSayisi, kararli] of ozet) {
  const kapsam = [ku / toplam("uzun") >= 0.9 && "uzun", kk / toplam("kisa") >= 0.9 && "kisa"].filter(Boolean);
  const alan = kararli ? [...ALAN, "ornek"] : ALAN;            // kimlik kararsizsa ornek etiketi yok
  const y = yanit(kapsam, alan), bayt = olcum * KAYIT_BAYT + seriSayisi * SERI_BAYT;
  console.log(`${ad.padEnd(7)}${String(`${y.length}/${SORU.length}`).padStart(9)}` +
    `${String(`${mb(bayt)} MB`).padStart(11)}${String(`${mb(bayt / y.length)} MB`).padStart(13)}  ` +
    SORU.filter((s) => !y.includes(s)).map(([k]) => k).join(" "));
}

const bos = Object.keys(OLCUT_UZUN).filter((a) => !SORU.some(([, , , o]) => o === a));
const bosSeri = bos.reduce((t, a) => t + seri({ [a]: OLCUT_UZUN[a] }), 0);
console.log(`\nhicbir soruyu yanitlamayan olcutler: ${bos.join(", ")}`);
console.log(`  ornek basina ${bosSeri}/${seri(OLCUT_UZUN)} seri (%${(100 * bosSeri / seri(OLCUT_UZUN)).toFixed(1)}),` +
  ` cekmede saatte ${mb(UZUN_SAYISI * bosSeri * (PENCERE / KAZIMA) * KAYIT_BAYT)} MB`);
const kacan = kosum.length - kapsanan(cekme, "kisa"), RAPOR = 7 * 3600, BASLANGIC = 2 * 3600;
const bekleme = kosum.reduce((t, o) => t + (RAPOR - BASLANGIC - o.bit), 0) / kosum.length / 3600;
console.log(`cekmede seri uretmeyen ${kacan} kosum: basarisizlik ancak sabah raporunda,` +
  ` ortalama ${bekleme.toFixed(1)} saat sonra`);
```

```
bolgesel olcum agi (kurgu): 29 uzun omurlu ornek, 3 ortam, 11 yeniden baslatma, 42 gecelik dogrulama kosumu
ornek basina 85 seri, kosum basina 7 seri; pencere 3600 sn

model  uzun omur  kisa omur   kesif ort/azami   kimlik uzun  kimlik kisa
cekme      40/40      13/42      14.6 / 27 sn         29/40        13/42
itme       40/40      42/42      10.0 / 10 sn         40/40         3/42

soru kumesine karsi (12 soru)
model  yanitlanan  bayt/saat  soru basina  yanitsiz kalan
cekme       8/12     9.7 MB       1.2 MB  S5 S6 S9 S12
itme        9/12    14.5 MB       1.6 MB  S8 S9 S12

hicbir soruyu yanitlamayan olcutler: surec-baslangic-zamani, cop-toplama-duraklamasi, dosya-tanitici-sayisi
  ornek basina 10/85 seri (%11.8), cekmede saatte 1.1 MB
cekmede seri uretmeyen 29 kosum: basarisizlik ancak sabah raporunda, ortalama 4.5 saat sonra
```

Uzun ömürlü tarafta iki model eşittir: kırk ömrün kırkı da her iki modelde kapsanır. Ayrım kısa
ömürlü tarafta açılır. Çekme temelli toplayıcı 42 doğrulama koşumunun yalnız **on üçünden** iki ya
da daha fazla ölçüm alabilir. Nedeni iki gecikmenin üst üste binmesidir: envanter otuz saniyede
bir yenilenir, kazıma on beş saniyede bir yapılır, koşumların ortalama ömrü ise otuz saniyenin
altındadır. Koşum, kendisini görecek olan turdan önce biter. Yirmi dokuz koşum hiçbir seri
üretmeden geçer ve **geçtikleri de görünmez** — eksik seri bir hata değil, yalnız bir yokluktur.

İtme tarafında bu sorun yoktur, çünkü kimse koşumu keşfetmek zorunda değildir: koşum kendi
verisini kendi gönderir ve her adım bitiminde bir kez daha gönderir. Kırk iki koşumun kırk ikisi
kapsanır.

Kimlik sütunları ayrımı tersine çevirir. Çekmede kimlik **envanterden** gelir; bir örnek yeniden
başladığında envanterdeki girdi aynı kaldığı için seri de aynı kalır — kırk ömür yirmi dokuz
kimlik altında toplanır ve yeniden başlatma serideki boşlukla görünür. İtmede kimlik **sürecin
kendi bildirimidir**; her yeni süreç kendine yeni bir kimlik üretir, kırk ömür kırk ayrı kimlik
yaratır ve yeniden başlayan bir örnek ile hiç görülmemiş yeni bir örnek birbirinden ayırt
edilemez. Kısa ömürlü tarafta aynı mekanizma ters yönde bozar: toplu iş şablonu iş adını sabit
yazdığı için kırk iki koşum **üç kimlik** altında birleşir ve tek tek koşumlar birbirine karışır.

#### İki Modelin Yanıtsız Bıraktığı Sorular

Çekme sekiz soruyu yanıtlar, itme dokuz soruyu. Yanıtsız kalanlar aynı değildir ve bu, ders için
tablonun en önemli satırıdır.

Çekmede S5, S6 ve S9 düşer: gecelik işin kaç okuma işlediği, dün neden geç bittiği ve hangi
koşumun yavaş olduğu. Üçü de kısa ömürlü kaynak sınıfına bağlıdır ve o sınıf kapsam dışıdır. Bunun
bedeli son satırdadır: seri üretmeyen yirmi dokuz koşumdan biri başarısız olduğunda bunu gösteren
tek sinyal sabahki mutabakat raporudur; iş gece iki ile üç arasında koşarken rapor yediye kadar
beklenir — **ortalama dört buçuk saat**. Faturalama zincirinin başındaki bir doğrulama koşumu
sessizce düştüğünde o dört buçuk saat, düzeltilmesi gereken kayıt sayısına doğrudan çarpar.

İtmede S8 ve S9 düşer: hangi örneğin yeniden başladığı ve hangi doğrulama koşumunun yavaş olduğu.
İkisi de tek bir etiketin güvenilirliğine bağlıdır — `ornek`. Etiket teknik olarak vardır ve her
kayıtta yazılıdır; güvenilir olmayan şey, aynı örneğin iki farklı zamanda aynı değeri taşıyacağı
güvencesidir. Bu, toplamanın **hiç veri kaybetmeden** bir soruyu kapatabildiğini gösterir: veri
eksik değil, ölçülemez durumdadır.

S12 her iki modelde de yanıtsızdır ve bu ders boyunca öyle kalır. Bir faturanın hangi okumadan
üretildiğini sormak, tek bir işlemin dört servis arasındaki yolunu istemek demektir; ölçüt hattı
bu yolu taşıyamaz, çünkü taşımak için işlem kimliğini etiket yapmak gerekir ve o etiketin
kardinalitesi işlem sayısı kadardır.

#### Hiçbir Soruyu Yanıtlamayan Ölçüt

Son blok, toplanan verinin hangi bölümünün karşılığı olmadığını sayar. Yedi ölçütün üçü — süreç
başlangıç zamanı, çöp toplama duraklaması ve dosya tanıtıcı sayısı — on iki sorunun hiçbirinde
geçmez. Örnek başına seksen beş serinin **onu** budur, yüzde on iki. Çekme modelinde saatte 1,1
megabayt, otuz günlük saklamada sekiz yüz megabayttan fazla eder ve karşılığında hiçbir soru
kapanmaz.

Bu üç ölçüt kötü değildir; birer sorusu olmadığı için maliyettir. Çöp toplama duraklaması
yarın bir soru kümesine girerse aynı bayt anlamlı olur. Ölçüyü kuran şey ölçütün kendisi değil,
onu isteyen sorunun varlığıdır.

Soru başına maliyet iki modeli aynı ölçekte karşılaştırmayı sağlar: çekme 1,2, itme 1,6 megabayt.
İtme daha fazla soru yanıtlar ama soru başına yüzde otuz daha pahalıdır, çünkü on saniyelik
gönderim aralığı on beş saniyelik kazımadan sık, kimlik çoğalması da seri sayısını kırk kimliğe
yayıyor. "Hangisi daha iyi" sorusunun yanıtı tek bir sayıda değil, bu iki sütunun birlikte
okunmasındadır.

#### Özet

- Soru kümesi on iki sorudan oluşur; her soru bir kaynak sınıfına, bir ölçüte ve bir etiket
  kümesine bağlıdır. Ölçü birimi toplanan bayt değil, yanıtlanan sorudur.
- Çekme temelli toplama 42 kısa ömürlü koşumun 13'ünü kapsar; envanter yenileme (30 sn) ile
  kazıma (15 sn) gecikmeleri üst üste bindiği için koşum kendisini görecek turdan önce biter.
- İtme temelli toplama kısa ömürlünün 42/42'sini kapsar ama kimliği süreç bildirdiği için 40 ömür
  40 ayrı kimlik üretir; kısa ömürlü tarafta 42 koşum 3 kimlik altında birleşir.
- Çekme 8/12, itme 9/12 soru yanıtlar; yanıtsız kalanlar kesişmez — çekmede S5, S6, S9, itmede
  S8, S9. S12 (bir faturanın hangi okumadan üretildiği) iki modelde de yanıtsızdır.
- Toplanan ölçütlerin 10/85 serisi (%11,8) hiçbir soruyu yanıtlamaz; çekmede saatte 1,1 MB.
  Soru başına maliyet çekmede 1,2, itmede 1,6 MB.
- Kapsanmayan koşumun bedeli sayıya bağlanır: seri üretmeyen 29 koşumdan birinin başarısızlığı
  ortalama 4,5 saat sonra, sabah raporunda görünür.

#### Sonraki Adım

Bu derste toplanan veri bir kutu gibi ele alındı: ölçüm sayısı, seri sayısı, bayt. Oysa serinin
kendisi bir yapıdır ve o yapının içinde bir karar durur — hangi etiketler var. Yanıtlanan sekiz
ya da dokuz sorunun her biri belirli bir etiketin varlığına bağlıydı; `ornek` etiketi düştüğünde
iki soru kapandı. Bir sonraki ders bu bağı ters yönden ölçer: bir etiket **eklemek** hangi soruyu
açıyor, kaç seriye ve kaç bayta mal oluyor ve hangi etiket eklendiğinde hiçbir soru açılmıyor.

### Zaman Serisi Verisi

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/zaman-serisi-verisi

Etiket eklemenin hangi soruyu açtığı soru kümesine karşı sayılır: her etiket için seri, bayt ve açılan soru birlikte ölçülür, marjinal soru başına bayt çıkarılır, hiçbir soru açmayan etiket adıyla yazılır ve saklama penceresinin hangi soruyu ne kadara açtığı ayrıca hesaplanır.

Bir önceki ders toplamayı bir kutu gibi ölçtü: kaç ölçüm, kaç seri, kaç bayt. Ama yanıtlanan
sekiz ya da dokuz sorunun her biri belirli bir etiketin varlığına bağlıydı ve `ornek` etiketi
güvenilmez olduğunda iki soru tek seferde kapandı. Bu ders o bağı ters yönden ölçer: bir etiket
**eklemek** hangi soruyu açıyor ve o soru kaç bayta açılıyor?

Etiketin seri sayısını neden toplamsal değil çarpımsal büyüttüğü **Konteyner Orkestrasyonu**
kursunun küme gözlemlenebilirliği dersinde ölçülmüştü: on bin serilik bir taban, yedi değerli tek
bir etiketle 6,8 kata, dört değerli bir etiket bütün ölçütlere eklendiğinde 28,3 kata çıkmıştı. O
ölçüm burada **tekrarlanmaz**; çarpım kuralı bu dersin **girdisidir**. Burada ölçülen şey başka
bir şeydir — çarpanın karşılığında **hangi sorunun açıldığı**.

Seri kümesi de sayılar da **kurgudur**; ölçülen şey `node` ile kurulmuş bir **modeldir**.

**OG7.** Etiket kümesi, kardinaliteler ve hangi etiketin hangi ölçüte uygulandığı kurgudur ve
önceden yazılıdır.
**OG8.** `ornek` etiketi servis içinde çözülür; servis başına en çok sekiz örnek varsayılır (bir
önceki dersteki 29 örnek dört servise dağılır).
**OG9.** Her sorunun geriye dönük bir **ufku** vardır: yanıtlanabilmesi için kaç günlük veriye
bakılması gerektiği önceden yazılıdır.
**OG10.** Örnekleme 15 saniye, bir kayıt 16 bayt, bir seri künyesi 120 bayttır (bir önceki dersle
aynı).
**OG11.** Bir sorunun açılmış sayılması için gerektirdiği **bütün** etiketlerin kümede bulunması
gerekir; tek başına yeten etiket yoktur.
**OG12.** Ölçüt kümesi bir önceki dersin ölçütlerinden türer; hiçbir soruyu yanıtlamayan üç ölçüt
orada sayıldığı için burada kümeye alınmaz.

#### Serinin İçindeki Karar

Bir zaman serisi bir ad ile bir etiket kümesinden oluşur ve depoda o ikilinin her ayrı bileşimi
ayrı bir seridir. Etiket kümesi bu yüzden bir depolama ayarı değil, bir **soru kararıdır**: hangi
ayrımı sonradan yapabileceğin toplama anında belirlenir.

```js
// seri.mjs — zaman serisi kumesi, etiket kardinaliteleri ve sorularin etiket/ufuk gereksinimi.
export const OLCUT = { "istek-sayisi": "uzun", "istek-suresi": "uzun", "kuyruk-boyu": "uzun",
  "islenen-okuma": "uzun", "is-adimi-suresi": "kisa", "is-islenen-kayit": "kisa" };
export const ETIKET = {                              // ad: [kardinalite, uygulandigi olcutler]
  servis: [4, ["istek-sayisi", "istek-suresi", "kuyruk-boyu", "islenen-okuma"]],
  is: [3, ["is-adimi-suresi", "is-islenen-kayit"]],
  ortam: [3, Object.keys(OLCUT)], surum: [4, Object.keys(OLCUT)], ornek: [8, Object.keys(OLCUT)],
  sonuc: [5, ["istek-sayisi", "islenen-okuma"]], dilim: [12, ["istek-suresi"]],
  kuyruk: [3, ["kuyruk-boyu"]], bolge: [11, ["islenen-okuma"]], adim: [6, ["is-adimi-suresi"]],
  "dugum-adi": [9, Object.keys(OLCUT)],
};
// soru: [kimlik, gereken etiketler, geriye dogru gereken ufuk (gun)]
export const SORU = [["S1", ["servis"], 1], ["S2", ["servis", "dilim"], 1],
  ["S3", ["ortam", "sonuc"], 1], ["S4", ["surum"], 30], ["S5", ["is"], 7],
  ["S6", ["is", "adim"], 7], ["S7", ["bolge", "sonuc"], 365], ["S8", ["ornek"], 7],
  ["S9", ["is", "ornek"], 7], ["S10", ["sonuc"], 1], ["S11", ["servis", "kuyruk"], 1],
  ["S12", ["islem-kimligi"], 1]];

export const seriSayisi = (acik) => Object.keys(OLCUT).reduce((t, m) => t +
  acik.reduce((c, e) => c * (ETIKET[e][1].includes(m) ? ETIKET[e][0] : 1), 1), 0);
export const bayt = (seri, gun, aralik = 15) => seri * Math.floor(86400 / aralik) * gun * 16 + seri * 120;
export const gb = (b) => (b / 1024 ** 3).toFixed(2);
```

Etiketlerin ölçütlere dağılımı eşit değildir. `bolge` yalnız işlenen okuma ölçütüne uygulanır;
`ortam`, `surum`, `ornek` ve `dugum-adi` bütün ölçütlere uygulanır. Bu ayrım maliyeti belirler:
tek bir ölçüte eklenen on bir değerli bir etiket, bütün ölçütlere eklenen dört değerli bir
etiketten ucuz olabilir.

#### Etiket Merdiveni

Merdiven boş bir kümeden başlar — yalnız servis ve iş adları — ve etiketleri birer birer ekler.
Her basamakta dört şey birlikte yazılır: seri, bayt, yanıtlanan soru ve **o basamakta açılan
sorunun marjinal bayt bedeli**.

```js
// etiket.mjs — etiket eklemenin actigi soru, kaldirmanin kapattigi soru ve saklama penceresi.
import { OLCUT, ETIKET, SORU, seriSayisi, bayt, gb } from "./seri.mjs";

const acilan = (a) => SORU.filter(([, e]) => e.every((x) => a.includes(x))).map(([k]) => k);
const MERDIVEN = ["ortam", "sonuc", "dilim", "kuyruk", "bolge", "adim", "surum", "ornek", "dugum-adi"];
let acik = ["servis", "is"], oncekiSoru = acilan(acik), oncekiBayt = bayt(seriSayisi(acik), 30);
console.log(`${Object.keys(OLCUT).length} olcut, 15 sn ornekleme, 30 gun saklama; taban etiketler ${acik.join(" + ")}`);
console.log("eklenen etiket   kardinalite     seri        GB   yanitlanan   acilan soru   marjinal GB/soru");
const yaz = (ad, kart) => {
  const s = seriSayisi(acik), b = bayt(s, 30), y = acilan(acik);
  const yeni = y.filter((q) => !oncekiSoru.includes(q));
  const marj = yeni.length ? gb((b - oncekiBayt) / yeni.length) : "-";
  console.log(`${ad.padEnd(15)}${String(kart).padStart(12)}${s.toLocaleString("tr-TR").padStart(9)}` +
    `${gb(b).padStart(10)}${String(`${y.length}/12`).padStart(13)}   ${(yeni.join(" ") || "-").padEnd(14)}${marj.padStart(8)}`);
  oncekiSoru = y; oncekiBayt = b;
};
yaz("taban", "-");
for (const e of MERDIVEN) { acik = [...acik, e]; yaz(`+ ${e}`, ETIKET[e][0]); }

const TAM = acik, tamBayt = bayt(seriSayisi(TAM), 30);
console.log(`\netiket kaldirildiginda (tam kume ${TAM.length} etiket,` +
  ` ${seriSayisi(TAM).toLocaleString("tr-TR")} seri, ${gb(tamBayt)} GB)`);
console.log("kaldirilan etiket   kazanilan GB   kapanan soru   GB/kapanan soru");
for (const e of TAM) {
  const kalan = TAM.filter((x) => x !== e), kazanc = tamBayt - bayt(seriSayisi(kalan), 30);
  const kapanan = acilan(TAM).filter((q) => !acilan(kalan).includes(q));
  console.log(`${e.padEnd(18)}${gb(kazanc).padStart(13)}   ${(kapanan.join(" ") || "-").padEnd(14)}` +
    `${(kapanan.length ? gb(kazanc / kapanan.length) : "-").padStart(9)}`);
}

const BUDANMIS = TAM.filter((e) => e !== "dugum-adi");
console.log(`\nsaklama penceresi (budanmis kume ${BUDANMIS.length} etiket,` +
  ` ${seriSayisi(BUDANMIS).toLocaleString("tr-TR")} seri)`);
console.log("pencere       GB   ufuk icinde yanitlanan   GB/soru   pencerenin actigi soru");
let oncekiUfuk = [];
for (const gun of [7, 30, 90, 395]) {
  const y = acilan(BUDANMIS).filter((q) => SORU.find(([k]) => k === q)[2] <= gun);
  const b = bayt(seriSayisi(BUDANMIS), gun);
  console.log(`${String(`${gun} gun`).padEnd(9)}${gb(b).padStart(9)}${String(`${y.length}/12`).padStart(24)}` +
    `${gb(b / y.length).padStart(10)}   ${y.filter((q) => !oncekiUfuk.includes(q)).join(" ") || "-"}`);
  oncekiUfuk = y;
}
```

```
6 olcut, 15 sn ornekleme, 30 gun saklama; taban etiketler servis + is
eklenen etiket   kardinalite     seri        GB   yanitlanan   acilan soru   marjinal GB/soru
taban                     -       22      0.06         2/12   -                    -
+ ortam                   3       66      0.17         2/12   -                    -
+ sonuc                   5      162      0.42         4/12   S3 S10            0.12
+ dilim                  12      294      0.76         5/12   S2                0.34
+ kuyruk                  3      318      0.82         6/12   S11               0.06
+ bolge                  11      918      2.36         7/12   S7                1.55
+ adim                    6      963      2.48         8/12   S6                0.12
+ surum                   4    3.852      9.92         9/12   S4                7.44
+ ornek                   8   30.816     79.35        11/12   S8 S9            34.72
+ dugum-adi               9  277.344    714.17        11/12   -                    -

etiket kaldirildiginda (tam kume 11 etiket, 277.344 seri, 714.17 GB)
kaldirilan etiket   kazanilan GB   kapanan soru   GB/kapanan soru
servis                   500.59   S1 S2 S11        166.86
is                        31.15   S5 S6 S9          10.38
ortam                    476.11   S3               476.11
sonuc                    427.17   S3 S7 S10        142.39
dilim                     97.89   S2                97.89
kuyruk                    17.80   S11               17.80
bolge                    444.97   S7               444.97
adim                      33.37   S6                33.37
surum                    535.63   S4               535.63
ornek                    624.90   S8 S9            312.45
dugum-adi                634.82   -                     -

saklama penceresi (budanmis kume 10 etiket, 30.816 seri)
pencere       GB   ufuk icinde yanitlanan   GB/soru   pencerenin actigi soru
7 gun        18.52                    9/12      2.06   S1 S2 S3 S5 S6 S8 S9 S10 S11
30 gun       79.35                   10/12      7.94   S4
90 gun      238.05                   10/12     23.80   -
395 gun    1044.76                   11/12     94.98   S7
```

Merdivenin ilk yarısı ucuzdur. Sonuç etiketi iki soruyu 0,12 gigabayta açar, kuyruk etiketi bir
soruyu 0,06 gigabayta, adım etiketi bir soruyu 0,12 gigabayta. Bunlar tek ölçüte uygulanan ya da
düşük kardinaliteli etiketlerdir; çarpım küçük bir çarpanla büyür.

İkinci yarı pahalıdır. Sürüm etiketi dört değerlidir ama **bütün ölçütlere** uygulandığı için
seriyi dört katına çıkarır ve tek bir soruyu — hangi sürümden sonra bozulduğu — 7,44 gigabayta
açar. Örnek etiketi iki soruyu açar, soru başına 34,72 gigabayta. Aynı kümede iki soru açan iki
farklı etiket arasında **üç yüz kat** fark vardır ve bu farkın kaynağı sorunun önemi değil,
etiketin kaç ölçüte uygulandığıdır.

`ortam` satırı ayrı okunmalıdır: eklendiği basamakta hiçbir soru açmaz. Ama S3 hem ortam hem sonuç
etiketini ister; ortam olmasa sonuç etiketi tek başına S3'ü açamazdı. Bir etiketin "hiçbir soru
açmaması" ile "tek başına yetmemesi" farklı şeylerdir ve merdiven bu ikisini ayırt edemez.

#### Etiketin Kaldırılması ve Budama

Ayrımı yapan şey ikinci tablodur: her etiket tam kümeden **çıkarılır** ve kapanan soru sayılır.
`ortam` çıkarıldığında S3 kapanır — demek ki payı vardır ve o pay 476 gigabayta mal olmaktadır.
`dugum-adi` çıkarıldığında **hiçbir soru kapanmaz**. Kazanılan bayt 634,82 gigabayttır: tam kümenin
yüzde seksen dokuzu.

Bu etiketin adı yazılmalıdır çünkü zararsız görünür. Dokuz değerli, kısa, okunması kolay bir
etikettir ve toplayıcı onu kendiliğinden ekler — düğüm adı zaten bilinmektedir. Sorunu, on iki
sorunun hiçbirinin düğüm adı sormamasıdır. Kapsül hangi düğümde koşuyorsa koşsun, işletimin sorduğu
şey servis, ortam, sürüm ve örnektir. Etiket bir soruya bağlanmadığı sürece bilgi değil, çarpandır.

Budama sırası da tablodan çıkar. Önce karşılığı olmayan etiket atılır; bu tek adım seriyi 277.344'ten
30.816'ya indirir. Ondan sonra kalan bütün etiketlerin marjinal maliyeti dokuzda birine iner — sürüm
etiketi 535 gigabayt yerine 59, örnek etiketi 624 yerine 69 gigabayt tutar. Karşılığı olan bir
etiketin pahalı görünmesinin nedeni çoğu zaman kendisi değil, yanındaki karşılıksız etikettir.

#### Çarpım Üst Sınırdır

Merdivenin bütün sayıları bir çarpımdan çıktı ve çarpım her etiket bileşiminin gerçekten
oluşacağını varsayar. Envanter bunu doğrulamaz: dört servisin örnek sayıları eşit değildir,
geliştirme ortamında iki servis hiç koşmaz ve işlenen okuma ölçütünü yalnız iki servis üretir.
Gerçekleşen seri kümesi envanterden sayılabilir.

```js
// gercek.mjs — carpim ust sinirdir: gerceklesen seri sayisi ve olcunun duzeltilmesi.
import { OLCUT, ETIKET, SORU, seriSayisi, bayt, gb } from "./seri.mjs";

const ORNEK = { "okuma-toplayici": [8, 2, 1], dogrulayici: [6, 2, 1],   // uretim, sinama, gelistirme
  faturalama: [4, 1, 0], "is-emri": [3, 1, 0] };
const EMITEN = { "islenen-okuma": ["okuma-toplayici", "dogrulayici"] };  // otekiler dort servisin hepsinde
const KOSUCU = 3 * 2;                                     // uc gecelik is, iki ortamda kosucu
const BUDANMIS = ["servis", "is", "ortam", "surum", "ornek", "sonuc", "dilim", "kuyruk", "bolge", "adim"];
const TABAN = ["servis", "is", "ortam", "ornek"];         // gercek envanterden sayilan uclu

const gerceklesen = Object.keys(OLCUT).reduce((t, m) => {
  const taban = OLCUT[m] === "kisa" ? KOSUCU
    : (EMITEN[m] || Object.keys(ORNEK)).reduce((s, v) => s + ORNEK[v].reduce((a, b) => a + b, 0), 0);
  return t + taban * BUDANMIS.filter((e) => !TABAN.includes(e) && ETIKET[e][1].includes(m))
    .reduce((c, e) => c * ETIKET[e][0], 1);
}, 0);

const kuramsal = seriSayisi(BUDANMIS), yanit = SORU.filter(([, e]) => e.every((x) => BUDANMIS.includes(x))).length;
console.log("olcut                gerceklesen   kuramsal   fazla sayim");
for (const m of Object.keys(OLCUT)) {
  const taban = OLCUT[m] === "kisa" ? KOSUCU
    : (EMITEN[m] || Object.keys(ORNEK)).reduce((s, v) => s + ORNEK[v].reduce((a, b) => a + b, 0), 0);
  const carpan = BUDANMIS.filter((e) => !TABAN.includes(e) && ETIKET[e][1].includes(m))
    .reduce((c, e) => c * ETIKET[e][0], 1);
  const k = BUDANMIS.reduce((c, e) => c * (ETIKET[e][1].includes(m) ? ETIKET[e][0] : 1), 1);
  console.log(`${m.padEnd(22)}${(taban * carpan).toLocaleString("tr-TR").padStart(9)}${k.toLocaleString("tr-TR").padStart(11)}` +
    `${String(`${(k / (taban * carpan)).toFixed(1)} kat`).padStart(14)}`);
}
console.log(`${"toplam".padEnd(22)}${gerceklesen.toLocaleString("tr-TR").padStart(9)}` +
  `${kuramsal.toLocaleString("tr-TR").padStart(11)}${String(`${(kuramsal / gerceklesen).toFixed(1)} kat`).padStart(14)}`);
console.log(`\n30 gunluk saklama   kuramsal ${gb(bayt(kuramsal, 30))} GB` +
  `   gerceklesen ${gb(bayt(gerceklesen, 30))} GB`);
console.log(`${yanit}/12 soru icin soru basina   kuramsal ${gb(bayt(kuramsal, 30) / yanit)} GB` +
  `   gerceklesen ${gb(bayt(gerceklesen, 30) / yanit)} GB`);
```

```
olcut                gerceklesen   kuramsal   fazla sayim
istek-sayisi                580      1.920       3.3 kat
istek-suresi              1.392      4.608       3.3 kat
kuyruk-boyu                 348      1.152       3.3 kat
islenen-okuma             4.400     21.120       4.8 kat
is-adimi-suresi             144      1.728      12.0 kat
is-islenen-kayit             24        288      12.0 kat
toplam                    6.888     30.816       4.5 kat

30 gunluk saklama   kuramsal 79.35 GB   gerceklesen 17.74 GB
11/12 soru icin soru basina   kuramsal 7.21 GB   gerceklesen 1.61 GB
```

Çarpım toplamda dört buçuk kat fazla sayar, gecelik iş ölçütlerinde on iki kat. Nedeni ölçüt
başına farklıdır: servis-ortam-örnek üçlüsünün kuramsal doksan altı bileşiminden yalnız yirmi
dokuzu vardır, işlenen okumayı dört servisten ikisi üretir, gecelik işi üç ortamda sekiz örnek
değil iki ortamda tek koşucu çalıştırır.

Bu düzeltme kararı değiştirir. Kuramsal sayıya bakan bir saklama tartışması otuz günü 79
gigabayta, soru başına 7,21 gigabayta fiyatlandırır; envanterden sayılan gerçek küme aynı otuz
günü 17,74 gigabayta, soru başına 1,61 gigabayta indirir. Aradaki fark bir tasarruf değil, bir
**ölçüm hatasıdır** — dört buçuk kat abartılmış bir maliyet, hiç eklenmemesi gereken bir etiketin
eklenmemesine değil, gereken bir etiketin eklenmemesine yol açar.

#### Saklama Penceresi

Etiket kümesi bir sorunun **hangi ayrımı** yapabileceğini belirler; saklama penceresi **ne kadar
geriye** bakabileceğini. Üçüncü tablo aynı budanmış kümeyi dört pencerede ölçer; sayılar kuramsal
seri kümesi üzerindendir, gerçekleşen kümede hepsi dört buçuğa bölünür.

Yedi günlük pencere on sekiz buçuk gigabayt tutar ve dokuz soruyu yanıtlar — soru başına 2,06
gigabayt. Otuz gün S4'ü açar: bir sürüm karşılaştırması iki sürümün de üretimde kaldığı süreyi
kapsamalıdır ve dağıtım sıklığı buna otuz gün gerektirir. Bedeli soru başına 7,94 gigabayttır.

Doksan günlük pencere hiçbir yeni soru açmaz. Üç kat bayt, sıfır soru — soru başına maliyet 23,80
gigabayta çıkar. Bu satır, saklamayı "biraz daha uzun tutalım" diye uzatan kararın tam karşılığıdır.

Üç yüz doksan beş gün tek bir soruyu açar: hangi bölgenin okumasının doğrulamadan geçmediği,
geçen yılın aynı dönemiyle karşılaştırılarak. Bedeli 965 gigabayt ek saklamadır. Yanıtsız kalmasının
bedeli de sayılabilir: mevsimsel karşılaştırma yapılamadığında hangi bölgenin kalıcı olarak sorunlu
olduğu ayırt edilemez ve saha ekibi tek bölge yerine **on bir bölgenin** tamamı için iş emri
kapatmak zorunda kalır. Hangi sayının büyük olduğu bölgesel ölçüm ağının kendi maliyet yapısına
bağlıdır; kararı taşıyan şey, iki sayının aynı tabloda durmasıdır.

S12 bu tabloların hiçbirinde görünmez. Ne etiket eklemek ne saklamayı uzatmak onu açar; bir
faturanın hangi okumadan üretildiği sorusu etiketle çözülemez, çünkü gereken ayrım işlem
başınadır.

#### Özet

- Bir etiketin bedeli kardinalitesi değil, kardinalitesi ile uygulandığı ölçüt sayısının
  çarpımıdır: 11 değerli `bolge` bir soruyu 1,55 GB'a açarken 4 değerli `surum` bir soruyu 7,44
  GB'a açar.
- Merdiven 22 seriden 277.344 seriye çıkarken yanıtlanan soru 2/12'den 11/12'ye çıkar; marjinal
  soru başına bayt 0,06 GB'dan 34,72 GB'a kadar üç yüz kat değişir.
- `dugum-adi` hiçbir soruyu açmaz ve hiçbir soruyu kapatmaz; kaldırılması 634,82 GB kazandırır,
  tam kümenin yüzde 89'u. Budama ilk adımdır; sonrasında öteki etiketlerin maliyeti dokuzda birine
  iner.
- Eklendiği basamakta soru açmayan etiket ile hiçbir soruya payı olmayan etiket farklıdır: `ortam`
  tek başına soru açmaz ama kaldırıldığında S3 kapanır.
- Çarpım üst sınırdır: envanterden sayılan gerçekleşen küme 6.888 seridir, kuramsal 30.816'nın
  dörtte biri; soru başına maliyet 7,21 GB'dan 1,61 GB'a iner.
- Saklama penceresi sorunun ufkunu belirler: 7 gün 9/12 soruyu 2,06 GB/soruya, 30 gün 10/12'yi
  7,94 GB/soruya, 395 gün 11/12'yi 94,98 GB/soruya yanıtlar. 90 günlük pencere üç kat bayt karşılığında
  hiçbir yeni soru açmaz.

#### Sonraki Adım

Buraya kadar seri kümesi bir depo gibi ele alındı: kaç seri var, kaç bayt tutuyor, hangi ayrımı
saklıyor. Ama hiçbir soru serinin kendisiyle yanıtlanmaz; yanıt bir **toplulaştırmadan** çıkar —
ortalama, yüzdelik, toplam, oran. Bir sonraki ders aynı soruyu farklı toplulaştırmalarla yanıtlar
ve yanıtın değiştiğini gösterir: hangi toplulaştırma neyi gizliyor, önceden toplulaştırma hangi
ayrıntıyı geri getirilemez biçimde siliyor ve karşılığında sorgu maliyetinden ne kazandırıyor.

### Sorgu ve Toplulaştırma

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/sorgu-ve-toplulastirma

Aynı soru dört toplulaştırmayla yanıtlanır ve yanıtın değiştiği gösterilir: ortalama gizler, yüzdelik gösterir, toplam yanıltır, sayı ile oran farklı servisi işaret eder. Önceden toplulaştırmanın geri getirilemez biçimde kaybettiği ayrıntı ile kazandırdığı sorgu maliyeti aynı tabloda sayılır.

Bir önceki ders seri kümesinin hangi ayrımı sakladığını ölçtü. Ama hiçbir soru serinin kendisiyle
yanıtlanmaz: bir seri yüz binlerce sayıdır ve yanıt tek bir sayı olmak zorundadır. Araya
**toplulaştırma** girer — ortalama, yüzdelik, en büyük, toplam — ve bu ders o adımın kararsız
olduğunu gösterir: aynı veriden, aynı soruya, farklı toplulaştırmalarla **farklı yanıtlar** çıkar.

İkinci ölçü önceden toplulaştırmadır. Ham ölçümü saklamak yerine dakikalık özet saklamak sorgu
maliyetini iki mertebe düşürür ve karşılığında bir ayrıntıyı geri getirilemez biçimde siler.
Bu dersin ölçüsü, o iki tarafı aynı tabloda saymaktır.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**; gerçek trafik koşturulmaz, sayılan
şey `node` ile üretilmiş bir **modeldir**.

**OG13.** Dört servisin istek hızı ve gecikme profili kurgudur ve önceden yazılıdır.
**OG14.** Ölçümler kendi üretecimizle üretilir, tohum `20260902`; bir saatlik pencerede 90.000
istek.
**OG15.** Faturalama servisinin isteklerinin yüzde altısı kilit bekler ve 950–1100 ms ek gecikme
alır; öteki üç servisin dağılımı düzgündür. Doğrulayıcıya ayrıca 90 saniye süren kurgu bir
bozulma eklenir (+900 ms) ve olaysız profil değerleri eşik tabanı sayılır.
**OG16.** Önceden toplulaştırma dakika başına dört alan tutar: adet, toplam, en büyük ve
dakikanın p95 değeri.
**OG17.** Özetten hesaplanan genel p95, dakika p95'lerinin istek sayısıyla ağırlıklı ortalamasıdır
— yüzdeliklerin birleştirilebileceği varsayımı bilerek uygulanır.
**OG18.** Süre ölçümü ortama bağlıdır; çıktıya yalnız bant denetiminin sonucu basılır, ham ölçüm
basılmaz.

#### Ham Ölçüm Kümesi

```js
// olcum.mjs — bir saatlik istek olcumleri kendi uretecimizle uretilir; profiller kurgudur.
export const uretec = (t) => () => (t = (t * 1103515245 + 12345) % 2147483648) / 2147483648;
export const PENCERE = 3600;
export const PROFIL = {                              // servis: [istek/sn, taban, yayilim, kuyruk payi, kuyruk ms, hata orani]
  "okuma-toplayici": [12, 150, 110, 0, 0, 0.012],
  dogrulayici: [8, 90, 40, 0, 0, 0.006],
  faturalama: [3, 40, 30, 0.06, 950, 0.035],
  "is-emri": [2, 200, 40, 0, 0, 0.009],
};
export const olcumler = (tohum = 20260902) => {
  const rast = uretec(tohum), o = {};
  for (const [servis, [hiz, taban, yayilim, pay, kuyruk, hata]] of Object.entries(PROFIL)) {
    const d = [];
    for (let sn = 0; sn < PENCERE; sn++)
      for (let i = 0; i < hiz; i++) {
        const kuyruklu = rast() < pay;
        d.push({ sn, ms: Math.round(taban + rast() * yayilim + (kuyruklu ? kuyruk + rast() * 150 : 0)),
          hata: rast() < hata });
      }
    o[servis] = d;
  }
  return o;
};
export const yuzdelik = (a, p) => {
  const s = [...a].sort((x, y) => x - y);
  return s[Math.min(s.length - 1, Math.ceil(p * s.length) - 1)];
};
export const enBuyukAd = (o) => Object.entries(o).sort((a, b) => b[1] - a[1])[0][0];
```

Profiller birbirinden yalnız ortalamayla ayrılmaz. Okuma toplayıcı yüksek hacimli ve düzgün
dağılımlıdır; faturalama düşük hacimli ve kuyrukludur — isteklerinin yüzde altısı bir saniyenin
üstünde biter. Bu iki biçim, gerçek işletimde en sık karşılaşılan iki gecikme desenidir ve
aralarındaki farkı hangi toplulaştırmanın gördüğü baştan belli değildir.

#### Aynı Soru, Dört Toplulaştırma

```js
// sorgu.mjs — ayni soru farkli toplulastirmalarla yanitlanir; onceden toplulastirmanin bedeli sayilir.
import { PROFIL, PENCERE, olcumler, yuzdelik, enBuyukAd } from "./olcum.mjs";

const ham = olcumler();
const servisler = Object.keys(PROFIL);
const toplamIstek = servisler.reduce((t, s) => t + ham[s].length, 0);
console.log(`bir saatlik olcum (kurgu model): ${toplamIstek.toLocaleString("tr-TR")} istek, ${servisler.length} servis`);
console.log("\nS1 'hangi servis yavasladi' — toplulastirmaya gore yanit");
console.log("toplulastirma   okuma-toplayici  dogrulayici  faturalama  is-emri   yanit");
const OLCU = [["ortalama ms", (d) => d.reduce((t, x) => t + x.ms, 0) / d.length],
  ["p95 ms", (d) => yuzdelik(d.map((x) => x.ms), 0.95)],
  ["en buyuk ms", (d) => Math.max(...d.map((x) => x.ms))],
  ["toplam sn", (d) => d.reduce((t, x) => t + x.ms, 0) / 1000]];
for (const [ad, f] of OLCU) {
  const v = Object.fromEntries(servisler.map((s) => [s, f(ham[s])]));
  console.log(`${ad.padEnd(14)}` + servisler.map((s, i) =>
    v[s].toFixed(0).padStart([17, 13, 12, 9][i])).join("") + `   ${enBuyukAd(v)}`);
}

console.log("\nS10 'hangi hata kodu artti' — sayi mi oran mi");
const hataSayi = Object.fromEntries(servisler.map((s) => [s, ham[s].filter((x) => x.hata).length]));
const hataOran = Object.fromEntries(servisler.map((s) => [s, 100 * hataSayi[s] / ham[s].length]));
console.log("olcu            " + servisler.map((s, i) => s.padStart([17, 13, 12, 9][i])).join("") + "   yanit");
console.log("hata sayisi   " + servisler.map((s, i) => String(hataSayi[s]).padStart([19, 13, 12, 9][i])).join("") +
  `   ${enBuyukAd(hataSayi)}`);
console.log("hata orani %  " + servisler.map((s, i) => hataOran[s].toFixed(2).padStart([19, 13, 12, 9][i])).join("") +
  `   ${enBuyukAd(hataOran)}`);
```

```
bir saatlik olcum (kurgu model): 90.000 istek, 4 servis

S1 'hangi servis yavasladi' — toplulastirmaya gore yanit
toplulastirma   okuma-toplayici  dogrulayici  faturalama  is-emri   yanit
ortalama ms                 204          110         125      220   is-emri
p95 ms                      255          128        1042      238   faturalama
en buyuk ms                 260          130        1166      240   faturalama
toplam sn                  8834         3162        1350     1582   okuma-toplayici

S10 'hangi hata kodu artti' — sayi mi oran mi
olcu              okuma-toplayici  dogrulayici  faturalama  is-emri   yanit
hata sayisi                   523          168         428       66   okuma-toplayici
hata orani %                 1.21         0.58        3.96     0.92   faturalama
```

Tek bir soru, dört farklı yanıt üretecek üç ayrı toplulaştırma. Sayılar aynı 90.000 isteğe aittir
ve hiçbiri yanlış değildir.

**Ortalama gizler.** Faturalamanın ortalaması 125 milisaniyedir ve dört servisin en düşük
ikincisidir. Kuyrukta bekleyen yüzde altılık dilim ortalamayı yalnız yetmiş milisaniye yukarı
çeker, çünkü ortalama uç değerleri hacme böler. Ortalamaya bakan bir gösterge faturalamayı hiç
göstermez.

**Yüzdelik gösterir.** Aynı servisin p95 değeri 1042 milisaniyedir — ötekilerin dört ile sekiz
katı arasında. Kuyruk p95'te saklanamaz, çünkü yüzde altılık dilim yüzde beşlik eşiğin üstündedir.
Bir istekten yirmisi saniyeyi aşıyorsa bu ancak yüzdelikte görünür.

**Toplam yanıltır.** Toplam süreye bakıldığında yanıt okuma toplayıcıdır: 8834 saniye. Ama bu
sayının söylediği şey gecikme değil, **hacimdir** — okuma toplayıcı saatte 43.200 istek alır,
faturalama 10.800. Toplam, hızı ölçmek isterken iş yükünü ölçer. Kapasite sorusunda doğru,
gecikme sorusunda yanıltıcıdır.

Hata tablosu aynı ayrımı ikinci kez kurar. Hata **sayısı** okuma toplayıcıyı işaret eder (523),
hata **oranı** faturalamayı (%3,96). İkisi de doğrudur ve iki farklı soruyu yanıtlar: "en çok
hangi servis hata üretiyor" ile "hangi servis en bozuk". Nöbetteki kişiye yanlış olanı
gösterildiğinde inceleme, hata oranı üç kat düşük olan servisin günlüklerinde başlar.

#### Sorgu Penceresi Aynı Şeyi Yapar

Toplulaştırma yalnız hangi işlevin uygulandığı değil, **hangi aralığa** uygulandığıdır. Aynı
ortalama bir dakikaya ve bir saate uygulandığında farklı şeyler ölçer. Aşağıdaki blok doğrulayıcıya
kısa bir bozulma yerleştirir ve aynı iki toplulaştırmayı dört pencerede sorar.

```js
// pencere.mjs — sorgu penceresi degistiginde ayni soru baska yanit verir.
import { PROFIL, PENCERE, olcumler, yuzdelik } from "./olcum.mjs";

const ham = olcumler();
const OLAY = { servis: "dogrulayici", bas: 1500, sure: 90, ek: 900 };   // kurgu bozulma
for (const x of ham[OLAY.servis])
  if (x.sn >= OLAY.bas && x.sn < OLAY.bas + OLAY.sure) x.ms += OLAY.ek;
const d = ham[OLAY.servis];
const taban = { ort: 110, p95: 128 };                    // olaysiz profilin degerleri
console.log(`${OLAY.servis} servisinde ${OLAY.sure} sn suren +${OLAY.ek} ms bozulma` +
  ` (saatin %${(100 * OLAY.sure / PENCERE).toFixed(1)}'i); esik taban degerinin iki kati`);
console.log("sorgu penceresi  pencere  en yuksek ort ms  esigi asan  en yuksek p95 ms  esigi asan  fark etme");
for (const w of [60, 300, 900, 3600]) {
  const say = PENCERE / w, ort = [], p95 = [];
  for (let i = 0; i < say; i++) {
    const g = d.filter((x) => x.sn >= i * w && x.sn < (i + 1) * w).map((x) => x.ms);
    ort.push(g.reduce((a, b) => a + b, 0) / g.length); p95.push(yuzdelik(g, 0.95));
  }
  console.log(`${String(`${w / 60} dk`).padEnd(15)}${String(say).padStart(8)}` +
    `${Math.max(...ort).toFixed(0).padStart(18)}${String(`${ort.filter((v) => v > 2 * taban.ort).length}/${say}`).padStart(12)}` +
    `${String(Math.max(...p95)).padStart(18)}${String(`${p95.filter((v) => v > 2 * taban.p95).length}/${say}`).padStart(12)}` +
    `${String(`${w / 60} dk`).padStart(11)}`);
}
console.log(`\ncozunurluk basina kayit (bir saat, dort servis): ` +
  [60, 300, 900, 3600].map((w) => `${w / 60} dk ${4 * (PENCERE / w) * 4}`).join("   "));
```

```
dogrulayici servisinde 90 sn suren +900 ms bozulma (saatin %2.5'i); esik taban degerinin iki kati
sorgu penceresi  pencere  en yuksek ort ms  esigi asan  en yuksek p95 ms  esigi asan  fark etme
1 dk                 60              1009        2/60              1028        2/60       1 dk
5 dk                 12               380        1/12              1023        1/12       5 dk
15 dk                 4               200         0/4              1008         1/4      15 dk
60 dk                 1               132         0/1               129         0/1      60 dk

cozunurluk basina kayit (bir saat, dort servis): 1 dk 960   5 dk 192   15 dk 64   60 dk 16
```

Bozulma saatin yüzde iki buçuğudur ve dört pencerede dört farklı görünür. Bir dakikalık pencerede
hem ortalama hem yüzdelik bin milisaniyenin üstüne çıkar ve iki pencere eşiği aşar. Beş dakikada
ortalama 380'e iner ama hâlâ eşiğin üstündedir. **On beş dakikada ortalama ölür**: en yüksek değer
200 milisaniyedir ve iki yüz yirmilik eşiğin altında kalır — hiçbir pencere işaretlenmez. Aynı
pencerede yüzdelik hâlâ 1008 milisaniye görür ve bir pencere işaretler. Bir saatte ikisi de kaybolur:
ortalama 132, yüzdelik 129 milisaniye — olayın hiçbir izi yoktur.

Kayıp sayısı ile bedel aynı satırdadır. Bir dakikalık çözünürlük saatte 960, bir saatlik çözünürlük
16 kayıt tutar — altmış kat fark. Fark etme süresi de pencerenin kendisidir: bir pencere kapanmadan
sorgulanamaz, dolayısıyla on beş dakikalık çözünürlük en iyi durumda on beş dakikalık bir gecikme
demektir. Bozulma doksan saniye sürüyorsa o on beş dakika olayın tamamının bitmesinden sonrasına
düşer.

#### Önceden Toplulaştırmanın İki Yüzü

Ham ölçümü istek başına saklamak pahalıdır. Yaygın karşılık dakikalık özet tutmaktır: her dakika
için adet, toplam, en büyük ve dakikanın p95 değeri. Aşağıdaki blok özeti gerçekten üretir ve
aynı soruları iki depoya sorar.

```js
// onagg.mjs — onceden toplulastirmanin kaybettigi ayrinti ve kazandirdigi sorgu maliyeti.
import { PROFIL, olcumler, yuzdelik } from "./olcum.mjs";

const ham = olcumler(), servisler = Object.keys(PROFIL);
const ozet = {};                                     // dakikalik ozet: adet, toplam, en buyuk, dakika p95
for (const s of servisler) {
  ozet[s] = Array.from({ length: 60 }, (_, d) => {
    const g = ham[s].filter((x) => Math.floor(x.sn / 60) === d).map((x) => x.ms);
    return { adet: g.length, toplam: g.reduce((a, b) => a + b, 0), enBuyuk: Math.max(...g), p95: yuzdelik(g, 0.95) };
  });
}
const hamHepsi = servisler.flatMap((s) => ham[s].map((x) => x.ms));
const hamKayit = hamHepsi.length, ozetKayit = servisler.length * 60 * 4;
const hamP95 = yuzdelik(hamHepsi, 0.95);
const ozetP95 = servisler.reduce((t, s) => t + ozet[s].reduce((a, d) => a + d.p95 * d.adet, 0), 0) / hamKayit;
const hamOrt = hamHepsi.reduce((a, b) => a + b, 0) / hamKayit;
const ozetOrt = servisler.reduce((t, s) => t + ozet[s].reduce((a, d) => a + d.toplam, 0), 0) / hamKayit;
const sapma = (o, h) => `%${(100 * Math.abs(o - h) / h).toFixed(1)}`;

console.log(`ham ${hamKayit.toLocaleString("tr-TR")} kayit, dakikalik ozet ${ozetKayit} kayit` +
  ` (${(hamKayit / ozetKayit).toFixed(0)} kat kucuk)`);
console.log("\nsoru                        ham yanit    ozetten yanit   sapma");
const SATIR = [["genel ortalama ms", hamOrt.toFixed(1), ozetOrt.toFixed(1), sapma(ozetOrt, hamOrt)],
  ["genel p95 ms", String(hamP95), ozetP95.toFixed(1), sapma(ozetP95, hamP95)],
  ["en buyuk ms", String(Math.max(...hamHepsi)),
    String(Math.max(...servisler.flatMap((s) => ozet[s].map((d) => d.enBuyuk)))), "%0.0"],
  ["1 sn ustu istek", String(hamHepsi.filter((x) => x > 1000).length), "hesaplanamaz", "-"]];
for (const [a, h, o, s] of SATIR)
  console.log(`${a.padEnd(26)}${h.padStart(11)}${o.padStart(16)}${s.padStart(8)}`);

// sorgu maliyeti: ayni p95 sorgusu iki depoda TEKRAR kez kosturulur
const TEKRAR = 40;
const beklenenOran = hamKayit / ozetKayit;
const olc = (f) => { const b = process.hrtime.bigint(); for (let i = 0; i < TEKRAR; i++) f(); return Number(process.hrtime.bigint() - b); };
const hamSure = olc(() => servisler.map((s) => yuzdelik(ham[s].map((x) => x.ms), 0.95)));
const ozetSure = olc(() => servisler.map((s) => yuzdelik(ozet[s].map((d) => d.p95), 0.95)));
const olculenOran = hamSure / ozetSure;
console.log(`\np95 sorgusu ${TEKRAR} kez kosturuldu`);
console.log(`  taranan kayit          ham ${(hamKayit * TEKRAR).toLocaleString("tr-TR")}` +
  `   ozet ${(ozetKayit * TEKRAR).toLocaleString("tr-TR")}   beklenen oran ${beklenenOran.toFixed(0)} kat`);
console.log(`  olculen sure orani 5 ile 20000 kat arasinda mi: ${olculenOran > 5 && olculenOran < 20000 ? "evet" : "hayir"}`);
```

```
ham 90.000 kayit, dakikalik ozet 960 kayit (94 kat kucuk)

soru                        ham yanit    ozetten yanit   sapma
genel ortalama ms               165.9           165.9    %0.0
genel p95 ms                      251           288.1   %14.8
en buyuk ms                      1166            1166    %0.0
1 sn ustu istek                   729    hesaplanamaz       -

p95 sorgusu 40 kez kosturuldu
  taranan kayit          ham 3.600.000   ozet 38.400   beklenen oran 94 kat
  olculen sure orani 5 ile 20000 kat arasinda mi: evet
```

Tablo üç ayrı davranışı yan yana koyar. Ortalama **birebir korunur**: sapma sıfırdır, çünkü
ortalama toplam ve adetten yeniden kurulabilir — dakikalık toplamların toplamı saatin toplamıdır.
En büyük değer de korunur, aynı nedenle: en büyüklerin en büyüğü gerçek en büyüktür.

Yüzdelik korunmaz. Genel p95 hamda 251, özetten 288 milisaniyedir; sapma yüzde 14,8. Nedeni tek
cümledir: **yüzdeliklerin ortalaması yüzdelik değildir.** Dakikalık p95 değerleri her dakikanın
kendi dağılımının üst dilimidir; bunları istek sayısıyla ağırlıklandırıp toplamak, saatin
dağılımının üst dilimini vermez. Yön de rastlantı değildir — bu veri kümesinde özet yukarı sapar,
çünkü faturalamanın kuyruğu her dakikanın p95'ini yukarı çeker ve o dakikalar toplamda seyrelmez.
Başka bir veri kümesinde aynı yöntem aşağı sapabilir; kestirilebilir olan tek şey sapmanın
varlığıdır.

Son satır tümüyle kayıptır. "Kaç istek bir saniyeyi aştı" sorusunun hamda yanıtı 729'dur; özette
yanıt yoktur ve yaklaşık bir yanıt da yoktur, çünkü eşiğin üstündeki istek sayısı özetin dört
alanının hiçbirinde durmaz. Ayrıntı silinmiştir ve geri getirilemez. Bunu görünür kılan şey de
yoktur: özet üzerinde bu sorgu yazıldığında depo hata vermez, yalnız sorgunun yazılamayacağı
anlaşılır.

Kazanç tarafı da aynı tablodadır. Aynı p95 sorgusu ham depoda 3,6 milyon kayıt tarar, özet depoda
38.400 — **94 kat** az. Süre ölçümü ortama bağlıdır ve buraya basılmaz; ölçülen oranın beklenen
mertebeyle uyumlu olup olmadığı bant denetiminden geçirilir ve sonuç `evet` yazılır.

Karar iki sayının çarpışmasındadır: doksan dört kat ucuz sorgu, yüzde on beş sapmış bir yüzdelik
ve tümüyle kaybolmuş bir eşik sorusu. Özet, ortalama ve en büyük soran gösterge tabloları için
bedavaya yakındır; yüzdelik ve eşik soran uyarı kuralları için yanlış bir tabandır.

#### Özet

- Aynı soru dört toplulaştırmayla üç farklı yanıt verir: ortalama `is-emri`, p95 ve en büyük
  `faturalama`, toplam `okuma-toplayici`. Hiçbiri yanlış değildir; her biri başka bir şeyi ölçer.
- Ortalama uç dilimi hacme böldüğü için gizler (faturalama 125 ms), yüzdelik gösterir (1042 ms);
  toplam gecikme yerine hacmi ölçer.
- Hata sayısı ile hata oranı farklı servisi işaret eder: 523 hata `okuma-toplayici`, %3,96 oran
  `faturalama`.
- Sorgu penceresi de bir toplulaştırmadır: 90 saniyelik bir bozulma 1 dakikalık pencerede hem
  ortalamada hem yüzdelikte görünür, 15 dakikada yalnız yüzdelikte, 60 dakikada hiçbirinde.
  Çözünürlük 960 kayıttan 16 kayda inerken fark etme süresi 1 dakikadan 60 dakikaya çıkar.
- Önceden toplulaştırma ortalamayı ve en büyüğü birebir korur (%0,0), p95'i %14,8 saptırır,
  eşik üstü istek sayısını tümüyle siler — 729 istek özette hesaplanamaz.
- Aynı sorgu ham depoda 3,6 milyon, özet depoda 38.400 kayıt tarar: 94 kat ucuz. Kazanç ile kayıp
  aynı kararın iki yüzüdür.

#### Sonraki Adım

Buraya kadar her yanıt bir sayıydı: kaç milisaniye, kaç istek, kaç hata. Ama tablodaki hiçbir sayı
**neden** sorusunu yanıtlamaz. Faturalamanın p95'inin 1042 milisaniye olduğu bilinir; hangi
kilidin, hangi sorgunun, hangi bölgenin okumasında beklendiği bilinmez. O bilgi ölçütte değil,
sürecin kendi yazdığı metinde durur. Bir sonraki ders günlük akışını ele alır ve o metnin toplama
hattından geçerken kaç satırının kaybolduğunu katman katman sayar.

### Günlük Toplama

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/gunluk-toplama

Günlük akışı aracı, tampon ve dizinleme katmanlarından geçirilir ve her katmanda kaybolan kayıt sayılır: tampon dolması, kırpma ve dizinleme gecikmesi. Yük iki katına çıktığında hangi katmanın önce kırıldığı ölçülür ve kaybın hangi soruyu yanıtsız bıraktığı, soru başına maliyetle birlikte yazılır.

Bir önceki dersin bütün yanıtları sayıydı: kaç milisaniye, kaç istek, kaç hata. Ama hiçbir sayı
**neden** sorusunu yanıtlamaz — faturalamanın p95'inin 1042 milisaniye olduğu bilinir, hangi
kilitte beklendiği bilinmez. O bilgi ölçütte değil, sürecin kendi yazdığı metinde durur.

Günlük satırı ölçütten farklı bir şeydir: önceden tanımlı bir seri değil, olay anında yazılmış bir
metindir ve kardinalitesi sınırsızdır. Bedeli de buradan gelir. Bir ölçüt hattı saniyede birkaç
bin sayı taşır; günlük hattı saniyede on binlerce satır. Bu ders o hattı üç katmana ayırır —
**günlük aracısı**, **tampon** ve **dizinleyici** — ve her katmanda kaç kaydın kaybolduğunu sayar.

Akış **bölgesel ölçüm ağının** akışıdır ve **kurgudur**; gerçek bir günlük deposu koşturulmaz,
sayılan şey `node` ile saniye saniye koşan bir **modeldir**.

**OG19.** Satır hızları, karışım ve katman sınırları kurgudur ve önceden yazılıdır; benzetimde
rastgelelik yoktur, aynı girdi her koşumda aynı sayıyı verir.
**OG20.** Günlük aracısı saniyede 1400 satır okur ve 30.000 satırlık yerel tampon tutar; kuyruk
300.000 satır, dizinleyici saniyede 1000 satırdır.
**OG21.** Kırpma 512 baytta yapılır. Hata satırı 620 bayttır ve son 108 baytında hata kodu ile
sürecin ürettiği işlem kimliği durur.
**OG22.** Tampon dolduğunda düşen satırların türü o saniyenin bileşimindedir; kuyruk tür ayrımı
yapmaz.
**OG23.** Bir satır yazıldıktan 60 saniyeden geç dizinlenirse "geç görünen" sayılır ve olay anında
sorulan soru için yok kabul edilir.
**OG24.** Bir soru, gerektirdiği satır türündeki kayıp kabul payının altındaysa yanıtlanır: oran
soruları yüzde 10, sayım soruları yüzde 1. S11 ölçer değeri günlüğe yazılmadığı için, S12
servisler zincirinde ortak bir kimlik olmadığı için hiçbir yükte yanıtlanmaz.

#### Üç Katman ve Sınırları

```js
// akis.mjs — gunluk akisi araci, tampon ve dizinleme katmanlarindan gecirilir; her katmanda kayip sayilir.
export const TABAN = 232, KARISIM = { istek: 0.86, hata: 0.02, "is-adimi": 0.12 };
export const BAYT = { istek: 180, hata: 620, "is-adimi": 240 };
export const IS_BAS = 600, IS_BIT = 1200, IS_EK = 900;   // gecelik toplu is penceresi, tamami is-adimi
export const SINIR = { araciOkuma: 1400, araciTampon: 30000, kuyruk: 300000, dizin: 1000,
  kirpma: 512, gorunurluk: 60 };
export const PENCERE = 3600;

export const kostur = (yuk, s = SINIR) => {
  let tampon = 0, kuyruk = 0;
  const d = { uretilen: 0, araciDusen: 0, kuyrukDusen: 0, dizinlenen: 0, gecGorunen: 0,
    enBuyukGecikme: 0, tur: {}, dusenTur: {} };
  for (const t of Object.keys(BAYT)) { d.tur[t] = 0; d.dusenTur[t] = 0; }
  for (let sn = 0; sn < PENCERE; sn++) {
    const girdi = {};                                    // o saniyenin satir bilesimi
    for (const t of Object.keys(BAYT)) girdi[t] = yuk * TABAN * KARISIM[t];
    if (sn >= IS_BAS && sn < IS_BIT) girdi["is-adimi"] += yuk * IS_EK;
    const toplam = Object.values(girdi).reduce((a, b) => a + b, 0);
    for (const t of Object.keys(BAYT)) d.tur[t] += girdi[t];
    d.uretilen += toplam;

    tampon += toplam;                                    // katman 1: araci
    const okunan = Math.min(tampon, s.araciOkuma);
    tampon -= okunan;
    if (tampon > s.araciTampon) {
      const dus = tampon - s.araciTampon;                // dusen satirlar o saniyenin bilesimindedir
      for (const t of Object.keys(BAYT)) d.dusenTur[t] += dus * girdi[t] / toplam;
      d.araciDusen += dus; tampon = s.araciTampon;
    }
    kuyruk += okunan;                                    // katman 2: tampon kuyrugu
    if (kuyruk > s.kuyruk) {                             // kuyruk tur ayrimi yapmaz, kayip her ture yayilir
      const dus = kuyruk - s.kuyruk;
      for (const t of Object.keys(BAYT)) d.dusenTur[t] += dus * girdi[t] / toplam;
      d.kuyrukDusen += dus; kuyruk = s.kuyruk;
    }
    const dizin = Math.min(kuyruk, s.dizin);             // katman 3: dizinleyici
    kuyruk -= dizin; d.dizinlenen += dizin;
    const gecikme = tampon / s.araciOkuma + kuyruk / s.dizin;
    d.enBuyukGecikme = Math.max(d.enBuyukGecikme, gecikme);
    if (gecikme > s.gorunurluk) d.gecGorunen += dizin;
  }
  return d;
};
```

Üç katmanın üç ayrı kırılma biçimi vardır ve ders için ayrımı yapan şey budur. Aracı ve kuyruk
**satır düşürür** — kayıt yok olur. Dizinleyici satır düşürmez, **geciktirir** — kayıt sonunda
gelir ama sorunun sorulduğu anda orada değildir. Kırpma ne düşürür ne geciktirir; satırı olduğu
yerde bırakıp **sonunu keser**.

#### İki Yükte Katman Katman Kayıp

```js
// katman.mjs — iki yukte katman katman kayip ve kaybin yanitsiz biraktigi soru.
import { TABAN, KARISIM, BAYT, IS_BAS, IS_BIT, IS_EK, SINIR, PENCERE, kostur } from "./akis.mjs";

const sy = (x) => Math.round(x).toLocaleString("tr-TR");
console.log(`gunluk akisi (kurgu, saniye saniye): ${PENCERE} sn, taban ${TABAN} satir/sn` +
  ` (${Object.entries(KARISIM).map(([t, p]) => `${t} %${p * 100}`).join(", ")})`);
console.log(`gecelik toplu is ${IS_BAS}-${IS_BIT} sn arasi +${IS_EK} satir/sn, tamami is-adimi`);
console.log(`sinirlar: araci okuma ${SINIR.araciOkuma}/sn tampon ${sy(SINIR.araciTampon)};` +
  ` kuyruk ${sy(SINIR.kuyruk)}; dizinleyici ${SINIR.dizin}/sn; kirpma ${SINIR.kirpma} bayt;` +
  ` gorunurluk esigi ${SINIR.gorunurluk} sn\n`);

console.log("yuk   uretilen   araci dusen  kuyruk dusen  kirpilan  en buyuk gecikme  gec gorunen  kayip %");
const sonuc = {};
for (const yuk of [1, 2]) {
  const d = kostur(yuk);
  const kirpilan = Object.entries(d.tur).reduce((t, [tur, n]) => t + (BAYT[tur] > SINIR.kirpma ? n : 0), 0);
  sonuc[yuk] = { ...d, kirpilan };
  console.log(`${`${yuk}x`.padEnd(6)}${sy(d.uretilen).padStart(9)}${sy(d.araciDusen).padStart(14)}` +
    `${sy(d.kuyrukDusen).padStart(14)}${sy(kirpilan).padStart(10)}` +
    `${`${d.enBuyukGecikme.toFixed(0)} sn`.padStart(18)}${sy(d.gecGorunen).padStart(13)}` +
    `${`%${(100 * d.araciDusen / d.uretilen).toFixed(1)}`.padStart(9)}`);
}

console.log("\nkaybin turu ve yanitsiz biraktigi soru");
console.log("kayip                     etkilenen satir                          yanitsiz kalan soru");
const iki = sonuc[2], SATIR = [
  ["araci tamponu doldu (2x)", `is-adimi ${sy(iki.dusenTur["is-adimi"])} satir` +
    ` (%${(100 * iki.dusenTur["is-adimi"] / iki.tur["is-adimi"]).toFixed(1)})`, "S5 S6"],
  ["kirpma (her iki yukte)", `hata satirlarinin son ${BAYT.hata - SINIR.kirpma} bayti (%100)`, "S10 S12"],
  ["dizinleme gecikmesi (2x)", `${sy(iki.gecGorunen)} satir ${SINIR.gorunurluk} sn'den gec gorundu`,
    "olay anindaki her soru"]];
for (const [a, b, c] of SATIR) console.log(`${a.padEnd(26)}${b.padEnd(40)}${c}`);

// soru kumesine karsi: [kimlik, satir turu, alan kirpilan kuyrukta mi, kabul edilen kayip payi]
const SORU_GUNLUK = [["S1", "istek", false, 0.10], ["S2", "istek", false, 0.10],
  ["S3", "istek", false, 0.10], ["S4", "istek", false, 0.10], ["S5", "is-adimi", false, 0.01],
  ["S6", "is-adimi", false, 0.01], ["S7", "istek", false, 0.10], ["S8", "istek", false, 0.10],
  ["S9", "is-adimi", false, 0.01], ["S10", "hata", true, 0.10]];
const mb = (b) => (b / 1024 ** 2).toFixed(0);
console.log("\nsoru kumesine karsi (S11 olcer degeri gunluge yazilmaz, S12 zincir capinda kimlik yok)");
console.log("yuk  saklanan MB  kaybolan MB  istek kayip  is-adimi kayip  yanitlanan  MB/soru  yanitsiz");
for (const yuk of [1, 2]) {
  const d = sonuc[yuk], kayip = (k) => d.dusenTur[k] / d.tur[k];
  const uret = Object.keys(BAYT).reduce((t, k) => t + d.tur[k] * BAYT[k], 0);
  const sakla = Object.keys(BAYT).reduce((t, k) =>
    t + (d.tur[k] - d.dusenTur[k]) * Math.min(BAYT[k], SINIR.kirpma), 0);
  const y = SORU_GUNLUK.filter(([, tur, kuyrukta, tol]) =>
    kayip(tur) <= tol && !(kuyrukta && BAYT[tur] > SINIR.kirpma));
  console.log(`${`${yuk}x`.padEnd(5)}${mb(sakla).padStart(11)}${mb(uret - sakla).padStart(13)}` +
    `${`%${(100 * kayip("istek")).toFixed(1)}`.padStart(13)}${`%${(100 * kayip("is-adimi")).toFixed(1)}`.padStart(16)}` +
    `${`${y.length}/12`.padStart(12)}${mb(sakla / y.length).padStart(9)}  ` +
    [...SORU_GUNLUK.filter((s) => !y.includes(s)).map(([k]) => k), "S11", "S12"].join(" "));
}
```

```
gunluk akisi (kurgu, saniye saniye): 3600 sn, taban 232 satir/sn (istek %86, hata %2, is-adimi %12)
gecelik toplu is 600-1200 sn arasi +900 satir/sn, tamami is-adimi
sinirlar: araci okuma 1400/sn tampon 30.000; kuyruk 300.000; dizinleyici 1000/sn; kirpma 512 bayt; gorunurluk esigi 60 sn

yuk   uretilen   araci dusen  kuyruk dusen  kirpilan  en buyuk gecikme  gec gorunen  kayip %
1x    1.375.200             0             0    16.704             79 sn      170.000     %0.0
2x    2.750.400       488.400             0    33.408            261 sn      895.000    %17.8

kaybin turu ve yanitsiz biraktigi soru
kayip                     etkilenen satir                          yanitsiz kalan soru
araci tamponu doldu (2x)  is-adimi 400.315 satir (%31.3)          S5 S6
kirpma (her iki yukte)    hata satirlarinin son 108 bayti (%100)  S10 S12
dizinleme gecikmesi (2x)  895.000 satir 60 sn'den gec gorundu     olay anindaki her soru

soru kumesine karsi (S11 olcer degeri gunluge yazilmaz, S12 zincir capinda kimlik yok)
yuk  saklanan MB  kaybolan MB  istek kayip  is-adimi kayip  yanitlanan  MB/soru  yanitsiz
1x           278            2         %0.0            %0.0        9/12       31  S10 S11 S12
2x           449          111         %6.0           %31.3        6/12       75  S5 S6 S9 S10 S11 S12
```

Tek kat yükte hiçbir satır düşmez. Aracı saniyede 1400 satır okuyabilir, tepe hız 1132'dir; kuyruk
üç yüz bin satırlık kapasitesinin yakınına bile gelmez. Ama hat yine de tam çalışmaz: dizinleyici
saniyede 1000 satır işler ve toplu iş penceresinde girdi bunun üstüne çıkar. Birikme kuyrukta
kalır, kayıp olmaz — yalnız **gecikir**. En büyük gecikme 79 saniyedir ve altmış saniyelik
görünürlük eşiğinin üstünde 170.000 satır dizinlenir. O satırlar kaybolmamıştır; yalnız
sorulduğu anda orada değildirler.

#### Kırpmanın Sessizliği

Kırpma her iki yükte de aynı şeyi yapar ve tabloda en küçük görünen sayıdır: tek kat yükte iki
megabayt. Ama etkilediği satır oranı yüzde yüzdür. Hata satırı 620 bayttır, kırpma sınırı 512;
her hata satırının son 108 baytı kesilir ve orada iki alan durur — hata kodu ile sürecin ürettiği
işlem kimliği.

Kaybın biçimi ayrıca önemlidir. Düşen satır kendini belli eder: sayaçlar tutmaz, satır aralığı
atlar. Kırpılan satır **belli etmez**. Depoda 16.704 hata satırı vardır, hepsi okunabilir,
hepsinin zaman damgası ve servis adı yerindedir. Yalnız hata kodu alanı boştur ve boş olmasının
nedeni hata kodunun yazılmamış olması değil, satırın kesilmiş olmasıdır. Bu iki durum sorgu
tarafında ayırt edilemez; ikisi de aynı boş hücreyi verir.

Bedeli S10'dur: hangi hata kodunun arttığı sorusu günlükten yanıtlanamaz. Bir önceki derste aynı
soru ölçütten yanıtlanmıştı — `sonuc` etiketi beş değerliydi ve hata oranı hesaplanabiliyordu. Ama
ölçütteki `sonuc` etiketi beş sınıfa ayırır; günlükteki hata kodu yüzlerce ayrı değer taşır ve
incelemeyi asıl daraltan odur.

#### Yük İki Katına Çıkınca

İkinci satır soruyu yanıtlar: **önce aracı kırılır.** Tepe hız 2264 satır/saniyeye çıkar, aracının
okuma hızı 1400'dür ve aradaki 864 satır/saniye tamponda birikir; otuz bin satırlık tampon otuz
beş saniyede dolar ve kalan beş yüz altmış beş saniye boyunca fazlalık düşer — 488.400 satır,
üretilenin yüzde 17,8'i.

Kuyruk hiç kırılmaz, çünkü aracı zaten fazlalığı geçirmemektedir. Bu, katmanlı bir hattın
karakteristik davranışıdır: **en dar katman ötekileri korur** ve koruduğu için ötekilerin
sınırları hiç sınanmaz. Kuyruk kapasitesini artırmak bu hatta tek bir satır kazandırmaz.

Düşen satırların dağılımı da rastlantı değildir. Tampon taştığı an toplu iş penceresidir ve o
pencerede girdinin yüzde seksen ikisi iş adımı satırıdır; düşen 488.400 satırın 400.315'i iş
adımıdır — bütün iş adımı satırlarının yüzde 31,3'ü. Gecelik işin kaç okuma işlediği ve neden geç
bittiği artık günlükten sorulamaz.

Ama kayıp orada durmaz. Tampon taşarken hangi satırın düşeceğini seçen bir kural yoktur; istek
satırlarının da yüzde altısı düşer. Toplu işle hiçbir ilgisi olmayan istek satırları, yalnız aynı
tampondan geçtikleri için eksilir. Bir katmanın taşması, taşmaya sebep olmayan soruları da
bozar — sayım soruları için yüzde altı zaten fazlasıyla yeter, oran soruları için sonuç yanlış
değil ama **eğridir** ve eğri olduğu görünmez.

Son tablo bu kursun kuralını en açık biçimde yazar. Yük iki katına çıktığında saklanan veri 278
megabayttan 449 megabayta çıkar — yüzde altmış bir artış. Yanıtlanan soru 9'dan 6'ya iner. Soru
başına maliyet 31 megabayttan 75 megabayta, **iki buçuk katına** çıkar. Daha çok veri toplandı,
daha az soru yanıtlandı; ikisi aynı olayın iki yüzüdür.

#### Hangi Sınır Değişirse Hangi Soru Geri Gelir

Kırılan katman bilindiğine göre soru şudur: tek bir sınırı büyütmek kaç soruyu geri getirir?

```js
// onlem.mjs — 2x yukte tek tek sinir degisiklikleri: hangi soru geri geliyor, kac megabayta.
import { BAYT, SINIR, kostur } from "./akis.mjs";

const SORU_GUNLUK = [["S1", "istek", false, 0.10], ["S2", "istek", false, 0.10],
  ["S3", "istek", false, 0.10], ["S4", "istek", false, 0.10], ["S5", "is-adimi", false, 0.01],
  ["S6", "is-adimi", false, 0.01], ["S7", "istek", false, 0.10], ["S8", "istek", false, 0.10],
  ["S9", "is-adimi", false, 0.01], ["S10", "hata", true, 0.10]];
const mb = (b) => (b / 1024 ** 2).toFixed(0), sy = (x) => Math.round(x).toLocaleString("tr-TR");
const DEGISIKLIK = [["degisiklik yok", {}],
  ["tampon 30 bin -> 300 bin", { araciTampon: 300000 }],
  ["araci okuma 1400 -> 2400", { araciOkuma: 2400 }],
  ["dizinleyici 1000 -> 2400", { dizin: 2400 }],
  ["kirpma 512 -> 1024 bayt", { kirpma: 1024 }],
  ["araci 2400 + dizinleyici 2400", { araciOkuma: 2400, dizin: 2400 }]];

console.log("2x yukte tek tek sinir degisikligi");
console.log("degisiklik                     araci dusen  kuyruk dusen  gecikme  saklanan MB  yanitlanan  MB/soru");
for (const [ad, yeni] of DEGISIKLIK) {
  const s = { ...SINIR, ...yeni }, d = kostur(2, s), kayip = (k) => d.dusenTur[k] / d.tur[k];
  const sakla = Object.keys(BAYT).reduce((t, k) =>
    t + (d.tur[k] - d.dusenTur[k]) * Math.min(BAYT[k], s.kirpma), 0);
  const y = SORU_GUNLUK.filter(([, tur, kuyrukta, tol]) =>
    kayip(tur) <= tol && !(kuyrukta && BAYT[tur] > s.kirpma));
  console.log(`${ad.padEnd(31)}${sy(d.araciDusen).padStart(11)}${sy(d.kuyrukDusen).padStart(14)}` +
    `${`${d.enBuyukGecikme.toFixed(0)} sn`.padStart(9)}${mb(sakla).padStart(13)}` +
    `${`${y.length}/12`.padStart(12)}${mb(sakla / y.length).padStart(9)}`);
}
```

```
2x yukte tek tek sinir degisikligi
degisiklik                     araci dusen  kuyruk dusen  gecikme  saklanan MB  yanitlanan  MB/soru
degisiklik yok                     488.400             0   261 sn          449        6/12       75
tampon 30 bin -> 300 bin           218.400        69.000   454 sn          495        6/12       83
araci okuma 1400 -> 2400                 0       459.400   299 sn          455        6/12       76
dizinleyici 1000 -> 2400           488.400             0    21 sn          449        6/12       75
kirpma 512 -> 1024 bayt            488.400             0   261 sn          452        7/12       65
araci 2400 + dizinleyici 2400            0             0     0 sn          556        9/12       62
```

Dört tek adımdan üçü hiçbir soruyu geri getirmez. Tamponu on katına çıkarmak aracıdaki kaybı
yarıya indirir ama kaybı **kuyruğa taşır** ve gecikmeyi 261 saniyeden 454 saniyeye çıkarır: tampon
kaybı önlemez, kaybı geciktirir ve gecikme de bir kayıptır. Aracının okuma hızını artırmak
aracıdaki kaybı sıfırlar, karşılığında kuyrukta 459.400 satır düşer — toplam kayıp neredeyse
aynıdır, yalnız katman değişmiştir. Dizinleyiciyi hızlandırmak tek başına hiçbir satır kurtarmaz;
yalnız gecikmeyi 261 saniyeden 21 saniyeye indirir, ki bu da gerçek bir kazançtır ama başka bir
kalemde.

Bir soruyu geri getiren tek ucuz adım kırpma sınırıdır: 512'den 1024 bayta çıkarmak üç megabayt
ek yer tutar ve S10'u geri getirir — soru başına maliyet 75 megabayttan 65'e iner. Öteki soruları
geri getiren tek yol iki sınırı **birlikte** değiştirmektir: kayıp sıfırlanır, gecikme sıfıra
iner, yanıtlanan soru 9/12'ye çıkar ve soru başına maliyet 62 megabayta düşer — altı satırın en
düşüğü. Hattın darboğazı tek bir katmanda değil, iki katmanın oranındadır.

#### Özet

- Üç katman üç ayrı biçimde bozulur: aracı ve kuyruk satır düşürür, dizinleyici geciktirir, kırpma
  satırı bırakıp sonunu keser.
- Tek kat yükte hiçbir satır düşmez ama dizinleme gecikmesi 79 saniyeye çıkar ve 170.000 satır
  60 saniyelik görünürlük eşiğinden geç görünür — kaybolmadan yanıtsız kalmış veri.
- Kırpma yükten bağımsızdır ve hata satırlarının yüzde yüzünde son 108 baytı siler; boş alan ile
  kesilmiş alan sorguda ayırt edilemez, S10 yanıtsız kalır.
- Yük iki katına çıkınca önce **aracı** kırılır: 488.400 satır düşer (%17,8), kuyruk hiç
  taşmaz — en dar katman ötekilerin sınırlarını hiç sınatmaz.
- Taşma seçici değildir: düşen satırların 400.315'i iş adımı (%31,3) ama istek satırlarının da
  %6'sı düşer; toplu işle ilgisi olmayan sorular da bozulur.
- Saklanan veri 278'den 449 MB'a çıkarken yanıtlanan soru 9/12'den 6/12'ye iner; soru başına
  maliyet 31 MB'dan 75 MB'a çıkar. Tek sınır büyütmenin dördü hiçbir soruyu geri getirmez; tampon
  kaybı kuyruğa taşır, aracı hızı kaybı katman değiştirir, çözüm iki sınırın oranındadır.

#### Sonraki Adım

Buraya kadar günlük satırı bir bütün olarak sayıldı: kaç satır üretildi, kaç satır düştü, kaç bayt
saklandı. Ama depoya ulaşan satır hâlâ **metindir** ve metin üzerinde yanıtlanabilecek soru
sayısı çok azdır — bir dizeyi arayabilir, kaç satırda geçtiğini sayabilirsin; hangi servisin hata
oranının hangi ortamda arttığını soramazsın. Bir sonraki ders gerçek günlük satırlarını ayrıştırır
ve aranabilir alanlara çevirir: yapılandırılmamış metinle kaç soru yanıtlanıyor, alanlar üretilince
kaç soru yanıtlanabilir hâle geliyor ve ayrıştırma kuralının sessizce kaçırdığı satırın bedeli ne.

### Günlük Ayrıştırma ve Yapılandırma

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/gunluk-ayristirma-ve-yapilandirma

Gerçek günlük satırları ayrıştırılıp aranabilir alanlara çevrilir ve iki depo biçimi soru kümesine karşı sayılır: yapılandırılmamış metin kaç soruyu yanıtlıyor, alanlar üretilince kaç soru açılıyor. Biçim değiştiğinde ayrıştırma kuralının sessizce kaçırdığı satır sayılır ve yanlış çıkan yanıtın bedeli yazılır.

Bir önceki ders satırı bir bütün olarak saydı: kaç satır üretildi, kaç satır düştü, kaç bayt
saklandı. Depoya ulaşan satır ise hâlâ **metindir**. Metin üzerinde bir dizeyi arayabilir ve kaç
satırda geçtiğini sayabilirsin; hangi bölgenin okumasının hangi ortamda doğrulamadan geçmediğini
soramazsın, çünkü bunun için satırın parçalara ayrılmış olması gerekir.

Bu ders o adımı ölçer. Gerçek satırlar bir ayrıştırma kuralından geçirilir, aranabilir alanlara
çevrilir ve iki depo biçimi — ham metin ile alanlar — aynı soru kümesine karşı sayılır. Üçüncü
ölçü kuralın **kaçırdığı satırdır**: bir servis biçim değiştirdiğinde alanlar sessizce boş kalır
ve sorgu hata vermeden yanlış yanıt döndürür.

Satırlar **bölgesel ölçüm ağının** gecelik doğrulama akışındandır ve **kurgudur**; her satırın
doğru karşılığı ayrıca tutulur ve ölçüm ona karşı yapılır.

**OG25.** Doğrulama akışının 900 satırı kendi üretecimizle üretilir, tohum `20260903`; her satırın
yapılandırılmış karşılığı ayrıca saklanır ve doğruluk ona göre denetlenir.
**OG26.** Doğrulayıcı servisi, satırların dörtte birlik noktasından sonra yeni bir sürüme geçer ve
alan adlarını değiştirir: `bolge` yerine `alan`, `sonuc` yerine `durum`, `sure=…ms` yerine
`sure_ms=…`.
**OG27.** Ayrıştırma kuralı eski biçime göre yazılmıştır ve sürüm geçişinden sonra değiştirilmez.
**OG28.** 07 bölgesinin düşen okumalarının çoğunu doğrulayıcı yazar; 13 bölgesinin düşenlerini
öteki servisler yazar.
**OG29.** Yapılandırılmamış metin yalnız önceden bilinen tek bir dizeyi sayabilir; gruplama ve
sayısal işlem alan gerektirir.
**OG30.** Bir alan, gruplama ya da sayısal soruda kullanılabilmesi için satırların en az yüzde
80'inde dolu olmalıdır.

#### Gerçek Günlük Satırları

```js
// satir.mjs — gercek gunluk satirlari uretilir; her satirin dogru karsiligi ayrica tutulur.
export const uretec = (t) => () => (t = (t * 1103515245 + 12345) % 2147483648) / 2147483648;
export const BOLGE = ["01", "03", "05", "07", "09", "11", "13", "15", "17", "19", "21"];
export const DUSME = { "07": [0.80, 0.10], "13": [0.12, 0.26] };
export const SERVIS = ["okuma-toplayici", "dogrulayici", "faturalama", "is-emri"];
const iki = (n) => String(n).padStart(2, "0");

// dogrulayici yeni surume gectikten sonra alan adlarini degistirir: bolge->alan, sonuc->durum
export const uret = (adet = 900, tohum = 20260903) => {
  const rast = uretec(tohum), satir = [], kayit = [];
  for (let i = 0; i < adet; i++) {
    const servis = SERVIS[Math.floor(rast() * SERVIS.length)];
    const yeniBicim = servis === "dogrulayici" && i > adet * 0.25;   // surum gecisi
    const b = BOLGE[Math.floor(rast() * BOLGE.length)];
    // dusme orani bolgeye gore: [dogrulayicida, oteki servislerde]
    const [dd, od] = DUSME[b] ?? [0.10, 0.07];
    const dustu = rast() < (servis === "dogrulayici" ? dd : od);
    const sure = 60 + Math.floor(rast() * 320), ornek = `u${iki(Math.floor(rast() * 29))}`;
    const zaman = `2026-08-02T02:${iki(Math.floor(i / 15))}:${iki(i % 60)}Z`;
    kayit.push({ servis, bolge: b, sonuc: dustu ? "dustu" : "gecti", sure, ornek, yeniBicim });
    satir.push(yeniBicim
      ? `${zaman} ortam=uretim servis=${servis} ornek=${ornek} duzey=info olay=okuma` +
        ` alan=${b} durum=${dustu ? "dustu" : "gecti"} sure_ms=${sure}`
      : `${zaman} uretim ${servis}[${ornek}] INFO okuma islendi bolge=${b}` +
        ` sonuc=${dustu ? "dustu" : "gecti"} sure=${sure}ms`);
  }
  return { satir, kayit };
};
```

İki biçim de aynı bilgiyi taşır; fark yalnız adlarındadır. Bir günlükleme sözleşmesi
değişikliğinin en sık görülen sonucu budur ve hiçbir servis için hata değildir — her iki satır da
geçerlidir.

#### Ayrıştırma ve Kaçırılan Satır

```js
// ayristir.mjs — yapilandirilmamis metin ile aranabilir alanlarin soru kumesine karsi karsilastirmasi.
import { uret, SERVIS } from "./satir.mjs";

const { satir, kayit } = uret();
console.log(`uretilen gunluk satiri: ${satir.length}`);
console.log("ornek satirlar");
for (const i of [0, 1, 227, 232]) console.log(`  ${satir[i]}`);

// eski bicime gore yazilmis ayristirma kurali
const KURAL = /^(\S+) (\w+) ([\w-]+)\[(\w+)\] (\w+) (.*?) bolge=(\d+) sonuc=(\w+) sure=(\d+)ms$/;
const alan = satir.map((s) => {
  const m = KURAL.exec(s);
  return m ? { zaman: m[1], ortam: m[2], servis: m[3], ornek: m[4], bolge: m[7], sonuc: m[8], sure: +m[9] }
    : { zaman: s.slice(0, 20).trim(), ortam: "", servis: "", ornek: "", bolge: "", sonuc: "", sure: null };
});
const eslesen = alan.filter((a) => a.bolge).length;
console.log(`\nayristirma kurali ${eslesen}/${satir.length} satiri esledi;` +
  ` ${satir.length - eslesen} satirda alanlar sessizce bos (%${(100 * (satir.length - eslesen) / satir.length).toFixed(1)})`);

// S7: hangi bolgenin okumasi dogrulanmadi
const say = (kaynak, bAl, sAl) => {
  const t = {};
  for (const k of kaynak) { const b = bAl(k); if (!b) continue; t[b] ??= [0, 0]; t[b][0]++; if (sAl(k) === "dustu") t[b][1]++; }
  return t;
};
const enKotu = (t) => Object.entries(t).sort((a, b) => b[1][1] - a[1][1])[0];
const gercek = say(kayit, (k) => k.bolge, (k) => k.sonuc), cikan = say(alan, (a) => a.bolge, (a) => a.sonuc);
const [gb, gv] = enKotu(gercek), [cb, cv] = enKotu(cikan);
console.log("\nS7 'hangi bolgenin okumasi dogrulanmadi'");
console.log(`  gercek        bolge ${gb}  ${gv[1]} dusen / ${gv[0]} okuma`);
console.log(`  ayristirmadan bolge ${cb}  ${cv[1]} dusen / ${cv[0]} okuma` +
  `   sapma %${(100 * Math.abs(cv[1] - gv[1]) / gv[1]).toFixed(1)}   yanit ayni mi: ${gb === cb ? "evet" : "hayir"}`);
console.log(`  kural bolge ${gb} icin ${gercek[gb][1] - (cikan[gb]?.[1] ?? 0)} dusen okumayi hic gormedi`);

// yapilandirilmamis metin yalniz bilinen tek bir dizeyi sayabilir
const DIZE = "okuma islendi", hamSay = satir.filter((x) => x.includes(DIZE)).length;
console.log(`\nS5 'gecelik is kac okuma isledi'`);
console.log(`  gercek ${kayit.length}   ham metinde "${DIZE}" gecen satir ${hamSay}` +
  `   sapma %${(100 * (kayit.length - hamSay) / kayit.length).toFixed(1)}`);

// S1: servis ortalamasi alanlardan dogru cikiyor mu
const ort = (l, s, f) => { const g = l.filter((x) => x.servis === s).map(f); return g.reduce((a, b) => a + b, 0) / g.length; };
const enYavas = (l, f) => SERVIS.map((s) => [s, ort(l, s, f)]).sort((a, b) => b[1] - a[1])[0];
const [gs, gd] = enYavas(kayit, (k) => k.sure), [as_, ad] = enYavas(alan.filter((a) => a.servis), (a) => a.sure);
console.log(`S1 'hangi servis yavasladi'   gercek ${gs} ${gd.toFixed(0)} ms` +
  `   ayristirmadan ${as_} ${ad.toFixed(0)} ms   yanit ayni mi: ${gs === as_ ? "evet" : "hayir"}`);

// bu akisin kapsamindaki alti soru; otekiler baska satir turlerinde durur
const SORU = [["S1", ["servis", "sure"], "sayisal", gs === as_], ["S2", ["sure"], "sayisal", true],
  ["S3", ["ortam", "sonuc"], "grupla", true], ["S5", ["dize"], "say", hamSay === kayit.length],
  ["S7", ["bolge", "sonuc"], "grupla", gb === cb], ["S8", ["ornek"], "grupla", true]];
const kapsama = (a) => alan.filter((x) => x[a] !== "" && x[a] !== null).length / alan.length;
const bayt = satir.reduce((t, x) => t + x.length, 0);
const alanBayt = alan.reduce((t, a) => t + Object.values(a).join("").length + Object.keys(a).length * 2, 0);
console.log("\ndepo bicimi        bayt   yanitlanabilen   dogru yanit   bayt/dogru soru   yanlis yanitlanan");
const yaz = (ad2, b, y) => {
  const d = y.filter(([, , , dogru]) => dogru);
  console.log(`${ad2.padEnd(18)}${b.toLocaleString("tr-TR").padStart(6)}${`${y.length}/6`.padStart(15)}` +
    `${`${d.length}/6`.padStart(14)}${(d.length ? Math.round(b / d.length).toLocaleString("tr-TR") : "-").padStart(18)}   ` +
    (y.filter((q) => !d.includes(q)).map(([k]) => k).join(" ") || "-"));
};
yaz("ham metin", bayt, SORU.filter(([, , i]) => i === "say"));
yaz("alanlar + dizin", bayt + alanBayt, SORU.filter(([, ger, , ]) =>
  ger.every((g) => g === "dize" || kapsama(g) >= 0.80)));
```

```
uretilen gunluk satiri: 900
ornek satirlar
  2026-08-02T02:00:00Z uretim dogrulayici[u02] INFO okuma islendi bolge=11 sonuc=gecti sure=210ms
  2026-08-02T02:00:01Z uretim okuma-toplayici[u21] INFO okuma islendi bolge=01 sonuc=gecti sure=217ms
  2026-08-02T02:15:47Z ortam=uretim servis=dogrulayici ornek=u21 duzey=info olay=okuma alan=05 durum=gecti sure_ms=250
  2026-08-02T02:15:52Z ortam=uretim servis=dogrulayici ornek=u08 duzey=info olay=okuma alan=11 durum=gecti sure_ms=83

ayristirma kurali 736/900 satiri esledi; 164 satirda alanlar sessizce bos (%18.2)

S7 'hangi bolgenin okumasi dogrulanmadi'
  gercek        bolge 07  29 dusen / 97 okuma
  ayristirmadan bolge 13  18 dusen / 51 okuma   sapma %37.9   yanit ayni mi: hayir
  kural bolge 07 icin 21 dusen okumayi hic gormedi

S5 'gecelik is kac okuma isledi'
  gercek 900   ham metinde "okuma islendi" gecen satir 736   sapma %18.2
S1 'hangi servis yavasladi'   gercek dogrulayici 225 ms   ayristirmadan dogrulayici 238 ms   yanit ayni mi: evet

depo bicimi        bayt   yanitlanabilen   dogru yanit   bayt/dogru soru   yanlis yanitlanan
ham metin         88.590            1/6           0/6                 -   S5
alanlar + dizin   140.932            6/6           4/6            35.233   S5 S7
```

Kural 900 satırın 736'sını eşler. Kalan 164 satır **reddedilmez**; ayrıştırma başarısız olduğunda
satır atılmaz, yalnız alanları boş kalır. Depoda 900 kayıt vardır, hepsi aranabilir, hepsinin
zaman damgası yerindedir. Yalnız 164'ünde bölge, sonuç, servis ve süre alanları boştur ve bu, bir
sorgunun sonucunda hiçbir işaret bırakmaz.

#### Sessizce Değişen Yanıt

S7 satırı bu dersin en pahalı sayısını taşır. Gerçekte en çok okuma düşen bölge **07**'dir: doksan
yedi okumanın yirmi dokuzu doğrulamadan geçmemiştir. Ayrıştırılmış alanlardan çıkan yanıt ise
**13**'tür. Sapma yalnız yüzde 37,9 değildir — **yanıt farklıdır**.

Nedeni birinci bölümdeki tasarımdadır. 07 bölgesinin düşen okumalarının çoğunu doğrulayıcı yazar;
doğrulayıcı yeni biçime geçmiştir; yeni biçim kurala uymaz. Kural, 07 bölgesi için yirmi bir düşen
okumayı **hiç görmemiştir**. 13 bölgesinin düşenlerini ise öteki servisler yazar, onlar eski
biçimdedir ve hepsi sayılır. Sonuç, saha ekibinin yanlış bölgeye gitmesidir: iş emirleri 13
bölgesi için açılır, 07 bölgesinin sayaçları okunmamış kalır ve fatura kesilmez.

Bu, ölçüt tarafında görülmeyen bir kayıp türüdür. Bir ölçüt eksikse seri kesilir ve kesinti
görülür. Bir alan boşsa **sorgu yine çalışır**; yalnız daha az satır üzerinde çalışır ve bunu
söylemez. Kaybın işareti kaybın kendisiyle birlikte kaybolur.

S5 satırı aynı olguyu daha basit biçimde gösterir. Gecelik işin kaç okuma işlediği sorusu ham
metinde `okuma islendi` dizesini saymakla yanıtlanabilir — bu, yapılandırılmamış metnin gerçekten
yanıtlayabildiği tek soru türüdür. Ama yeni biçim o dizeyi yazmaz; sayım 900 yerine 736 verir,
yüzde 18,2 eksik. Grep ile alınan sayı da, ayrıştırmadan alınan sayı da aynı nedenle aynı miktarda
yanlıştır.

S1 ise doğru yanıt verir: en yavaş servis her iki hesapta da doğrulayıcıdır. Ama değeri kayar —
gerçek ortalama 225, ayrıştırmadan çıkan 238 milisaniye. Aynı eksik veri bir soruda yanıtı
değiştirir, ötekinde yalnız sayıyı kaydırır. Hangisinin olacağı verinin dağılımına bağlıdır ve
sorgu yazarken bilinmez.

#### Metin, Alan ve Bedel

Son tablo iki depo biçimini yan yana koyar. Ham metin 88.590 bayttır ve altı sorudan **birini**
yanıtlayabilir — o da yanlış. Alanlar üretildiğinde bayt 140.932'ye çıkar, yüzde elli dokuz artış
ve **altı sorunun altısı** yanıtlanabilir hâle gelir. Artan şey satırlar değil, alan adları,
ayrılmış değerler ve arama dizinidir.

Ama tablonun asıl sütunu üçüncüsüdür: yanıtlanabilen altı sorunun yalnız **dördü doğru** yanıtlanır.
"Yanıtlanabilir" ile "doğru" arasındaki bu iki soruluk boşluk, bu dersin ölçtüğü şeydir. Doğru
yanıt başına maliyet 35.233 bayttır; altı sorunun altısı doğru olsaydı 23.489 bayt olurdu. Aradaki
fark, kuralın bakımsız kalmasının fiyatıdır ve bunu tetikleyecek bir uyarı yoktur — eşleşmeyen
satır oranı bir ölçüt olarak toplanmadıkça yüzde 18,2 hiçbir yerde görünmez.

#### Kuralı Onarmanın Beş Yolu

Beş ayrıştırma seçeneği aynı satır kümesine uygulanır; eşleşen satır, doğru yanıt ve bayt birlikte
ölçülür.

```js
// secenek.mjs — ayristirma seceneklerinin esledigi satir, dogru yanit ve bayt bedeli.
import { uret } from "./satir.mjs";

const { satir, kayit } = uret();
const ESKI = /^(\S+) (\w+) ([\w-]+)\[(\w+)\] \w+ .*? bolge=(\d+) sonuc=(\w+) sure=(\d+)ms$/;
const YENI = /^(\S+) ortam=(\w+) servis=([\w-]+) ornek=(\w+) .*? alan=(\d+) durum=(\w+) sure_ms=(\d+)$/;
const kv = (s) => Object.fromEntries([...s.matchAll(/(\w+)=(\S+)/g)].map((m) => [m[1], m[2]]));
const ESLEM = { alan: "bolge", durum: "sonuc", sure_ms: "sure" };
const duzelt = (o) => Object.fromEntries(Object.entries(o).map(([k, v]) => [ESLEM[k] ?? k, v]));
const bicimden = (m) => ({ ortam: m[2], servis: m[3], ornek: m[4], bolge: m[5], sonuc: m[6], sure: +m[7] });
const bos = { ortam: "", servis: "", ornek: "", bolge: "", sonuc: "", sure: null };

const SECENEK = [
  ["tek kural (eski bicim)", (s) => { const m = ESKI.exec(s); return m ? bicimden(m) : bos; }],
  ["iki kural (eski + yeni)", (s) => { const m = ESKI.exec(s) || YENI.exec(s); return m ? bicimden(m) : bos; }],
  ["anahtar-deger, eslemsiz", (s) => ({ ...bos, ...kv(s) })],
  ["anahtar-deger + alan eslemi", (s) => ({ ...bos, ...duzelt(kv(s)) })],
  ["kaynakta yapilandirilmis", null],                  // butun satirlar tek sozlesmeyle yazilir
];
const yapilandirilmis = kayit.map((k) => `zaman=2026-08-02T02:00:00Z ortam=uretim servis=${k.servis}` +
  ` ornek=${k.ornek} olay=okuma bolge=${k.bolge} sonuc=${k.sonuc} sure=${k.sure}`);
const enKotu = (l) => {
  const t = {};
  for (const a of l) { if (!a.bolge) continue; t[a.bolge] ??= [0, 0]; t[a.bolge][0]++; if (a.sonuc === "dustu") t[a.bolge][1]++; }
  return Object.entries(t).sort((a, b) => b[1][1] - a[1][1])[0];
};
const [gercekBolge] = enKotu(kayit), hamBayt = satir.reduce((t, x) => t + x.length, 0);

console.log("secenek                        eslesen  S7 yaniti  S7 dogru  S5 dogru   bayt   bayt/dogru soru");
for (const [ad, f] of SECENEK) {
  const kaynak = f ? satir : yapilandirilmis;
  const alan = f ? satir.map(f) : yapilandirilmis.map((s) => ({ ...bos, ...kv(s) }));
  const dolu = alan.filter((a) => a.bolge).length;
  const [b] = enKotu(alan), s7 = b === gercekBolge, s5 = dolu === kayit.length;
  const bayt = kaynak.reduce((t, x) => t + x.length, 0) +
    alan.reduce((t, a) => t + Object.values(a).join("").length + Object.keys(a).length * 2, 0);
  const dogru = 4 + (s7 ? 1 : 0) + (s5 ? 1 : 0);       // S1 S2 S3 S8 her secenekte dogru
  console.log(`${ad.padEnd(31)}${String(`${dolu}/900`).padStart(8)}${String(b).padStart(11)}` +
    `${(s7 ? "evet" : "hayir").padStart(10)}${(s5 ? "evet" : "hayir").padStart(10)}` +
    `${bayt.toLocaleString("tr-TR").padStart(8)}${Math.round(bayt / dogru).toLocaleString("tr-TR").padStart(18)}`);
}
console.log(`\nham metin ${hamBayt.toLocaleString("tr-TR")} bayt; gercek en kotu bolge ${gercekBolge}`);
```

```
secenek                        eslesen  S7 yaniti  S7 dogru  S5 dogru   bayt   bayt/dogru soru
tek kural (eski bicim)          736/900         13     hayir     hayir 121.132            30.283
iki kural (eski + yeni)         900/900         07      evet      evet 126.036            21.006
anahtar-deger, eslemsiz         736/900         13     hayir     hayir 116.154            29.039
anahtar-deger + alan eslemi     900/900         07      evet      evet 115.170            19.195
kaynakta yapilandirilmis        900/900         07      evet      evet 161.292            26.882

ham metin 88.590 bayt; gercek en kotu bolge 07
```

Üçüncü satır beklenmedik olanıdır. Anahtar-değer ayrıştırıcı her iki biçimi de okur ve hiçbir
satırı reddetmez; buna rağmen S7 yanıtı hâlâ 13'tür. Nedeni, ayrıştırmanın başarılı olması ile
alanın **doğru adla** çıkması arasındaki farktır: yeni biçim bölgeyi `alan` anahtarıyla yazar,
sorgu `bolge` alanını arar, ikisi eşleşmez. Biçimden bağımsız bir ayrıştırıcı biçim sorununu
çözer, **ad sorununu çözmez**.

Dördüncü satır en ucuz doğru seçenektir: aynı ayrıştırıcıya üç satırlık bir alan eşlemi eklenir ve
doğru yanıt başına maliyet 30.283 bayttan 19.195 bayta iner. İki kurallı seçenek de doğrudur ama
her yeni biçim bir kural daha ister; eşlem tablosu yalnız bir satır büyür.

Beşinci satır sorunu kaynağında çözer: bütün servisler tek bir sözleşmeyle yazar ve ayrıştırma
kuralı hiç gerekmez. Kırılmaz, bakım istemez — ve **en pahalısıdır**: her satırda alan adları
yinelendiği için bayt 115.170'ten 161.292'ye, yüzde kırk artar. Ayrıştırma bir bayt tasarrufudur
ve tasarrufun karşılığı bakım yüküdür; hangisinin ucuz olduğu satır hacmine ve biçim değişikliği
sıklığına bağlıdır.

#### Özet

- Ayrıştırma kuralı 900 satırın 736'sını eşler; kalan 164 satır atılmaz, yalnız alanları boş
  kalır (%18,2) ve bu hiçbir sorgu sonucunda işaret bırakmaz.
- Yapılandırılmamış metin altı sorudan yalnız birini yanıtlayabilir (bilinen tek bir dizeyi
  saymak); alanlar üretilince altısı da yanıtlanabilir hâle gelir, bayt %59 artar.
- Yanıtlanabilir olmak doğru olmak değildir: altı sorunun dördü doğru yanıtlanır. S7'de yanıt
  bölge 07 yerine bölge 13 çıkar — kural 07 için 21 düşen okumayı hiç görmemiştir.
- Aynı eksik veri S1'de yanıtı değiştirmez, yalnız değeri 225'ten 238 milisaniyeye kaydırır;
  hangi sorunun bozulacağı verinin dağılımına bağlıdır ve sorgu yazılırken bilinmez.
- Doğru yanıt başına maliyet 35.233 bayttır; kural bakımlı olsaydı 23.489 bayt olurdu. Eşleşmeyen
  satır oranı bir ölçüt olarak toplanmadıkça %18,2 hiçbir yerde görünmez.
- Biçimden bağımsız ayrıştırıcı biçim sorununu çözer, ad sorununu çözmez (hâlâ 736/900); alan
  eşlemi eklenince doğru yanıt başına 19.195 bayt olur. Kaynakta yapılandırılmış yazım kırılmaz
  ama %40 daha fazla bayt tutar.

#### Sonraki Adım

Buraya kadar ölçüt ve günlük ayrı ayrı toplandı, ayrıştırıldı ve soru kümesine karşı sayıldı. Ama
her ölçümde saklama süresi sabit tutuldu ve bedel tek bir ayrıntı düzeyi üzerinden hesaplandı.
Gerçek bir hat böyle işlemez: veri yaşlandıkça ayrıntısı azaltılır, seyreltilir, özetlenir ve
sonunda atılır. Bir sonraki ders bu basamakları tarar ve her basamakta yanıtlanabilen soru
sayısıyla baytı birlikte sayar: soru başına maliyet basamak basamak nereye gider, en ucuz basamak
hangi soruyu kaybeder.

### Saklama ve Maliyet

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/saklama-ve-maliyet

Üç saklama basamağı taranır ve her basamakta yanıtlanabilen soru sayısı ile bayt birlikte sayılır: soru başına maliyet basamak basamak çıkarılır, bir basamağın marjinal bedeli bin katı fark eder ve en ucuz basamağın hangi soruları hangi nedenle kaybettiği adıyla yazılır.

Buraya kadarki beş ölçümde saklama süresi hep sabit tutuldu. Ölçüt hattı otuz gün, günlük hattı
bir saat üzerinden fiyatlandı ve her ders tek bir ayrıntı düzeyinde ölçüldü. Gerçek bir hat böyle
işlemez: veri yaşlandıkça çözünürlüğü düşürülür, etiketleri seyreltilir, satırları atılır ve
sonunda özete iner.

Bu ders o basamakları tarar. Ölçü değişmez — her basamakta **yanıtlanabilen soru sayısı** ile
**bayt** birlikte sayılır ve soru başına maliyet basamak basamak çıkarılır. Sonunda iki sayı yan
yana durur: bir basamağı eklemenin marjinal bedeli ve o basamağın kapattığı sorunun adı.

Sayılar **bölgesel ölçüm ağının** hattındandır ve **kurgudur**; ölçülen şey `node` ile kurulmuş
bir **modeldir** ve girdileri bu konunun önceki derslerinden gelir.

**OG31.** Üç basamağın yaş aralığı, çözünürlüğü, düşürdüğü etiketler ve tuttuğu günlük satır
türleri kurgudur ve önceden yazılıdır.
**OG32.** Ölçüt seri sayısı ikinci dersin gerçekleşen kümesinden alınır: 6.888 seri. Özet
basamağında `ornek` etiketi servis düzeyine toplanır, `dilim` etiketi tümüyle düşürülür.
**OG33.** Günlük hacmi dördüncü dersin akışından türer: taban 232 satır/saniye, gecelik iş 540.000
satır; hata satırı kırpma sınırındaki 512 bayttır.
**OG34.** Her sorunun ufku ikinci dersten, çözünürlük gereksinimi üçüncü dersten, gereken günlük
satır türü dördüncü ve beşinci derslerden gelir.
**OG35.** Bir basamak bir soruyu yanıtlar sayılır: yaş aralığı sorunun ufkunu kapsıyorsa,
çözünürlüğü yeterliyse, gereken etiketi düşürmemişse ve gereken satır türünü tutuyorsa.
**OG36.** S12 hiçbir basamakta yanıtlanmaz; gerektirdiği veri hiçbir basamağın içeriğinde yoktur.

#### Üç Basamak ve Ayrım Ölçütleri

```js
// basamak.mjs — saklama basamaklari, her basamakta yanitlanan soru ve soru basina maliyet.
export const OLCUT = {              // olcut: [ornek tabani, servis tabani, oteki etiket carpani, dilim]
  "istek-sayisi": [29, 4, 4 * 5, 1], "istek-suresi": [29, 4, 4, 12], "kuyruk-boyu": [29, 4, 4 * 3, 1],
  "islenen-okuma": [20, 2, 4 * 11 * 5, 1], "is-adimi-suresi": [6, 3, 4 * 6, 1], "is-islenen-kayit": [6, 3, 4, 1],
};
export const seri = (ozet) => Object.values(OLCUT).reduce((t, [a, b, c, d]) =>
  t + (ozet ? b : a) * c * (ozet ? 1 : d), 0);       // ozette ornek servise, dilim tumuyle dusurulur

export const GUNLUK_SATIR = { istek: 232 * 0.86 * 86400, hata: 232 * 0.02 * 86400,
  "is-adimi": 232 * 0.12 * 86400 + 540000 };         // gunde satir; gecelik is 540.000 satir
export const SATIR_BAYT = { istek: 180, hata: 512, "is-adimi": 240 };

// basamak: [ad, bas gun, bit gun, cozunurluk sn, ozet mi, tuttugu gunluk satir turleri]
export const BASAMAK = [["ham", 0, 7, 15, false, ["istek", "hata", "is-adimi"]],
  ["seyreltilmis", 7, 90, 300, false, ["hata", "is-adimi"]],
  ["ozet", 90, 395, 3600, true, []]];

// soru: [kimlik, ufuk gun, gereken cozunurluk sn, gereken etiketler, gereken satir turu]
export const SORU = [["S1", 1, 300, ["servis"], null], ["S2", 1, 15, ["dilim"], null],
  ["S3", 1, 3600, ["ortam", "sonuc"], null], ["S4", 30, 3600, ["surum"], null],
  ["S5", 7, null, [], "is-adimi"], ["S6", 7, null, [], "is-adimi"],
  ["S7", 365, 3600, ["bolge", "sonuc"], null], ["S8", 7, 300, ["ornek"], null],
  ["S9", 7, 300, ["ornek"], "is-adimi"], ["S10", 1, null, [], "hata"],
  ["S11", 1, 300, ["kuyruk"], null], ["S12", 1, null, [], "izleme"]];

export const DUSEN = ["ornek", "dilim"];             // ozet basamaginda dusurulen etiketler
export const uygun = (b, s, yasSay = true) => {      // basamak soruyu yanitliyor mu
  const [, bas, bit, coz, ozet, turler] = b, [, ufuk, gerCoz, gerEt, gerTur] = s;
  if (yasSay && !(bas <= ufuk && ufuk <= bit)) return false;
  if (gerCoz !== null && coz > gerCoz) return false;
  if (ozet && gerEt.some((e) => DUSEN.includes(e))) return false;
  return gerTur === null || turler.includes(gerTur);
};
export const gb = (b) => (b / 1024 ** 3).toFixed(2);
```

Bir basamağı tanımlayan dört ölçüt vardır ve dördü de bir soruyu kapatabilir: **yaş aralığı**
(sorunun ufkunu kapsıyor mu), **çözünürlük** (üçüncü dersteki sorgu penceresi ölçümü), **düşürülen
etiket** (ikinci dersteki etiket merdiveni) ve **tutulan satır türü** (dördüncü dersteki katman
kaybı). Basamak tasarımı bu dört kaleme aynı anda karar vermektir.

#### Basamak Basamak Bayt ve Soru

```js
// maliyet.mjs — basamak basamak bayt, yanitlanan soru ve soru basina maliyet.
import { OLCUT, seri, GUNLUK_SATIR, SATIR_BAYT, BASAMAK, SORU, DUSEN, uygun, gb } from "./basamak.mjs";

const olcutBayt = (b) => {
  const [, bas, bit, coz, ozet] = b;
  return seri(ozet) * Math.floor(86400 / coz) * (bit - bas) * 16 + seri(ozet) * 120;
};
const gunlukBayt = (b) => (b[2] - b[1]) * b[5].reduce((t, tur) => t + GUNLUK_SATIR[tur] * SATIR_BAYT[tur], 0);

console.log(`olcut serisi: ham/seyreltilmis ${seri(false).toLocaleString("tr-TR")},` +
  ` ozet ${seri(true).toLocaleString("tr-TR")} (dusurulen etiket: ${DUSEN.join(", ")})`);
console.log("\nbasamak       gun      cozunurluk  olcut GB  gunluk GB  toplam GB  yas araliginda  ayrinti duzeyi  GB/soru");
const satirlar = [];
for (const b of BASAMAK) {
  const o = olcutBayt(b), g = gunlukBayt(b), t = o + g;
  const yas = SORU.filter((s) => uygun(b, s)), ayr = SORU.filter((s) => uygun(b, s, false));
  satirlar.push([b, t, yas, ayr]);
  console.log(`${b[0].padEnd(14)}${`${b[1]}-${b[2]}`.padEnd(9)}${`${b[3]} sn`.padStart(10)}` +
    `${gb(o).padStart(10)}${gb(g).padStart(11)}${gb(t).padStart(11)}${`${yas.length}/12`.padStart(16)}` +
    `${`${ayr.length}/12`.padStart(16)}${gb(t / (yas.length || 1)).padStart(9)}`);
}

console.log("\nbirikimli (basamaklar ust uste konunca)");
console.log("basamaklar                toplam GB   yanitlanan   GB/soru   marjinal GB/yeni soru   yeni acilan");
let toplam = 0, once = [];
for (let i = 0; i < satirlar.length; i++) {
  const ekle = satirlar[i][1], ad = BASAMAK.slice(0, i + 1).map((b) => b[0]).join(" + ");
  toplam += ekle;
  const y = [...new Set(satirlar.slice(0, i + 1).flatMap(([, , yas]) => yas))];
  const yeni = y.filter((s) => !once.includes(s));
  console.log(`${ad.padEnd(26)}${gb(toplam).padStart(9)}${`${y.length}/12`.padStart(13)}` +
    `${gb(toplam / y.length).padStart(10)}${(yeni.length ? gb(ekle / yeni.length) : "-").padStart(24)}   ` +
    (yeni.map(([k]) => k).join(" ") || "-"));
  once = y;
}

const ucuz = satirlar[satirlar.length - 1];
const kayip = SORU.filter((s) => !ucuz[3].includes(s) && s[0] !== "S12");
console.log(`\nen ucuz basamak: ${ucuz[0][0]}, ${gb(ucuz[1])} GB, ayrinti duzeyiyle ${ucuz[3].length}/12 soru` +
  `, soru basina ${gb(ucuz[1] / ucuz[3].length)} GB`);
console.log("kaybettigi sorular ve nedeni");
for (const s of kayip) {
  const neden = [ucuz[0][3] > (s[2] ?? Infinity) && `cozunurluk ${ucuz[0][3]} sn`,
    s[3].some((e) => DUSEN.includes(e)) && `${s[3].filter((e) => DUSEN.includes(e)).join("/")} etiketi dusuruldu`,
    s[4] && !ucuz[0][5].includes(s[4]) && `${s[4]} satirlari tutulmuyor`].filter(Boolean);
  console.log(`  ${s[0].padEnd(4)} ${neden.join("; ")}`);
}
```

```
olcut serisi: ham/seyreltilmis 6.888, ozet 668 (dusurulen etiket: ornek, dilim)

basamak       gun      cozunurluk  olcut GB  gunluk GB  toplam GB  yas araliginda  ayrinti duzeyi  GB/soru
ham           0-7           15 sn      4.14      26.18      30.31            9/12           11/12     3.37
seyreltilmis  7-90         300 sn      2.45      70.51      72.96            5/12           10/12    14.59
ozet          90-395      3600 sn      0.07       0.00       0.07            1/12            3/12     0.07

birikimli (basamaklar ust uste konunca)
basamaklar                toplam GB   yanitlanan   GB/soru   marjinal GB/yeni soru   yeni acilan
ham                           30.31         9/12      3.37                    3.37   S1 S2 S3 S5 S6 S8 S9 S10 S11
ham + seyreltilmis           103.28        10/12     10.33                   72.96   S4
ham + seyreltilmis + ozet    103.35        11/12      9.40                    0.07   S7

en ucuz basamak: ozet, 0.07 GB, ayrinti duzeyiyle 3/12 soru, soru basina 0.02 GB
kaybettigi sorular ve nedeni
  S1   cozunurluk 3600 sn
  S2   cozunurluk 3600 sn; dilim etiketi dusuruldu
  S5   is-adimi satirlari tutulmuyor
  S6   is-adimi satirlari tutulmuyor
  S8   cozunurluk 3600 sn; ornek etiketi dusuruldu
  S9   cozunurluk 3600 sn; ornek etiketi dusuruldu; is-adimi satirlari tutulmuyor
  S10  hata satirlari tutulmuyor
  S11  cozunurluk 3600 sn
```

İki sütun ayrı şeyleri ölçer ve ayrımı görmek bu tablonun anahtarıdır. **Yaş aralığında**
sütunu, o basamağın kapsadığı yaş penceresine ufku düşen soruları sayar; **ayrıntı düzeyi**
sütunu, yaş hiç gözetilmeseydi o basamağın ayrıntısıyla kaç sorunun yanıtlanabileceğini. Ham
basamak ayrıntı düzeyiyle on bir soruyu taşır ama yalnız dokuzunu yanıtlar, çünkü sürüm
karşılaştırması ile mevsimsel bölge karşılaştırmasının ufku yedi günün dışındadır. Ayrıntıyı
tutmak yetmez; ayrıntının yeterince eski veriyle birlikte durması gerekir.

Bayt dağılımı da beklenenden farklıdır. Ham basamağın 30,31 gigabaytının 26,18'i günlüktür, ölçüt
yalnız 4,14. Seyreltilmiş basamakta istek satırları atılmasına rağmen günlük hâlâ 70,51 gigabayt
tutar — çünkü seksen üç günlük bir pencerede hata ve iş adımı satırları da birikir. Özet basamak
her iki tarafta da neredeyse bedavadır: üç yüz beş günlük saklama 0,07 gigabayta iner.

#### Marjinal Maliyetin Tersine Dönmesi

Birikimli tablo kararı taşıyan sayıyı verir. Ham basamak dokuz soruyu 30,31 gigabayta açar — soru
başına 3,37. Seyreltilmiş basamak eklendiğinde toplam 103,28 gigabayta çıkar ve yanıtlanan soru
dokuzdan **ona** çıkar: yetmiş üç gigabayt, tek bir soru. Marjinal maliyet 72,96 gigabayt/sorudur,
ham basamağın yirmi bir katı.

Özet basamak eklendiğinde toplam 103,35 gigabayt olur ve yanıtlanan soru on birdir. Marjinal
maliyet **0,07 gigabayt/sorudur** — seyreltilmiş basamağın bin katı ucuz. Aradaki oran bu dersin
en keskin sayısıdır: iki basamak da tam olarak bir soru açar ve biri ötekinden bin kat pahalıdır.

Farkın nedeni basamağın uzunluğu değil, **ne tuttuğudur**. Seyreltilmiş basamak seksen üç gün
boyunca günlük satırı ve tam etiketli seriyi tutar; açtığı tek soru ise yalnız `surum` etiketiyle
saatlik çözünürlük ister. Yani otuz günlük sürüm karşılaştırması için tutulan verinin neredeyse
tamamı o soru tarafından kullanılmaz. Aynı soru, özet basamağın ayrıntı düzeyiyle de
yanıtlanabilirdi.

Bu, basamak tasarımının asıl kararını gösterir: seyreltilmiş basamağın çözünürlüğünü ve satır
seçimini soruların gerektirdiği en düşük düzeye indirmek, tek bir sorunun bedelini yetmiş üç
gigabayttan gigabayt mertebesine düşürür. Basamağın süresini kısaltmak ise S4'ü tümüyle kapatır ve
hiçbir şey kazandırmaz.

#### En Ucuz Basamağın Kaybettiği Sorular

Özet basamak ayrıntı düzeyiyle üç soruyu 0,07 gigabayta yanıtlar — soru başına 0,02 gigabayt, bütün
hattın en ucuz sayısı. Yalnız bu sayıya bakan bir karar her şeyi özete indirirdi. Kaybedilenler
listede adıyla durur ve her birinin nedeni ayrı bir tasarım kalemidir.

Çözünürlük 3600 saniyeye çıktığı için **S1** (hangi servis yavaşladı), **S11** (iş emri kuyruğu
neden birikti) ve kısmen **S8** düşer; üçüncü derste ölçülmüştü, bir saatlik pencerede doksan
saniyelik bir bozulma ne ortalamada ne yüzdelikte görünür. `dilim` etiketi düşürüldüğü için **S2**
düşer: dağılım kovası olmadan üst dilim hesaplanamaz. `ornek` etiketi servise toplandığı için
**S8** ve **S9** düşer — hangi örneğin yeniden başladığı ve hangi koşumun yavaş olduğu artık
sorulamaz. Günlük satırları hiç tutulmadığı için **S5**, **S6** ve **S10** düşer.

Sekiz sorunun sekizi de sessizce kapanır. Özet basamakta bu sorgular hata vermez; boş sonuç ya da
tek bir toplam değer döner. Beşinci dersteki kırpma bulgusuyla aynı biçimdir: kaybın işareti,
kaybın kendisiyle birlikte kaybolur.

#### Basamak Düzenleri Yan Yana

Basamakların tek tek bedeli bilindiğine göre düzenin kendisi karşılaştırılabilir: aynı on iki
soruluk küme hangi düzende kaç gigabayta yanıtlanıyor?

```js
// politika.mjs — basamak duzenleri karsilastirilir: ayni soru kumesi kac gigabayta yanitlaniyor.
import { seri, GUNLUK_SATIR, SATIR_BAYT, BASAMAK, SORU, uygun, gb } from "./basamak.mjs";

const bicim = (ad, bas, bit) => {                    // bir basamagi baska yas araligina tasi
  const b = BASAMAK.find((x) => x[0] === ad);
  return [ad, bas, bit, b[3], b[4], b[5]];
};
const bayt = (b) => seri(b[4]) * Math.floor(86400 / b[3]) * (b[2] - b[1]) * 16 + seri(b[4]) * 120 +
  (b[2] - b[1]) * b[5].reduce((t, tur) => t + GUNLUK_SATIR[tur] * SATIR_BAYT[tur], 0);

const POLITIKA = [
  ["yalniz ham, 7 gun", [bicim("ham", 0, 7)]],
  ["yalniz ham, 30 gun", [bicim("ham", 0, 30)]],
  ["yalniz ham, 395 gun", [bicim("ham", 0, 395)]],
  ["uc basamak 7 / 90 / 395", [bicim("ham", 0, 7), bicim("seyreltilmis", 7, 90), bicim("ozet", 90, 395)]],
  ["ham 7 + ozet 395 (orta yok)", [bicim("ham", 0, 7), bicim("ozet", 7, 395)]],
  ["ham 30 + ozet 395", [bicim("ham", 0, 30), bicim("ozet", 30, 395)]],
];
console.log("politika                       toplam GB   yanitlanan   GB/soru   yanitsiz kalan");
const olc = POLITIKA.map(([ad, bs]) => {
  const t = bs.reduce((s, b) => s + bayt(b), 0);
  const y = SORU.filter((s) => bs.some((b) => uygun(b, s)));
  console.log(`${ad.padEnd(31)}${gb(t).padStart(9)}${`${y.length}/12`.padStart(13)}${gb(t / y.length).padStart(10)}   ` +
    SORU.filter((s) => !y.includes(s)).map(([k]) => k).join(" "));
  return [ad, t, y.length];
});
const [, ucT, ucY] = olc[3], [, ortasiz, ortasizY] = olc[4];
console.log(`\norta basamagin katkisi: ${gb(ucT - ortasiz)} GB fazla, ${ucY - ortasizY} yeni soru`);
console.log(`her seyi ham tutmanin bedeli: ${gb(olc[2][1] - ortasiz)} GB fazla,` +
  ` ${olc[2][2] - ortasizY} yeni soru`);
```

```
politika                       toplam GB   yanitlanan   GB/soru   yanitsiz kalan
yalniz ham, 7 gun                  30.31         9/12      3.37   S4 S7 S12
yalniz ham, 30 gun                129.92        10/12     12.99   S7 S12
yalniz ham, 395 gun              1710.56        11/12    155.51   S12
uc basamak 7 / 90 / 395           103.35        11/12      9.40   S12
ham 7 + ozet 395 (orta yok)        30.41        11/12      2.76   S12
ham 30 + ozet 395                 130.00        11/12     11.82   S12

orta basamagin katkisi: 72.94 GB fazla, 0 yeni soru
her seyi ham tutmanin bedeli: 1680.16 GB fazla, 0 yeni soru
```

Dört düzen aynı on bir soruyu yanıtlar ve aralarında elli altı kat fiyat farkı vardır. En ucuzu
orta basamağı **hiç kurmayan** düzendir: yedi günlük ham, sonrasında doğrudan özet. Toplam 30,41
gigabayt, soru başına 2,76.

Üç basamaklı düzenin orta katmanı 72,94 gigabayt fazla tutar ve **sıfır yeni soru** açar. Nedeni
dördüncü bölümde görülmüştü: seyreltilmiş basamağın tek katkısı S4'tü ve S4, `surum` etiketiyle
saatlik çözünürlük istediği için özet basamağın ayrıntısıyla da yanıtlanır. Orta basamak yalnız
"yedi gün az, doksan gün iyi olur" sezgisiyle kurulmuştur; soru kümesine karşı sayıldığında
karşılığı yoktur.

"Her şeyi ham tut" düzeni aynı on bir soruyu 1710,56 gigabayta yanıtlar — 1680 gigabayt fazla,
sıfır yeni soru. Soru başına maliyeti 155,51 gigabayttır, en ucuz düzenin elli altı katı. Bu iki
satır bu kursun kuralını sayıya bağlar: hiçbir soruyu yanıtlamayan veri, ne kadar özenle
toplanırsa toplansın, maliyettir.

#### Özet

- Bir basamağı dört kalem tanımlar ve dördü de soru kapatabilir: yaş aralığı, çözünürlük,
  düşürülen etiket ve tutulan satır türü.
- Ham basamak ayrıntı düzeyiyle 11/12 soruyu taşır ama yaş aralığı yüzünden 9/12'sini yanıtlar;
  ayrıntıyı tutmak yetmez, yeterince eski veriyle birlikte durması gerekir.
- Bayt günlük tarafında toplanır: ham basamağın 30,31 GB'ının 26,18'i günlük, 4,14'ü ölçüt;
  seyreltilmiş basamakta istek satırları atılmasına rağmen günlük 70,51 GB tutar.
- Marjinal maliyet tersine döner: seyreltilmiş basamak bir soruyu (S4) 72,96 GB'a açar, özet
  basamak bir soruyu (S7) 0,07 GB'a — bin kat fark, ikisi de tam bir soru.
- En ucuz basamak (özet) 3/12 soruyu 0,02 GB/soruya yanıtlar ve sekiz soruyu adıyla, sessizce
  kaybeder: çözünürlükten S1, S11; `dilim` etiketinden S2; `ornek` etiketinden S8, S9; günlük
  satırlarından S5, S6, S10. Sorgular hata vermez, boş ya da tek toplam değer döner.
- Düzen karşılaştırmasında dört farklı düzen aynı 11/12'yi yanıtlar: en ucuzu orta basamağı hiç
  kurmayandır (30,41 GB, 2,76 GB/soru). Orta basamak 72,94 GB fazla tutup sıfır soru açar; "her
  şeyi ham tut" 1680 GB fazla tutup sıfır soru açar.

#### Sonraki Adım

Bu konu veriyi uçtan uca ele aldı: nasıl toplandığı, hangi etiketlerle saklandığı, hangi
toplulaştırmayla sorulduğu, günlük hattının hangi katmanında ne kaybettiği, metnin nasıl aranabilir
alana çevrildiği ve yaşlandıkça hangi basamakta ne kadara mal olduğu. On iki sorunun on biri bir
yerde yanıtlanır hâle geldi ve her yanıtın fiyatı bilinir.

Geriye tek bir soru kaldı ve hiçbir basamakta, hiçbir etiket kümesinde, hiçbir günlük satırında
görünmedi: bir faturanın hangi okumadan üretildiği. Bunu sormak, tek bir işlemin okuma
toplayıcıdan doğrulayıcıya, oradan faturalamaya ve iş emrine giden **yolunu** istemektir. Ölçüt
onu taşıyamaz, çünkü işlem kimliğinin kardinalitesi sınırsızdır; günlük satırı taşıyamaz, çünkü
her servis kendi kimliğini üretir ve satırlar birbirine bağlanamaz. Toplanan yüz gigabaytın hiçbir
baytı o yolu göstermez. Sonraki konu bu boşluktan başlar: bir isteğin servisler arasındaki yolunu
görünür kılmak neyi gerektirir ve hangi soruları açar.

## İzleme ve Gösterge

Toplanan verinin soruya bağlanması: dağıtık izlemenin toplayıcı ve depolama bileşenleri, ortak telemetri sözleşmesinin ne kazandırdığı, soruya yanıt veren gösterge tablosu tasarımı, eşik, oran ve anomali temelli uyarı kuralları, gürültü azaltma ve önceliklendirmeyle uyarı yorgunluğunun ölçülmesi ve dışarıdan periyodik doğrulama yapan sentetik izleme.

### Dağıtık İzleme Altyapısı

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/dagitik-izleme-altyapisi

Bir isteğin beş servis arasında izlediği yolun iz ağacı olarak kurulması: on bir işletim sorusunun ölçüt, günlük ve iz görünümlerine ayrı ayrı sorulması, adım başına baytın ölçülmesi ve örnekleme oranının kaçırdığı yavaş isteğin sayılması.

Ölçüt toplandı, günlük saklandı, ikisinin de bedeli çıkarıldı. Gecikme eğrisinin yükseldiği de
görülüyor. Görülmeyen şey, eğrinin arkasındaki **tek bir isteğin** beş servis arasında izlediği
yol: hangi adımda beklendi, hangi çağrı yeniden denendi, hangi servis hiç çağrılmadı. Bu üç soru ne
ölçüt kovalarında ne günlük satırlarında karşılık bulur; ikisi de isteği değil olayı sayar.

Dağıtık izlemenin üç parçası vardır. **Adım kaydı** bir iş parçasının kaydıdır: kendi kimliği, üst
adımın kimliği, servis adı, başlangıç, süre. **Bağlam taşıma** isteğin kimliğini çağrıdan çağrıya
geçirir; taşınmazsa ağaç beş parçaya bölünür. **Toplayıcı** adım kayıtlarını iz deposuna yazar,
depo kayıtları iz kimliğine göre gruplar: zaman serisi deposu zamana göre, iz deposu **kimliğe
göre** dizinlenir; ölçüt kaydı dakikada bir, iz kaydı her adımda bir yazılır.

#### Bir İsteğin Ağacı

Model bölgesel ölçüm ağının bir saatlik trafiğini üretir; üreteç kodda yazılıdır, ölçüm
değil kurgudur.

```js
// iz/model.mjs — bolgesel olcum aginin (kurgu) bir saatlik trafik MODELI. Her istek bes servisten
// gecer; her adim bir kayittir: kimlik, ust kimlik, servis, baslangic, sure, hata, deneme.
// IG1: cagri grafigi sabit — gecit okuma ile faturayi, okuma dogrulamayi, fatura isemrini cagirir.
// IG2: adimin kendi suresi taban + gurultu, hata orani binde. IG3: isteklerin bir kisminda okuma
// kendi onbelleginden yanitlar ve dogrulama hic cagrilmaz. IG4: isemri cagrisinin bir kismi zaman
// asimina duser, bir kez yeniden denenir. IG5: bazi istekler yavastir, yavaslik tek adimda toplanir.
export const TOHUM = 20260802, ISTEK = 24000, DK = 60;
export const SERVIS = ["gecit", "okuma", "dogrulama", "fatura", "isemri"];
export const PROFIL = { gecit: [4, 2, 0], okuma: [18, 6, 2], dogrulama: [26, 9, 3],
  fatura: [31, 11, 4], isemri: [44, 15, 9] };
export const ATLAMA = 0.11, DENEME = 0.06, YAVAS = 0.02, ZAMAN_ASIMI = 120;

export function uret() {
  let s = TOHUM;
  const r = () => ((s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32);
  const gur = (ad) => { const [t, g] = PROFIL[ad]; return Math.max(1, Math.round(t + (r() * 2 - 1) * g)); };
  const izler = [];
  for (let i = 0; i < ISTEK; i += 1) {
    const t0 = Math.floor(r() * DK * 60000), adimlar = [];
    let no = 0;
    const ekle = (ust, servis, bas, sure, hata, deneme) =>
      (adimlar.push({ id: (no += 1), ust, servis, bas, sure, hata, deneme }), no);
    const yavasAdim = r() < YAVAS ? (r() < 0.6 ? "isemri" : SERVIS[1 + Math.floor(r() * 4)]) : null;
    const kat = yavasAdim ? 8 + Math.floor(r() * 13) : 1;
    const uzat = (ad, d) => (ad === yavasAdim ? d * kat : d);
    const atlandi = r() < ATLAMA, dogSure = atlandi ? 0 : uzat("dogrulama", gur("dogrulama"));
    const okumaKendi = uzat("okuma", gur("okuma"));
    const okumaSure = okumaKendi + (atlandi ? 0 : dogSure + 2);
    const yenidenDendi = r() < DENEME, isemriSure = uzat("isemri", gur("isemri"));
    const isemriToplam = isemriSure + (yenidenDendi ? ZAMAN_ASIMI + 2 : 0);
    const faturaSure = uzat("fatura", gur("fatura")) + isemriToplam + 2;
    const faturaBas = PROFIL.gecit[0] + okumaSure + 2;
    const kok = ekle(0, "gecit", 0, faturaBas + faturaSure, false, 1);
    const okuma = ekle(kok, "okuma", PROFIL.gecit[0], okumaSure, false, 1);
    if (!atlandi) ekle(okuma, "dogrulama", PROFIL.gecit[0] + okumaKendi + 1, dogSure, false, 1);
    const fatura = ekle(kok, "fatura", faturaBas, faturaSure, false, 1);
    let ib = faturaBas + 2;
    if (yenidenDendi) { ekle(fatura, "isemri", ib, ZAMAN_ASIMI, true, 1); ib += ZAMAN_ASIMI + 2; }
    ekle(fatura, "isemri", ib, isemriSure, r() < PROFIL.isemri[2] / 1000, yenidenDendi ? 2 : 1);
    izler.push({ iz: `iz-${(i + 1).toString(36).padStart(4, "0")}`, t0, toplam: faturaBas + faturaSure,
      adimlar, atlandi, yenidenDendi, yavasAdim });
  }
  return izler;
}
// Adimin kendi suresi: adim suresi eksi cocuklarinin suresi.
export const kendi = (iz, a) =>
  a.sure - iz.adimlar.filter((c) => c.ust === a.id).reduce((x, c) => x + c.sure, 0);

if (import.meta.filename === process.argv[1]) {
  const I = uret(), adim = I.reduce((x, z) => x + z.adimlar.length, 0);
  console.log(`tohum ${TOHUM}, ${ISTEK} istek, ${adim} adim, ${SERVIS.length} servis, ${DK} dakika`);
  console.log(`dogrulamasi atlanan ${I.filter((z) => z.atlandi).length}, yeniden denenen cagri ` +
    `${I.filter((z) => z.yenidenDendi).length}, yavas istek ${I.filter((z) => z.yavasAdim).length}`);
  const o = I.find((z) => z.yenidenDendi && z.yavasAdim === "isemri" && !z.atlandi);
  console.log(`\niz agaci — ${o.iz} (${o.toplam} ms)`);
  const yaz = (ust, gir) => o.adimlar.filter((x) => x.ust === ust).forEach((a) => {
    console.log(`${gir}${a.servis.padEnd(14 - gir.length)}${String(a.sure).padStart(6)} ms` +
      `  kendi ${String(kendi(o, a)).padStart(4)} ms  deneme ${a.deneme}${a.hata ? "  zaman asimi" : ""}`);
    yaz(a.id, gir + "  ");
  });
  yaz(0, "");
}
```

```
tohum 20260802, 24000 istek, 118794 adim, 5 servis, 60 dakika
dogrulamasi atlanan 2624, yeniden denenen cagri 1418, yavas istek 477

iz agaci — iz-008m (889 ms)
gecit            889 ms  kendi    6 ms  deneme 1
  okuma           47 ms  kendi   16 ms  deneme 1
    dogrulama     31 ms  kendi   31 ms  deneme 1
  fatura         836 ms  kendi   44 ms  deneme 1
    isemri       120 ms  kendi  120 ms  deneme 1  zaman asimi
    isemri       672 ms  kendi  672 ms  deneme 2
```

Girinti bağı gösteriyor. Kök adım 889 ms sürdü, kendi işi 6 ms. Fatura adımı 836 ms sürdü, kendi
işi 44 ms — kalanı iş emri çağrısını beklemekle geçti ve o çağrı iki kez yapıldı; ilk deneme
120 ms'de zaman aşımına düştü. Bunların hiçbiri tek bir süre ölçütünden okunamaz: **üst-alt bağı**
olmadan 889 ms yalnız bir sayıdır.

#### On Bir Soru, Üç Görünüm

Aynı olaylardan üç görünüm üretilir: dakikalık ölçüt kovaları, adım başına bir günlük satırı, iz
ağaçları. Sorular üçüne de aynı biçimde sorulur; görünüm gerekli alanı taşımıyorsa arama boş döner
ve yanıt yazılmaz.

```js
// iz/soru.mjs — ayni olaylardan uc gorunum uretilir: dakikalik olcut kovalari, adim basina bir
// gunluk satiri, iz agaclari. On bir soru ucune de sorulur; gorunum gerekli alani tasimiyorsa
// arama bos doner ve yanit yazilmaz.
import { uret, kendi, ISTEK } from "./model.mjs";
const I = uret(), KOVA = [25, 50, 100, 200, 400, 800, 1600, Infinity], ESIK = 400;
// IG6 (varsayim): olcut kovasi ve gunluk satiri istek kimligi tasimaz; iz adimi hata bayragi
// tasir, hata metnini tasimaz.
const OLCUT = new Map(), GUNLUK = [], METIN = ["zaman asimi", "baglanti reddedildi", "gecersiz okuma"];
for (const z of I) for (const a of z.adimlar) {
  const k = `${a.servis}|${Math.floor((z.t0 + a.bas) / 60000)}`;
  let o = OLCUT.get(k);
  if (!o) OLCUT.set(k, (o = { n: 0, hata: 0, kova: new Array(KOVA.length).fill(0) }));
  o.n += 1; o.hata += a.hata ? 1 : 0; o.kova[KOVA.findIndex((b) => a.sure <= b)] += 1;
  GUNLUK.push({ servis: a.servis, sure: a.sure, hata: a.hata,
    mesaj: a.hata ? METIN[(a.sure + a.deneme) % 3] : "tamam" });
}
const p95 = (x) => x.slice().sort((a, b) => a - b)[Math.floor(x.length * 0.95)];
const sik = (m) => [...m].sort((a, b) => b[1] - a[1])[0];
const say = (dizi, f) => dizi.reduce((m, x) => m.set(f(x), (m.get(f(x)) || 0) + 1), new Map());
const kok = [...OLCUT].filter(([x]) => x.startsWith("gecit|")).map(([, o]) => o);
const gk = GUNLUK.filter((l) => l.servis === "gecit"), yavas = I.filter((z) => z.toplam > ESIK);
const enYavas = (z) => z.adimlar.slice().sort((a, b) => kendi(z, b) - kendi(z, a))[0];
const ort = (f) => { const g = I.filter(f); return g.reduce((x, z) => x + z.toplam, 0) / g.length; };
const yuzde = (a, b) => `%${(a / b * 100).toFixed(a / b < 0.1 ? 2 : 0)}`;
// bildirilen yavas istek: kimligi elde olan tek istek
const HEDEF = I.filter((z) => z.yavasAdim && z.yenidenDendi)[0], H = HEDEF.iz;
const oyok = () => OLCUT.get(H) ?? null;                  // kova kimlikle aranmaz
const gyok = () => GUNLUK.find((l) => l.iz === H) ?? null; // satirda iz alani yok

const SORU = [
  ["istek suresi p95", () => { const t = kok.reduce((a, o) => a.map((v, i) => v + o.kova[i]),
    KOVA.map(() => 0)), n = t.reduce((a, b) => a + b, 0); let s = 0;
    for (let i = 0; ; i += 1) if ((s += t[i]) >= n * 0.95) return `<=${KOVA[i]} ms`; },
    () => `${p95(gk.map((l) => l.sure))} ms`, () => `${p95(I.map((z) => z.toplam))} ms`],
  ["hata orani", () => yuzde([...OLCUT.values()].reduce((a, o) => a + o.hata, 0),
    [...OLCUT.values()].reduce((a, o) => a + o.n, 0)),
    () => yuzde(GUNLUK.filter((l) => l.hata).length, GUNLUK.length),
    () => yuzde(I.reduce((x, z) => x + z.adimlar.filter((a) => a.hata).length, 0), GUNLUK.length)],
  [`${ESIK} ms ustu istek`, () => kok.reduce((a, o) => a + o.kova[5] + o.kova[6] + o.kova[7], 0),
    () => gk.filter((l) => l.sure > ESIK).length, () => yavas.length],
  [`${H}: hangi adim yavas`, oyok, gyok, () => enYavas(HEDEF).servis],
  [`${H}: yavas adimin payi`, oyok, gyok, () => yuzde(kendi(HEDEF, enYavas(HEDEF)), HEDEF.toplam)],
  [`${H}: yeniden denenen cagri`, oyok, gyok, () => { const d = HEDEF.adimlar.find((a) => a.deneme > 1);
    return d ? `${d.servis} x${d.deneme}` : "yok"; }],
  [`${H}: dogrulama cagrildi mi`, oyok, gyok,
    () => (HEDEF.adimlar.some((a) => a.servis === "dogrulama") ? "evet" : "hayir")],
  ["yavas isteklerde en sik yavas adim", oyok, gyok,
    () => { const [ad, n] = sik(say(yavas, (z) => enYavas(z).servis)); return `${ad} ${yuzde(n, yavas.length)}`; }],
  ["dogrulamasi atlanan istek ne kadar hizli", oyok, gyok,
    () => `${(ort((z) => !z.atlandi) - ort((z) => z.atlandi)).toFixed(0)} ms`],
  ["en sik hata metni", () => null, () => sik(say(GUNLUK.filter((l) => l.hata), (l) => l.mesaj))[0],
    () => null],
  ["yavas adimin icindeki sorgu", () => null, () => null,
    () => HEDEF.adimlar.find((a) => a.ust === enYavas(HEDEF).id && a.servis === enYavas(HEDEF).servis) ?? null],
];

console.log(`${"soru".padEnd(42)}${"olcut".padStart(12)}${"gunluk".padStart(22)}${"iz".padStart(14)}`);
const n = [0, 0, 0];
for (const [ad, ...f] of SORU) {
  const y = f.map((fn) => { const v = fn(); return v === null || v === undefined ? "-" : String(v); });
  y.forEach((v, i) => { if (v !== "-") n[i] += 1; });
  console.log(`${ad.padEnd(42)}${y[0].padStart(12)}${y[1].padStart(22)}${y[2].padStart(14)}`);
}
const disi = SORU.filter(([, o, g]) => (o() ?? null) === null && (g() ?? null) === null);
console.log(`\n${ISTEK} istek, ${SORU.length} soru — olcut ${n[0]}, gunluk ${n[1]}, iz ${n[2]}`);
console.log(`olcut ve gunlukle yanitlanamayan ${disi.length} soru — izle yanitlanan ` +
  `${disi.filter(([, , , z]) => (z() ?? null) !== null).length}, hicbiriyle yanitlanamayan ` +
  `${SORU.filter(([, ...f]) => f.every((fn) => (fn() ?? null) === null)).length}`);
```

```
soru                                             olcut                gunluk            iz
istek suresi p95                              <=400 ms                248 ms        248 ms
hata orani                                       %1.38                 %1.38         %1.38
400 ms ustu istek                                  411                   411           411
iz-0024: hangi adim yavas                            -                     -         okuma
iz-0024: yavas adimin payi                           -                     -           %45
iz-0024: yeniden denenen cagri                       -                     -     isemri x2
iz-0024: dogrulama cagrildi mi                       -                     -          evet
yavas isteklerde en sik yavas adim                   -                     -    isemri %82
dogrulamasi atlanan istek ne kadar hizli             -                     -         27 ms
en sik hata metni                                    -   baglanti reddedildi             -
yavas adimin icindeki sorgu                          -                     -             -

24000 istek, 11 soru — olcut 3, gunluk 4, iz 9
olcut ve gunlukle yanitlanamayan 7 soru — izle yanitlanan 6, hicbiriyle yanitlanamayan 1
```

İlk üç soru üç görünümde de yanıtlanıyor ama aynı çözünürlükte değil: ölçüt görünümü p95 için
`<=400 ms` diyor, gerçek değer 248 ms — kova sınırı 200 ile 400 arasını tek hücrede topluyor. Soru
yanıtlanıyor, yanıt karara yetmiyor; bu yanıtsızlıktan farklı bir kusurdur.

Sonraki dört soru bildirilen tek bir isteğe bakıyor; iki görünümde arama boş dönüyor, çünkü kova da
günlük satırı da iz kimliği taşımıyor. `iz-0024` isteğinde en uzun kendi süresi okuma adımında
(toplam sürenin yüzde 45'i), iş emri çağrısı iki kez yapılmış, doğrulama çağrılmış. Küme sorusuyla
tek istek sorusu **farklı yanıt veriyor**: 400 ms'yi aşan 411 isteğin yüzde 82'sinde yavaş adım iş
emriydi, bildirilen istekte değildi.

Son iki soru izin sınırını çiziyor. Hata metnini yalnız günlük taşıyor; iz adımı hata bayrağı
tutuyor, metni tutmuyor. Yavaş adımın içindeki sorgu ise **üç görünümün hiçbiriyle**
yanıtlanamıyor: enstrümantasyon o derinlikte adım açmıyor. Yedi sorunun altısı izle yanıtlandı,
yanıtsız kalanın nedeni toplama değil **enstrümantasyon derinliği**.

#### Adım Başına Bayt

```js
// iz/bedel.mjs — izin bayt bedeli ve kokte verilen ornekleme kararinin taranmasi. Kayit boyutu
// gercek kayittan olculur, sikistirma uygulanmaz. IZ_SORU: yalniz izle yanitlanan soru sayisi.
import { uret, ISTEK } from "./model.mjs";
const I = uret(), ESIK = 400, IZ_SORU = 6, gun = (b) => (b * 24 / 1e6).toFixed(1);
const adim = I.reduce((x, z) => x + z.adimlar.length, 0);
const izBayt = I.reduce((x, z) => x + z.adimlar.reduce((y, a) =>
  y + JSON.stringify({ iz: z.iz, ...a }).length, 0), 0);
console.log(`${adim} adim, adim basina ${(izBayt / adim).toFixed(0)} bayt, istek basina ` +
  `${(izBayt / ISTEK).toFixed(0)} bayt (${(adim / ISTEK).toFixed(1)} adim), gunde ${gun(izBayt)} MB`);

const kirp = (s) => { let h = 7; for (const c of s) h = (h * 31 + c.charCodeAt(0)) >>> 0; return h; };
const yavas = I.filter((z) => z.toplam > ESIK), H = I.filter((z) => z.yavasAdim && z.yenidenDendi)[0].iz;
console.log(`\n${"oran".padEnd(7)}${"kayitli iz".padStart(11)}${"gun/MB".padStart(8)}` +
  `${"yakalanan".padStart(11)}${"kacan yavas".padStart(13)}${"MB/soru".padStart(9)}  bildirilen istek`);
for (const n of [1, 2, 5, 20, 100]) {
  const tut = (z) => kirp(z.iz) % n === 0, k = I.filter(tut), b = izBayt / ISTEK * k.length;
  console.log(`${`1/${n}`.padEnd(7)}${String(k.length).padStart(11)}${gun(b).padStart(8)}` +
    `${String(yavas.filter(tut).length).padStart(11)}` +
    `${String(yavas.length - yavas.filter(tut).length).padStart(13)}` +
    `${(+gun(b) / IZ_SORU).toFixed(1).padStart(9)}  ${k.some((z) => z.iz === H) ? "kayitli" : "kayitsiz"}`);
}
```

```
118794 adim, adim basina 92 bayt, istek basina 455 bayt (4.9 adim), gunde 262.2 MB

oran    kayitli iz  gun/MB  yakalanan  kacan yavas  MB/soru  bildirilen istek
1/1          24000   262.2        411            0     43.7  kayitli
1/2          12001   131.1        209          202     21.8  kayitsiz
1/5           4800    52.4         82          329      8.7  kayitli
1/20          1200    13.1         27          384      2.2  kayitsiz
1/100          245     2.7          6          405      0.5  kayitsiz
```

Bir istek 4,9 adım ve 455 bayt; adım başına 92 bayt, günde 262 MB. Yalnız izle yanıtlanan altı
sorunun her biri bu ölçekte 43,7 MB'ye mal oluyor. Örnekleme çarpanı doğrudan bölüyor: 1/20
oranında hacim 13 MB'ye, soru başına maliyet 2,2 MB'ye iniyor. Bedel sağ sütunlarda — 411 yavaş
isteğin 384'ü kayıtsız kalıyor. Karar kökte, sonuç görülmeden verildiği için **yavaş olduğu için
tutulan** istek yok; bildirilen isteğin elde olması kura işidir.

Yanıtsız sorunun bedeli buradan okunur. "Hangi adım yavaş" yanıtlanamadığında müdahale beş servise
birden bakar, iz varken bakılacak yer tek bir adımdır. Örnekleme yüzünden yanıtsız kalındığında
bedel eşit bölünmez: 1/20 oranında yavaş isteklerin yüzde 93'ü için soru yanıtsızdır.

#### Özet

- İz ağacı adımların üst-alt bağıdır; bağ olmadan toplam süre yalnız bir sayıdır.
- On bir sorudan ölçüt görünümü 3'ünü, günlük görünümü 4'ünü, iz görünümü 9'unu yanıtladı; ölçüt ve
  günlükle yanıtlanamayan 7 sorunun 6'sı izle yanıtlandı.
- Bir soru üç görünümün hiçbiriyle yanıtlanmadı — yavaş adımın içindeki sorgu; eksik olan toplama
  değil enstrümantasyon derinliğidir.
- İzin bedeli adım sayısıyla ölçülür: adım başına 92 bayt, günde 262 MB, yalnız izle yanıtlanan
  soru başına 43,7 MB.
- Kökte verilen 1/20 örnekleme hacmi 13 MB'ye indiriyor ama 411 yavaş isteğin 384'ünü kayıtsız
  bırakıyor; hangi isteğin kaldığı sorunun önemine bakmaz.

#### Sonraki Adım

Bu derste beş servisin adım kayıtları tek ağaçta birleşti, çünkü hepsi aynı alan adlarını
kullanıyordu: `servis`, `sure`, `deneme`. Gerçek bir ağda bu birleşme kendiliğinden olmaz; beş ekip
kendi adlandırmasını yazar, biri süreyi milisaniye öteki mikrosaniye tutar, aynı kavram üç ada
bölünür ve iki adım yan yana geldiğinde karşılaştırılamaz.
Sonraki ders ortak bir telemetri sözleşmesini alan alan tanımlar ve bedelini sayar: kaç alan ve kaç
servis değişikliği karşılığında kaç soru birleştirilebiliyor, kaç servis uyumsuz kalıyor.

### Enstrümantasyon Standartları

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/enstrumantasyon-standartlari

Beş servisin kendi adlandırmasıyla yazdığı telemetrinin servisler arası birleştirilememesi: on sorunun yerel şemalar ve ortak sözleşme üzerinde ayrı ayrı yanıtlanması, sessizce yanlış yanıtların sayılması ve sözleşmenin alan, servis değişikliği ve uyumsuz servis olarak bedelinin çıkarılması.

Önceki derste beş servisin adım kayıtları tek bir ağaçta birleşti. Birleşmenin nedeni kodda
yazılıydı: her servis aynı alan adlarını, aynı birimi ve aynı iz kimliğini kullanıyordu. Bu
varsayım gerçek bir ağda karşılıksızdır. Beş servisi beş ekip yazar; her ekip kendi kaydını kendi
alışkanlığıyla adlandırır, süreyi kendi birimine göre yazar, hatayı kendi bildiği biçimde işaretler.
Kayıtlar tek tek doğrudur ve her ekip kendi gösterge tablosunda doğru sayıları görür. Kırılan şey,
**servisler arası** sorudur.

Bu ders bölgesel ölçüm ağının (kurgu) beş servisini kendi yerel şemalarıyla yazdırır, aynı on soruyu
önce bu şemalar üzerinde sorar, sonra ortak bir telemetri sözleşmesi tanımlayıp yeniden sorar.
Sözleşmenin ne olduğu ortak yapısıyla anlatılır; şema ders içinde tanımlanır.

#### Aynı İsteğin Beş Kaydı

```js
// soz/kayit.mjs — bes servisin ayni istegi kendi yerel semasiyla yazmasinin MODELI. Once dogru
// degerler uretilir (gercek), sonra her servis kendi alan adlari ve birimiyle bir kayit yazar.
// IG7: yerel semalar kurgudur. IG8: okuma ile fatura ayni "sure" adini farkli birimle yazar.
// IG9: fatura zincirden gelen kimligi degil kendi istek numarasini tasir. IG10: isemri disaridan
// alinmis bir bilesendir, kaydi degistirilemez.
export const TOHUM = 20260803, ISTEK = 6000;
export const SERVIS = ["gecit", "okuma", "dogrulama", "fatura", "isemri"];
export const TABAN = { gecit: 6, okuma: 21, dogrulama: 28, fatura: 47, isemri: 19 };
export const AKIS = "fatura_sorgu";

export function gercek() {
  let s = TOHUM;
  const r = () => ((s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32);
  const cikti = [];
  for (let i = 0; i < ISTEK; i += 1) {
    const t0 = Date.UTC(2026, 7, 3) + Math.floor(r() * 3600000), atlandi = r() < 0.11, adimlar = [];
    for (const ad of SERVIS) {
      if (ad === "dogrulama" && atlandi) continue;
      adimlar.push({ servis: ad, sure_ms: Math.max(1, Math.round(TABAN[ad] * (0.6 + r() * 0.9))),
        durum: r() < ({ fatura: 0.014, isemri: 0.0005 }[ad] ?? 0.004) ? "hata" : "tamam" });
    }
    cikti.push({ iz: `iz-${(i + 1).toString(36).padStart(4, "0")}`, t0, atlandi, adimlar });
  }
  return cikti;
}

// Yerel semalar: ayni bilgi bes ayri adlandirma ve uc ayri birimle yazilir.
export const YEREL = {
  gecit: (z, a) => ({ zaman: new Date(z.t0).toISOString(), servis: "gecit", islem: AKIS,
    sure_ms: a.sure_ms, durum: a.durum, iz: z.iz }),
  okuma: (z, a) => ({ t: Math.floor(z.t0 / 1000), birim: "okuma", eylem: "sorgu",
    sure: a.sure_ms * 1000, sonuc: a.durum === "hata" ? 1 : 0, izlem: z.iz }),
  dogrulama: (z, a) => ({ ts: z.t0, bilesen: "dogrulama", islem: "dogrula",
    gecikme: a.sure_ms / 1000, hata: a.durum === "hata", iz_kimlik: z.iz }),
  fatura: (z, a) => ({ zaman: new Date(z.t0).toISOString(), uygulama: "fatura", uc: "hesapla",
    sure: a.sure_ms, durum_kodu: a.durum === "hata" ? 500 : 200, istek_no: `f-${z.iz.slice(3)}` }),
  isemri: (z, a) => ({ zaman: z.t0, servis: "isemri", yordam: "emir_ac",
    islem_suresi: a.sure_ms, hata_kodu: a.durum === "hata" ? 7 : 0 }),
};
export const yerelAkis = (G) => G.flatMap((z) => z.adimlar.map((a) => YEREL[a.servis](z, a)));

if (import.meta.filename === process.argv[1]) {
  const G = gercek(), z = G[0];
  console.log(`tohum ${TOHUM}, ${ISTEK} istek, ${SERVIS.length} servis, ` +
    `${G.reduce((x, y) => x + y.adimlar.length, 0)} kayit`);
  console.log(`\nbir istegin (${z.iz}) bes serviste yazdigi kayit:`);
  for (const a of z.adimlar) console.log(`  ${JSON.stringify(YEREL[a.servis](z, a))}`);
  const alan = new Map();
  for (const a of z.adimlar) for (const k of Object.keys(YEREL[a.servis](z, a)))
    alan.set(k, (alan.get(k) || 0) + 1);
  console.log(`\ntoplam ${alan.size} ayri alan adi, bes serviste ortak olan: ` +
    `${[...alan].filter(([, n]) => n === 5).map(([k]) => k).join(", ") || "yok"}`);
}
```

```
tohum 20260803, 6000 istek, 5 servis, 29362 kayit

bir istegin (iz-0001) bes serviste yazdigi kayit:
  {"zaman":"2026-08-03T00:21:34.006Z","servis":"gecit","islem":"fatura_sorgu","sure_ms":5,"durum":"tamam","iz":"iz-0001"}
  {"t":1785716494,"birim":"okuma","eylem":"sorgu","sure":30000,"sonuc":0,"izlem":"iz-0001"}
  {"ts":1785716494006,"bilesen":"dogrulama","islem":"dogrula","gecikme":0.035,"hata":false,"iz_kimlik":"iz-0001"}
  {"zaman":"2026-08-03T00:21:34.006Z","uygulama":"fatura","uc":"hesapla","sure":54,"durum_kodu":200,"istek_no":"f-0001"}
  {"zaman":1785716494006,"servis":"isemri","yordam":"emir_ac","islem_suresi":25,"hata_kodu":0}

toplam 24 ayri alan adi, bes serviste ortak olan: yok
```

Tek bir isteğin beş kaydında üç ayrılık birden var. **Alan adı:** aynı kavram beş serviste `sure_ms`,
`sure`, `gecikme`, `islem_suresi` adlarıyla geçiyor; toplam 24 ayrı alan adı sayılıyor ve beş
servisin hepsinde bulunan tek bir ortak alan yok. **Birim:** süre üç ayrı birimde yazılmış —
milisaniye, mikrosaniye, saniye — ve alan adı birimi söylemiyor. **Değer uzayı:** hata beş serviste
`"hata"` metni, `1` sayısı, `true` mantıksal değeri, `500` kodu ve `7` kodu olarak işaretlenmiş.
Dördüncü ayrılık kimlikte: fatura zincirden gelen iz kimliğini değil kendi istek numarasını
taşıyor, iş emri hiçbir kimlik taşımıyor.

#### Sözleşmenin Ortak Yapısı

Telemetri sözleşmesi bir araç değil, bir **anlaşmadır**: hangi alanın hangi adla, hangi birimde,
hangi değer uzayında yazılacağını ve isteğin kimliğinin çağrıdan çağrıya nasıl taşınacağını
sabitler. Bu derste kullanılan altı alanlık şema şudur:

| Alan | Anlam | Birim ve değer uzayı |
|---|---|---|
| `iz` | isteğin çağrı zinciri boyunca taşınan kimliği | metin, beş serviste aynı |
| `zaman_ms` | adımın başlangıcı | epoch milisaniye, tam sayı |
| `servis` | kaydı yazan servis | katalogdaki ad |
| `akis` | adımın ait olduğu iş akışı | ortak akış adı |
| `sure_ms` | adımın süresi | milisaniye |
| `durum` | adımın sonucu | `tamam` ya da `hata` |

Sözleşmenin karşısındaki çözüm, sorgu tarafında elle yazılmış bir **eşleme tablosudur**: "şu alan
adını görürsen süre say, şu değeri görürsen hata say". Aşağıdaki karşılaştırma iki yolu aynı soru
kümesiyle ölçer.

#### On Soru, İki Aşama

```js
// soz/sorgu.mjs — on soru iki asamada sorulur: once yerel semalar uzerinde elle yazilmis esleme
// tablosuyla (IG11), sonra ortak sozlesmeye gecmis kayitlar uzerinde. Her yanit gercek degerle
// karsilastirilir: sapma yuzde 5'i asarsa "yanlis", okunabilir alan yoksa "yok".
import { gercek, YEREL, SERVIS, AKIS, ISTEK } from "./kayit.mjs";
const G = gercek();
// IG11: esleme tablosu ilk buldugu alani kullanir, deger uzayini bilmez.
const ESLEME = { iz: ["iz", "izlem", "iz_kimlik", "istek_no"], zaman_ms: ["zaman_ms", "zaman", "ts", "t"],
  servis: ["servis", "birim", "bilesen", "uygulama"], akis: ["akis", "islem", "eylem", "yordam", "uc"],
  sure_ms: ["sure_ms", "sure", "gecikme", "islem_suresi"],
  durum: ["durum", "hata", "sonuc", "durum_kodu", "hata_kodu"] };
const oku = (k, alan) => { for (const a of ESLEME[alan]) if (a in k) return k[a]; return null; };
const sayi = (v) => (typeof v === "number" && Number.isFinite(v) ? v : null);
const hataMi = (v) => v === "hata" || v === true;      // eslemeyi yazanin bildigi iki bicim
// IG12: sozlesme gecisi kaydin uretildigi yerde yapilir; isemri (IG10) yerel kaydinda kalir.
const SOZLESME = ["iz", "zaman_ms", "servis", "akis", "sure_ms", "durum"], UYUMSUZ = ["isemri"];
const sozlesmeli = (z, a) => (UYUMSUZ.includes(a.servis) ? YEREL[a.servis](z, a)
  : { iz: z.iz, zaman_ms: z.t0, servis: a.servis, akis: AKIS, sure_ms: a.sure_ms, durum: a.durum });
const kayitlar = (f) => G.flatMap((z) => z.adimlar.map((a) => f(z, a)));
const [YEREL_K, SOZ_K] = [kayitlar((z, a) => YEREL[a.servis](z, a)), kayitlar(sozlesmeli)];

const ort = (x) => (x.length ? x.reduce((a, b) => a + b, 0) / x.length : null);
const p95 = (x) => (x.length ? x.slice().sort((a, b) => a - b)[Math.floor(x.length * 0.95)] : null);
const grup = (K, alan) => { const m = new Map();
  for (const k of K) { const g = oku(k, alan); if (g !== null) m.set(g, [...(m.get(g) ?? []), k]); }
  return m; };
const sure = (k) => sayi(oku(k, "sure_ms")) ?? 0;
const izToplam = (K) => [...grup(K, "iz").values()].map((v) => v.reduce((x, k) => x + sure(k), 0));
const servisSure = (K, s) => (grup(K, "servis").get(s) ?? []).map((k) => sayi(oku(k, "sure_ms")))
  .filter((v) => v !== null);
const enYavas = (K) => SERVIS.map((s) => [s, p95(servisSure(K, s)) ?? -1]).sort((a, b) => b[1] - a[1])[0];
const gS = (s) => G.flatMap((z) => z.adimlar.filter((a) => a.servis === s).map((a) => a.sure_ms));
const gAdim = G.flatMap((z) => z.adimlar), uctanUca = G.map((z) => z.adimlar.reduce((x, a) => x + a.sure_ms, 0));

const SORU = [
  ["en yavas servis", "fatura", (K) => enYavas(K)[0]],
  ["en yavas servisin p95 (ms)", p95(gS("fatura")), (K) => enYavas(K)[1]],
  ["en cok hata ureten servis", "fatura", (K) => SERVIS.map((s) => [s,
    (grup(K, "servis").get(s) ?? []).filter((k) => hataMi(oku(k, "durum"))).length])
    .sort((a, b) => b[1] - a[1])[0][0]],
  ["hata orani (%)", gAdim.filter((a) => a.durum === "hata").length / gAdim.length * 100,
    (K) => K.filter((k) => hataMi(oku(k, "durum"))).length / K.length * 100],
  ["saatlik istek sayisi", ISTEK, (K) => ((g) => (g.length ? g.length : null))(
    (grup(K, "servis").get("gecit") ?? []).filter((k) => sayi(+oku(k, "zaman_ms")) !== null))],
  ["uctan uca ortalama sure (ms)", ort(uctanUca), (K) => ort(izToplam(K))],
  ["istek basina birlesen kayit", ort(G.map((z) => z.adimlar.length)),
    (K) => ort([...grup(K, "iz").values()].map((v) => v.length))],
  ["dogrulamasi atlanan istek", G.filter((z) => z.atlandi).length,
    (K) => [...grup(K, "iz").values()].filter((v) => v.every((k) => oku(k, "servis") !== "dogrulama")).length],
  [`${AKIS} akisinin toplam suresi (ms)`, uctanUca.reduce((a, b) => a + b, 0),
    (K) => (grup(K, "akis").get(AKIS) ?? []).reduce((x, k) => x + sure(k), 0) || null],
  ["isemri adiminin uctan uca payi (%)", ort(gS("isemri")) / ort(uctanUca) * 100,
    (K) => { const m = grup(K, "iz"), i = [...m.values()].flat()
      .filter((k) => oku(k, "servis") === "isemri" && oku(k, "iz") !== null);
      return i.length ? ort(i.map(sure)) / ort(izToplam(K)) * 100 : null; }],
];
const bicim = (v) => (v === null ? "-" : typeof v === "number" ? v.toFixed(v < 100 ? 2 : 0) : String(v));
const dogruMu = (g, v) => (v === null ? "yok" : typeof g === "number"
  ? (Math.abs(v - g) / g <= 0.05 ? "dogru" : "yanlis") : (v === g ? "dogru" : "yanlis"));

console.log(`${"soru".padEnd(40)}${"gercek".padStart(9)}${"yerel sema".padStart(12)}` +
  `${"durum".padStart(8)}${"sozlesme".padStart(11)}${"durum".padStart(8)}`);
const say = { yerel: {}, soz: {} };
for (const [ad, g, f] of SORU) {
  const [y, s] = [f(YEREL_K), f(SOZ_K)], [dy, ds] = [dogruMu(g, y), dogruMu(g, s)];
  say.yerel[dy] = (say.yerel[dy] || 0) + 1; say.soz[ds] = (say.soz[ds] || 0) + 1;
  console.log(`${ad.padEnd(40)}${bicim(g).padStart(9)}${bicim(y).padStart(12)}${dy.padStart(8)}` +
    `${bicim(s).padStart(11)}${ds.padStart(8)}`);
}
const d = (o) => `dogru ${o.dogru || 0}, yanlis ${o.yanlis || 0}, yok ${o.yok || 0}`;
console.log(`\nyerel sema: ${d(say.yerel)}\nsozlesme  : ${d(say.soz)}`);
const degisim = SERVIS.map((s) => [s, UYUMSUZ.includes(s) ? 0
  : SOZLESME.filter((a) => !(a in YEREL[s](G[0], G[0].adimlar[0]))).length]);
console.log(`sozlesme ${SOZLESME.length} alan; degisen alan: ${degisim.map(([s, n]) => `${s} ${n}`).join(", ")}` +
  `; toplam ${degisim.reduce((x, [, n]) => x + n, 0)} alan degisikligi, ` +
  `uyumsuz kalan ${UYUMSUZ.length}/${SERVIS.length} servis`);
```

```
soru                                       gercek  yerel sema   durum   sozlesme   durum
en yavas servis                            fatura       okuma  yanlis     fatura   dogru
en yavas servisin p95 (ms)                  68.00       31000  yanlis      68.00   dogru
en cok hata ureten servis                  fatura   dogrulama  yanlis     fatura   dogru
hata orani (%)                               0.56        0.18  yanlis       0.54   dogru
saatlik istek sayisi                         6000           -     yok       6000   dogru
uctan uca ortalama sure (ms)                  124       11141  yanlis        104  yanlis
istek basina birlesen kayit                  4.89        1.95  yanlis       3.89  yanlis
dogrulamasi atlanan istek                     638        6638  yanlis        638   dogru
fatura_sorgu akisinin toplam suresi (ms)   744212       37943  yanlis     625249  yanlis
isemri adiminin uctan uca payi (%)          15.99           -     yok          -     yok

yerel sema: dogru 0, yanlis 8, yok 2
sozlesme  : dogru 6, yanlis 3, yok 1
sozlesme 6 alan; degisen alan: gecit 2, okuma 6, dogrulama 6, fatura 6, isemri 0; toplam 20 alan degisikligi, uyumsuz kalan 1/5 servis
```

Yerel şemalar üzerinde on sorudan **hiçbiri** doğru yanıtlanmadı. Asıl bulgu dağılımdadır: yalnız
ikisi yanıtsız kaldı, sekizi **sessizce yanlış** yanıtlandı. Eşleme tablosu okuma servisinin
mikrosaniye değerini milisaniye sanıp p95'i 68 yerine 31.000 buldu ve en yavaş servis olarak
faturayı değil okumayı gösterdi. Hata oranı yüzde 0,56 yerine 0,18 çıktı, çünkü tablo yalnız iki
biçimi tanıyor. En çok hata üreten servis sorusuna fatura yerine doğrulama yanıtı verildi. Uçtan
uca süre 124 ms yerine 11.141 ms göründü. Bu yanıtların hiçbirinin yanında bir uyarı yok; sorgu
çalışıyor, sayı üretiyor, gösterge tablosuna çiziliyor.

Yanıtsız kalan iki soru bu yüzden **daha ucuzdur**: saatlik istek sayısı hiç hesaplanamadı, çünkü
geçit zamanı metin biçiminde yazıyor ve sayıya çevrilemedi. Yanıt yokluğu görülür, yanlış yanıt
görülmez.

Sözleşme uygulandığında altı soru doğru yanıtlandı. Kalan dördün tamamı tek bir kaynağa çıkıyor:
sözleşmeye geçirilemeyen servis. Uçtan uca süre 124 yerine 104 ms, istek başına birleşen kayıt 4,89
yerine 3,89, akış toplamı 744.212 yerine 625.249 ms — üçü de eksik bir adımın açığı. İş emri
adımının uçtan uca paydaki payı ise hâlâ yanıtsız: o servisin kaydında iz kimliği yok, dolayısıyla
adım hiçbir isteğe bağlanamıyor.

#### Sözleşmenin Bedeli

Sözleşme altı alandan oluşuyor. Dört servis bu alanlara geçti ve bu geçiş toplam 20 alan
değişikliği demek: geçit iki alan ekledi, öteki üç servis altışar alanını yeniden adlandırdı ya da
birimini çevirdi. Beşinci servis dışarıdan alınmış bir bileşen olduğu için değiştirilemedi ve
uyumsuz kaldı.

Bu üç sayının oranı işin kararını taşıyor. Alan başına kazanç yüksek: 20 alan değişikliği
karşılığı sıfır doğru yanıttan altı doğru yanıta çıkıldı, yani bir doğru yanıt ortalama yaklaşık
3,3 alan değişikliğine mal oldu. Buna karşılık kazanç **doğrusal değil**: servislerin yüzde 80'i
sözleşmeye uydu ama soruların yalnız yüzde 60'ı yanıtlandı, çünkü servisler arası soru en zayıf
halkaya bağlı. Bir istek zincirinde tek bir uyumsuz adım, o adımı içeren her soruyu bozuyor.

Yanıtsız kalan sorunun bedeli burada iki katmanlıdır. Birinci katman doğrudan: iş emri adımının payı
bilinmediği için o servisin yavaşlaması uçtan uca ölçümde görünmez. İkinci katman daha pahalı:
sözleşme öncesi sekiz soru **yanlış** yanıtlanıyordu ve bu yanıtlarla karar verilmişti — en yavaş
servis olarak okuma gösterildiği sürece iyileştirme çabası yanlış servise harcanır.

#### Özet

- Beş servis kendi adlandırmasıyla yazdığında tek bir istek 24 ayrı alan adına dağılıyor ve beş
  servisin hepsinde bulunan ortak alan kalmıyor.
- Yerel şemalar üzerinde on sorudan sıfırı doğru yanıtlandı; ikisi yanıtsız kaldı, sekizi sessizce
  yanlış yanıtlandı — yanlış yanıt yanıtsızlıktan pahalıdır, çünkü görülmez.
- Ayrılık üç katmanda birden çıkıyor: alan adı, birim (ms, µs, sn) ve değer uzayı (metin, sayı,
  mantıksal değer, kod); kimlik ayrılığı bunlara ek olarak birleştirmeyi tümden engelliyor.
- Altı alanlık sözleşme 20 alan değişikliği ve dört servis değişikliği karşılığında doğru yanıtı
  altıya çıkardı.
- Servislerin yüzde 80'i uydu ama soruların yüzde 60'ı yanıtlandı: tek uyumsuz servis kendi
  adımını içeren dört soruyu birden bozuyor.

#### Sonraki Adım

Sözleşme kurulduktan sonra sorular yanıtlanabilir hâle geldi, ama yanıtın nerede okunacağı hâlâ
açık. Bir kişi olay sırasında sorgu yazmaz; önüne çıkan panellere bakar. Panellerin hangi soruya
yanıt verdiği ise çoğu zaman hiç sorulmamıştır — tablolar zamanla eklenen, kimsenin silmediği
panellerle dolar. Sonraki ders bir gösterge tablosunu soru kümesine karşı denetler: kaç panel bir
soruya yanıt veriyor, kaç panel hiçbir soruya yanıt vermiyor, kaç soru panelsiz kalıyor ve bir
soruya yanıt bulmak kaç panel gezmeyi gerektiriyor.

### Gösterge Tablosu Tasarımı

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/gosterge-tablosu-tasarimi

Bir gösterge tablosunun soru kümesine karşı denetlenmesi: kaç panelin bir soruya yanıt verdiği, kaç panelin hiçbir soruya yanıt vermediği, kaç sorunun panelsiz kaldığı ve bir soruya yanıt bulmak için gezilen panel sayısının yeniden düzenlemeyle nasıl düştüğü.

Sözleşme kurulduktan sonra sorular yanıtlanabilir hâle geldi. Yanıtın nasıl okunacağı ise ayrı bir
iş: bir olay sırasında kimse sorgu yazmaz, önüne çıkan panellere bakar. Panonun kendisi de zamanla
büyür — her olaydan sonra bir panel eklenir, hiçbir olaydan sonra panel silinmez ve iki yıl sonra
ortaya kimsenin bütününü bilmediği bir sayfa çıkar.

Bu ders bir panoyu **soru kümesine karşı** denetler. Ölçülen üç sayı şudur: kaç panel en az bir
soruya yanıt veriyor, kaç panel hiçbir soruya yanıt vermiyor, kaç soru panelsiz kalıyor. Dördüncü
sayı bunlardan çıkar: bir soruya yanıt bulmak kaç panel gezmeyi gerektiriyor.

#### Panelin Yanıtladığı Soru

Bir panel bir soruyu üç koşul birden sağlarsa yanıtlar. **Ölçüt** aynı olmalıdır: hata oranı
sorusuna gecikme paneli yanıt vermez. **Boyut** sorunun istediği kırılımı içermelidir: "hangi
servis bozuk" sorusuna toplam hata oranı paneli yanıt veremez, çünkü kırılım paneldeki sorguda
yok. **Çözünürlük** sorunun istediği kadar ince olmalıdır: beş dakikalık kovalarla çizilen bir
panel, bir dakikalık pencereyi soran soruya yanıt vermez.

Bu üç koşul aşağıdaki modelde birer alan olarak duruyor. Bölgesel ölçüm ağının panel ve soru
listesi kurgudur;
soru sıklıkları, panonun bakılma biçimini ağırlıklandırmak için konmuştur.

```js
// pano/pano.mjs — bir gosterge tablosunun ve isletimde sorulan soru kumesinin MODELI.
// Panel: [ad, olcut, boyutlar, cozunurluk sn, sorgunun taradigi seri]. Soru: [ad, olcut, gereken
// boyut, gereken en kaba cozunurluk, kirk olayin kacinda soruldugu]. IG13: panel katalogu, soru
// kumesi ve soru sikliklari kurgudur; pano iki yil boyunca eklemelerle buyumustur. IG14: bir panel
// bir soruyu ancak ayni olcutu, sorunun istedigi boyutu ve o cozunurlugu tasiyorsa yanitlar.
// IG15: bir paneli gozle tarayip gecmek 8 saniye; panelsiz soru icin elle sorgu yazmak 4 dakika.
export const PANEL = [
  ["kume islemci kullanimi", "islemci", ["dugum"], 60, 120], ["kume bellek kullanimi", "bellek", ["dugum"], 60, 120],
  ["dugum disk doluluk", "disk", ["dugum"], 300, 120], ["toplam istek (gunluk)", "istek", [], 3600, 1],
  ["istek sayisi", "istek", ["servis"], 60, 5], ["hata orani (toplam)", "hata_orani", [], 60, 1],
  ["surum bilgisi", "surum", [], 3600, 5], ["kayit sayisi (bugun)", "kayit", [], 3600, 1],
  ["p95 gecikme (toplam)", "gecikme", [], 60, 1], ["p95 gecikme (servis)", "gecikme", ["servis"], 60, 5],
  ["adim suresi (servis)", "adim_suresi", ["servis"], 60, 5], ["istemci surum dagilimi", "istemci", ["surum"], 3600, 40],
  ["dugum sayisi", "dugum_sayisi", [], 300, 1], ["kuyruk derinligi", "kuyruk", ["servis"], 60, 5],
  ["onbellek isabet orani", "onbellek", ["servis"], 60, 5], ["cop toplama suresi", "cop_toplama", ["dugum"], 60, 120],
  ["hata orani (servis)", "hata_orani", ["servis"], 60, 5], ["yeniden deneme sayisi", "yeniden_deneme", [], 60, 1],
  ["ag trafigi", "ag", ["dugum"], 60, 240], ["dagitim olaylari", "dagitim", ["servis"], 60, 5],
  ["gecelik toplu is suresi", "toplu_is", [], 3600, 1], ["saatlik okuma sayisi", "okuma", [], 3600, 1],
  ["bagimlilik gecikmesi", "adim_suresi", ["bagimlilik"], 60, 12], ["hata orani (bolge)", "hata_orani", ["bolge"], 300, 30],
  ["sayac tipi dagilimi", "sayac_tipi", ["tip"], 3600, 8], ["islemci (tek dugum)", "islemci", ["dugum"], 60, 1],
];
// Soru kumesi: bir olay sirasinda sirasiyla sorulanlar (onem sirasi = dizi sirasi).
export const SORU = [
  ["uye etkileniyor mu", "hata_orani", [], 60, 40], ["hangi servis bozuk", "hata_orani", ["servis"], 60, 38],
  ["gecikme hangi adimda", "adim_suresi", ["servis"], 60, 30], ["trafik degisti mi", "istek", ["servis"], 60, 25],
  ["yeni dagitim var mi", "dagitim", ["servis"], 60, 22], ["kuyruk birikiyor mu", "kuyruk", ["servis"], 60, 16],
  ["yeniden denemeler artti mi", "yeniden_deneme", [], 60, 12], ["dis bagimlilik yavas mi", "adim_suresi", ["bagimlilik"], 60, 10],
  ["hata bir bolgeye mi ozgu", "hata_orani", ["bolge"], 60, 9], ["gecelik toplu is etkilendi mi", "toplu_is", [], 3600, 6],
  ["onbellek isabeti dustu mu", "onbellek", ["servis"], 60, 5], ["hangi abone grubu etkilendi", "hata_orani", ["abone_grubu"], 60, 4],
];
export const PANEL_SN = 8, SORGU_DK = 4, OLAY = 40;
export const yanitlar = (p, s) => p[1] === s[1] && s[2].every((b) => p[2].includes(b)) && p[3] <= s[3];
export const denetle = (paneller) => {
  const bulus = SORU.map((s) => paneller.findIndex((p) => yanitlar(p, s)) + 1);   // 0: panel yok
  const kullanilan = paneller.filter((p) => SORU.some((s) => yanitlar(p, s)));
  const agirlik = SORU.reduce((a, s, i) => a + (bulus[i] ? s[4] : 0), 0);
  const bakis = SORU.reduce((a, s, i) => a + (bulus[i] ? s[4] * bulus[i] : 0), 0) / agirlik;
  const dk = (SORU.reduce((a, s, i) => a + (bulus[i] ? s[4] * bulus[i] * PANEL_SN
    : s[4] * SORGU_DK * 60), 0)) / OLAY / 60;
  return { panel: paneller.length, kullanilan: kullanilan.length, sus: paneller.length - kullanilan.length,
    yanitlanan: bulus.filter((b) => b > 0).length, panelsiz: SORU.filter((_, i) => bulus[i] === 0).map((s) => s[0]),
    bakis, dk, seri: paneller.reduce((a, p) => a + p[4], 0), bulus };
};

if (import.meta.filename === process.argv[1]) {
  const d = denetle(PANEL);
  console.log(`${d.panel} panel, ${SORU.length} soru`);
  console.log(`bir soruya yanit veren panel ${d.kullanilan}, hicbir soruya yanit vermeyen ${d.sus}`);
  console.log(`yanitlanan soru ${d.yanitlanan}, panelsiz soru ${d.panelsiz.length}: ${d.panelsiz.join(", ")}`);
  console.log(`bakis suresi (soru sikligiyla agirlikli gezilen panel) ${d.bakis.toFixed(1)}, ` +
    `en kotu ${Math.max(...d.bulus)}`);
  console.log(`olay basina pano suresi ${d.dk.toFixed(1)} dk, pano acilisinda taranan seri ${d.seri}\n`);
  console.log(`${"soru".padEnd(30)}${"gezilen panel".padStart(14)}  yanit veren panel`);
  SORU.forEach((s, i) => console.log(`${s[0].padEnd(30)}${(d.bulus[i] || "-").toString().padStart(14)}  ` +
    `${d.bulus[i] ? PANEL[d.bulus[i] - 1][0] : "yok"}`));
  const sus = PANEL.filter((p) => !SORU.some((s) => yanitlar(p, s)));
  console.log(`\nsus paneller (${sus.length}): ${sus.map((p) => p[0]).join(", ")}`);
  console.log(`sus panellerin taradigi seri ${sus.reduce((a, p) => a + p[4], 0)} ` +
    `(toplamin %${(sus.reduce((a, p) => a + p[4], 0) / d.seri * 100).toFixed(0)}'i)`);
}
```

```
26 panel, 12 soru
bir soruya yanit veren panel 10, hicbir soruya yanit vermeyen 16
yanitlanan soru 10, panelsiz soru 2: hata bir bolgeye mi ozgu, hangi abone grubu etkilendi
bakis suresi (soru sikligiyla agirlikli gezilen panel) 13.0, en kotu 23
olay basina pano suresi 10.1 dk, pano acilisinda taranan seri 859

soru                           gezilen panel  yanit veren panel
uye etkileniyor mu                         6  hata orani (toplam)
hangi servis bozuk                        17  hata orani (servis)
gecikme hangi adimda                      11  adim suresi (servis)
trafik degisti mi                          5  istek sayisi
yeni dagitim var mi                       20  dagitim olaylari
kuyruk birikiyor mu                       14  kuyruk derinligi
yeniden denemeler artti mi                18  yeniden deneme sayisi
dis bagimlilik yavas mi                   23  bagimlilik gecikmesi
hata bir bolgeye mi ozgu                   -  yok
gecelik toplu is etkilendi mi             21  gecelik toplu is suresi
onbellek isabeti dustu mu                 15  onbellek isabet orani
hangi abone grubu etkilendi                -  yok

sus paneller (16): kume islemci kullanimi, kume bellek kullanimi, dugum disk doluluk, toplam istek (gunluk), surum bilgisi, kayit sayisi (bugun), p95 gecikme (toplam), p95 gecikme (servis), istemci surum dagilimi, dugum sayisi, cop toplama suresi, ag trafigi, saatlik okuma sayisi, hata orani (bolge), sayac tipi dagilimi, islemci (tek dugum)
sus panellerin taradigi seri 814 (toplamin %95'i)
```

Yirmi altı panelin onu bir soruya yanıt veriyor, on altısı hiçbirine. Bu on altı panel yanlış
değil — küme işlemcisi, düğüm belleği, istemci sürüm dağılımı hepsi doğru sayıları çiziyor. Ama
işletimin bu soru kümesinde bir karşılıkları yok, dolayısıyla olay sırasında bakan kişi için
**gezilecek yol**durlar.

Bedelleri de yalnız yer kaplamak değil: pano açıldığında taranan 859 serinin 814'ü, yani yüzde
95'i, hiçbir soruya yanıt vermeyen panellerden geliyor. Sorgu maliyetinin neredeyse tamamı
karşılıksız. Oranın bu kadar yüksek olmasının nedeni de okunabilir: düğüm kırılımlı paneller yüz
yirmişer seri tarıyor, servis kırılımlı paneller beşer. Kırılımın inceliği panelin görsel
büyüklüğüne yansımaz, sorgu maliyetine yansır.

"Süs" nitelemesi mutlak değildir, **soru kümesine görelidir.** Küme işlemcisi ve düğüm belleği
panelleri kapasite sorularının tam karşılığıdır; buradaki denetim kapasiteyi değil olay sırasında
sorulanları ölçüyor. Bu yüzden bu paneller silinmez, ayrı bir panoya taşınır — ve o panonun kendi
denetimi kendi soru kümesiyle yapılır. Aynı ayrım panodaki iki işlemci panelinin niye yan yana
durduğunu da açıklıyor: biri küme, öteki tek düğüm için eklenmiş, ikisi de aynı soruyu yanıtlıyor
ve olay panosunda ikisinin de karşılığı yok.

İki soru panelsiz. Bölge kırılımı sorusunun panelsiz kalması ilk bakışta şaşırtıcı, çünkü panoda
bölge kırılımlı bir hata oranı paneli var — ama beş dakikalık çözünürlükle çiziliyor ve soru bir
dakikalık pencere istiyor. Panel var, yanıt yok. İkinci panelsiz soru başka bir yere bağlanıyor:
abone grubu boyutu hiç toplanmamış, dolayısıyla o soru pano düzeniyle değil ancak
enstrümantasyonla açılabilir.

Bakış süresi bu düzende 13,0 panel. Yani bir soruya yanıt bulmak için, sorunun sıklığıyla
ağırlıklandırıldığında, ortalama on üç panel gözle taranıyor; en kötü soruda yirmi üç. Panel başına
sekiz saniyeyle bu, olay başına 10,1 dakika eder.

#### Yeniden Düzen

Düzenleme dört adımda yapılır ve her adımdan sonra aynı denetim yeniden koşar.

```js
// pano/duzen.mjs — panonun soru kumesine gore yeniden duzenlenmesi. Dort asama sirayla uygulanir
// ve her asamada ayni denetim yeniden kosar. IG16: sus paneller silinmez, olay panosundan
// cikarilip kapasite panosuna tasinir; bedeli o panonun kendi seri taramasidir.
import { PANEL, SORU, denetle, yanitlar, OLAY, SORGU_DK } from "./pano.mjs";
const kopya = PANEL.map((p) => [...p]);
const cozunurluk = kopya.map((p) => (p[0] === "hata orani (bolge)" ? [p[0], p[1], p[2], 60, p[4]] : p));
const ayiklanmis = cozunurluk.filter((p) => SORU.some((s) => yanitlar(p, s)));
// Duzen kurali: sorular siklik sirasinda gezilir, her sorunun yanitini veren ilk yerlesmemis
// panel siraya konur; artakalanlar sonuna eklenir.
const dizili = [];
for (const s of SORU) { const p = ayiklanmis.find((x) => yanitlar(x, s) && !dizili.includes(x));
  if (p) dizili.push(p); }
for (const p of ayiklanmis) if (!dizili.includes(p)) dizili.push(p);
const ASAMA = [["once", kopya], ["cozunurluk duzeltmesi", cozunurluk],
  ["sus paneller ayrildi", ayiklanmis], ["soru sirasina dizildi", dizili]];

console.log(`${"asama".padEnd(24)}${"panel".padStart(7)}${"sus".padStart(5)}${"yanitlanan".padStart(12)}` +
  `${"panelsiz".padStart(10)}${"bakis".padStart(8)}${"olay/dk".padStart(9)}${"seri".padStart(7)}`);
const sonuc = ASAMA.map(([ad, p]) => {
  const d = denetle(p);
  console.log(`${ad.padEnd(24)}${String(d.panel).padStart(7)}${String(d.sus).padStart(5)}` +
    `${String(d.yanitlanan).padStart(12)}${String(d.panelsiz.length).padStart(10)}` +
    `${d.bakis.toFixed(1).padStart(8)}${d.dk.toFixed(1).padStart(9)}${String(d.seri).padStart(7)}`);
  return d;
});
const [ilk, son] = [sonuc[0], sonuc[3]];
console.log(`\n${"soru".padEnd(30)}${"once".padStart(6)}${"sonra".padStart(7)}`);
SORU.forEach((s, i) => console.log(`${s[0].padEnd(30)}${(ilk.bulus[i] || "-").toString().padStart(6)}` +
  `${(son.bulus[i] || "-").toString().padStart(7)}`));
console.log(`\nbakis suresi ${ilk.bakis.toFixed(1)} panelden ${son.bakis.toFixed(1)} panele, ` +
  `olay basina pano suresi ${ilk.dk.toFixed(1)} dk'dan ${son.dk.toFixed(1)} dk'ya indi`);
console.log(`kirk olayda kazanilan ${((ilk.dk - son.dk) * OLAY).toFixed(0)} dakika; ` +
  `taranan seri ${ilk.seri} yerine ${son.seri}`);
const kalan = SORU.filter((s) => !dizili.some((p) => yanitlar(p, s)));
console.log(`hala panelsiz ${kalan.length} soru: ${kalan.map((s) => s[0]).join(", ")} — ` +
  `${kalan.reduce((a, s) => a + s[4], 0)} olayda ${kalan.reduce((a, s) => a + s[4] * SORGU_DK, 0)} dakika elle sorgu`);
```

```
asama                     panel  sus  yanitlanan  panelsiz   bakis  olay/dk   seri
once                         26   16          10         2    13.0     10.1    859
cozunurluk duzeltmesi        26   15          11         1    13.5     10.0    859
sus paneller ayrildi         11    0          11         1     4.8      3.8     75
soru sirasina dizildi        11    0          11         1     4.1      3.3     75

soru                            once  sonra
uye etkileniyor mu                 6      1
hangi servis bozuk                17      2
gecikme hangi adimda              11      3
trafik degisti mi                  5      4
yeni dagitim var mi               20      5
kuyruk birikiyor mu               14      6
yeniden denemeler artti mi        18      7
dis bagimlilik yavas mi           23      8
hata bir bolgeye mi ozgu           -      9
gecelik toplu is etkilendi mi     21     10
onbellek isabeti dustu mu         15     11
hangi abone grubu etkilendi        -      -

bakis suresi 13.0 panelden 4.1 panele, olay basina pano suresi 10.1 dk'dan 3.3 dk'ya indi
kirk olayda kazanilan 273 dakika; taranan seri 859 yerine 75
hala panelsiz 1 soru: hangi abone grubu etkilendi — 4 olayda 16 dakika elle sorgu
```

İlk adım tek bir panelin çözünürlüğünü düzeltiyor ve yanıtlanan soru sayısı 10'dan 11'e çıkıyor.
Dikkat çeken şey bakış süresinin bu adımda **artması**: 13,0'dan 13,5'e. Yeni yanıtlanan soru
panonun yirmi dördüncü sırasındaki bir panelde bulunuyor ve ortalamayı yukarı çekiyor. Bir soruyu
daha yanıtlamak, o yanıtın bulunabilir olduğu anlamına gelmiyor.

Asıl düşüş ikinci adımda. Hiçbir soruya yanıt vermeyen on beş panel olay panosundan çıkarılıp
kapasite panosuna taşınınca panel sayısı 26'dan 11'e, bakış süresi 13,5'ten 4,8'e, taranan seri
859'dan 75'e iniyor. Üçüncü adım panelleri soru sıklığı sırasına dizerek bakış süresini 4,1'e
indiriyor; artık her soru kendi sırasındaki panelde bulunuyor ve en sık sorulan soru ilk panelde.

Toplam kazanç olay başına 10,1 dakikadan 3,3 dakikaya düşen pano süresidir; kırk olayda 273
dakika. Bu sürenin tamamı olay uzunluğuna eklenen süredir — panelde gezinen kişi o sırada başka
bir şey yapmıyor.

Bakış süresinin panel sayısıyla ölçülmesi bir sadeleştirmedir: gerçekte kişi panoyu baştan sona
taramaz, bildiği yere atlar. Sadeleştirmenin tuttuğu şey oran: bilmeyen ya da uykudan kalkmış
birinin gezindiği panel sayısı, panonun düzeniyle doğru orantılıdır. Sayının kendisi değil, iki
düzen arasındaki üç kata yakın fark okunmalıdır.

#### Kalan Soru

Düzenden sonra panosuz kalan tek soru abone grubu kırılımıdır ve pano düzenlemesiyle kapanmaz.
Kırk olayın dördünde soruluyor, her seferinde elle sorgu yazmak gerekiyor ve dört dakika sürüyor:
kırk olayda 16 dakika. Bu sayı küçük görünür, ama sorunun yanıtlanma biçimi de önemlidir — elle
yazılan sorgunun sonucu panoya girmez, bir sonraki olayda aynı sorgu yeniden yazılır.

Denetimin çıkardığı üç sayı bir arada okunur. **Hiçbir soruyu yanıtlamayan veri maliyettir:**
panelin yüzde 62'si, sorgu maliyetinin yüzde 95'i. **Yanıtsız kalan soru risktir:** iki sorudan
biri yanlış çözünürlükle, öteki toplanmamış boyutla kapalıydı. **Yanıtın yeri de maliyettir:**
aynı veri, aynı paneller, yalnız sıra değişerek olay başına altı dakikadan fazla kazandırdı.

#### Özet

- Bir panel bir soruyu ancak üç koşul birden sağlarsa yanıtlar: aynı ölçüt, sorunun istediği boyut,
  sorunun istediği çözünürlük.
- Yirmi altı panelin 16'sı hiçbir soruya yanıt vermiyordu; bu paneller pano açılışında taranan 859
  serinin 814'ünü, yani sorgu maliyetinin yüzde 95'ini oluşturuyordu.
- On iki sorunun ikisi panelsizdi: biri yanlış çözünürlük (panel vardı, yanıt yoktu), öteki hiç
  toplanmamış boyut.
- Çözünürlük düzeltmesi yanıtlanan soruyu 11'e çıkardı ama bakış süresini 13,0'dan 13,5'e
  **yükseltti**; yanıtın var olması bulunabilir olması demek değil.
- Süs panellerin ayrılması ve panellerin soru sırasına dizilmesi bakış süresini 4,1 panele, olay
  başına pano süresini 10,1 dakikadan 3,3 dakikaya indirdi; kırk olayda 273 dakika.
- Bir panelin süs olması mutlak değil soru kümesine göredir: ayrılan paneller silinmez, kendi soru
  kümesi olan ayrı bir panoya taşınır.

#### Sonraki Adım

Düzenlenmiş bir pano yalnız bakıldığında işe yarar. Gecenin üçünde kimse bakmıyorsa on bir panelin
sıralaması bir şey değiştirmez; birinin çağrılması gerekir. Çağrıyı doğuran kural ise tek biçimde
yazılmaz: bir eşik aşıldığında da çağrılabilir, bir oranın belirli bir pencerede belirli bir hızla
değişmesiyle de, geçmiş davranıştan öğrenilmiş bir bandın dışına çıkılmasıyla da. Üç kural türü
aynı olay kümesinde farklı olayları yakalar. Sonraki ders üçünü aynı bilinen olay dizisinde
koşturur ve yakalanan, kaçan, yanlış alarm sayılarıyla fark etme turunu karşılaştırır.

### Uyarı Kuralları

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/uyari-kurallari

Eşik, oran ve anomali temelli üç kural türünün aynı on günün aynı sekiz bilinen olayı üzerinde koşturulması: her türün parametresi taranarak yakalanan, kaçan, yanlış alarm ve fark etme turu sayılır, üç türün birbirini tamamladığı yer kural kümesi birleşimleriyle ölçülür.

Düzenlenmiş bir pano yalnız bakıldığında işe yarar. Gecenin üçünde kimse bakmıyorsa panelin
sıralaması bir şey değiştirmez; birinin çağrılması gerekir. Çağrıyı doğuran kuralın hangi ölçütten
yazılacağı — bileşenin iç ölçütünden mi, üyenin gördüğü ölçütten mi — ayrı bir derste ölçüldü ve
burada tekrarlanmaz. Buradaki soru kuralın **biçimi**: aynı ölçüt üzerinde üç ayrı kural türü
yazılabilir ve üçü aynı olayları yakalamaz.

**Eşik kuralı** değeri sabit bir sınırla karşılaştırır. **Oran kuralı** değerin bir pencere
öncesine göre değişim hızına bakar. **Anomali kuralı** geçmişten öğrenilmiş bir bandın dışına
çıkışı arar. Üçü de bölgesel ölçüm ağının (kurgu) on günlük iki ölçüt serisi ve sekiz bilinen olayı
üzerinde koşturulur.

#### On Gün, Sekiz Olay

```js
// uyari/seri.mjs — on gunluk dakikalik iki olcut serisinin ve sekiz bilinen olayin MODELI.
// IG19: istek sayisi gunluk desen tasir (gece dusuk, ogleden sonra zirve); hata orani desensizdir.
// IG20: her iki seride zararsiz kisa sivrilar vardir (bes bin dakikada bir, 2-4 dk).
// IG21: sekiz olay bilinen olaydir; pencereleri ve hedef degerleri asagida yazilidir.
export const TOHUM = 20260804, GUN = 10, DK = GUN * 1440;
export const SAAT_DESEN = [40, 32, 28, 26, 30, 48, 78, 118, 150, 168, 176, 172,
  165, 170, 178, 174, 160, 138, 120, 104, 92, 78, 62, 50];
// [gun, saat, sure dk, ad, [[seri, hedef deger, bicim]]] — bicim: "ani" ya da "tirmanma"
export const OLAY = [
  [2, 11, 20, "ani hata sicramasi", [["hata", 6.0, "ani"]]],
  [3, 9, 300, "yavas hata tirmanmasi", [["hata", 1.4, "tirmanma"]]],
  [4, 3, 90, "gece trafik kaybi", [["istek", 8, "ani"]]],
  [5, 14, 4, "kisa derin kesinti", [["hata", 9.0, "ani"]]],
  [6, 8, 600, "sabit kayma", [["hata", 0.9, "ani"]]],
  [7, 16, 45, "yayin sonrasi artis", [["hata", 2.6, "ani"]]],
  [8, 1, 300, "gece istek tirmanmasi", [["istek", 110, "tirmanma"]]],
  [9, 6, 360, "kademeli trafik dususu", [["istek", 0.45, "tirmanma"]]],
];
export const pencere = (i) => [OLAY[i][0] * 1440 + OLAY[i][1] * 60, OLAY[i][2]];

export function seri() {
  let s = TOHUM;
  const r = () => ((s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32);
  const S = { istek: new Float64Array(DK), hata: new Float64Array(DK) };
  const sivri = { istek: 0, hata: 0 };
  for (let t = 0; t < DK; t += 1) {
    const saat = Math.floor(t / 60) % 24, taban = SAAT_DESEN[saat];
    S.istek[t] = taban * (0.94 + r() * 0.12);
    S.hata[t] = 0.2 + (r() * 2 - 1) * 0.08;
    for (const ad of ["istek", "hata"]) {
      if (sivri[ad] > 0) { sivri[ad] -= 1; S[ad][t] *= ad === "hata" ? 4.2 : 1.35; }
      else if (r() < 1 / 5000) sivri[ad] = 2 + Math.floor(r() * 3);
    }
    for (let i = 0; i < OLAY.length; i += 1) {
      const [bas, sr] = pencere(i);
      if (t < bas || t >= bas + sr) continue;
      for (const [ad, hedef, bicim] of OLAY[i][4]) {
        const p = bicim === "tirmanma" ? (t - bas + 1) / sr : Math.min(1, (t - bas + 1) / 3);
        const taban2 = ad === "istek" ? SAAT_DESEN[saat] : 0.2;
        const h = ad === "istek" && hedef < 1 ? taban2 * hedef : hedef;
        S[ad][t] = taban2 + (h - taban2) * p;
      }
    }
  }
  return S;
}

if (import.meta.filename === process.argv[1]) {
  const S = seri();
  const ort = (a, b, ad) => { let x = 0; for (let t = a; t < b; t += 1) x += S[ad][t]; return x / (b - a); };
  console.log(`tohum ${TOHUM}, ${GUN} gun, ${DK} dakika, 2 olcut, ${OLAY.length} bilinen olay`);
  console.log(`taban: gece hata ${ort(0, 1440, "hata").toFixed(2)}, istek ` +
    `${ort(180, 300, "istek").toFixed(0)}/dk (03-05), ogleden sonra istek ` +
    `${ort(840, 960, "istek").toFixed(0)}/dk (14-16)\n`);
  console.log(`${"olay".padEnd(24)}${"gun".padStart(4)}${"sure".padStart(7)}` +
    `${"olay ici en uc deger".padStart(21)}`);
  OLAY.forEach(([gun, , sr, ad, hedefler], i) => {
    const [b] = pencere(i), a = hedefler[0][0];
    let uc = S[a][b];
    for (let t = b; t < b + sr; t += 1) uc = a === "hata" || hedefler[0][1] > 100
      ? Math.max(uc, S[a][t]) : Math.min(uc, S[a][t]);
    console.log(`${ad.padEnd(24)}${String(gun).padStart(4)}${`${sr} dk`.padStart(7)}` +
      `${`${a} ${uc.toFixed(a === "hata" ? 2 : 0)}`.padStart(21)}`);
  });
}
```

```
tohum 20260804, 10 gun, 14400 dakika, 2 olcut, 8 bilinen olay
taban: gece hata 0.20, istek 28/dk (03-05), ogleden sonra istek 176/dk (14-16)

olay                     gun   sure olay ici en uc deger
ani hata sicramasi         2  20 dk            hata 6.00
yavas hata tirmanmasi      3 300 dk            hata 1.40
gece trafik kaybi          4  90 dk              istek 8
kisa derin kesinti         5   4 dk            hata 9.00
sabit kayma                6 600 dk            hata 0.90
yayin sonrasi artis        7  45 dk            hata 2.60
gece istek tirmanmasi      8 300 dk            istek 110
kademeli trafik dususu     9 360 dk             istek 71
```

Olay kümesi kasıtlı olarak farklı biçimlerden seçildi: yirmi dakikalık ani sıçrama, beş saate yayılan
yavaş tırmanma, dört dakikalık derin kesinti, on saat süren sabit kayma ve iki tanesi mevsimsel
ölçüt üzerinde — gece trafiğin düşmesi ve gece isteğin tırmanması. Sonuncusu, kademeli trafik
düşüşü, mutlak değer olarak hiçbir zaman düşük görünmüyor: 176'lık öğleden sonra tabanına göre
düşüyor ama sayı 71'in altına inmiyor.

#### Üç Tarama

Her tür tek bir parametreyle taranır. Seçim kuralı kodda yazılı: on günde en çok on iki yanlış
alarm bütçesini aşmayan parametreler arasından en çok olay yakalayan seçilir.

```js
// uyari/kural.mjs — uc kural turu ayni on gunun ayni iki serisi uzerinde kosturulur. IG22: bir
// kural kosulu K tur (dakika) ust uste saglandiginda bir uyari uretir ve kosul dusene kadar
// yeniden uretmez; degerlendirme her dakika bir tur koser. IG23: esik medyanin kati olarak
// yazilir; oran kurali W dakika oncesine gore iki kat artis ya da yariya dususe bakar; anomali
// kurali ayni dakika-of-day icin onceki L gunun bandini kullanir (ortalama arti dort sapma, band
// tabani ortalamanin yuzde 15'i). IG24: on gunde en cok 12 yanlis alarm butcesi vardir ve her tur
// icin bu butceyi asmayan parametreler arasindan en cok olay yakalayan secilir.
import { seri, OLAY, pencere, DK } from "./seri.mjs";
const S = seri(), OLCUT = ["hata", "istek"], K = { esik: 5, oran: 3, anomali: 10 }, BUTCE = 12;
const medyan = Object.fromEntries(OLCUT.map((a) =>
  [a, [...S[a]].sort((x, y) => x - y)[Math.floor(DK / 2)]]));

const kosullar = {
  esik: (k) => (a, t) => (a === "hata" ? S[a][t] > k * medyan[a]
    : S[a][t] > k * medyan[a] || S[a][t] < medyan[a] / k),
  oran: (w) => (a, t) => { if (t < w) return false;
    const o = S[a][t] / Math.max(1e-9, S[a][t - w]); return o > 2 || o < 0.5; },
  anomali: (l) => (a, t) => { const g = Math.min(l, Math.floor(t / 1440));
    if (g < 1) return false;
    const ge = []; for (let j = 1; j <= g; j += 1) ge.push(S[a][t - j * 1440]);
    const m = ge.reduce((x, y) => x + y, 0) / g;
    const sd = Math.sqrt(ge.reduce((x, y) => x + (y - m) ** 2, 0) / g);
    return Math.abs(S[a][t] - m) > 4 * Math.max(sd, 0.15 * m); },
};

function kosr(tur, p) {
  const uyari = [];
  const kosul = kosullar[tur](p);
  for (const a of OLCUT) {
    let ard = 0, etkin = false;
    for (let t = 0; t < DK; t += 1) {
      if (kosul(a, t)) { ard += 1; if (ard >= K[tur] && !etkin) { etkin = true; uyari.push([t - K[tur] + 1, a]); } }
      else { ard = 0; etkin = false; }
    }
  }
  const ici = (t) => OLAY.findIndex((o, i) => t >= pencere(i)[0] && t < pencere(i)[0] + o[2]);
  const yakalanan = new Map();
  for (const [t] of uyari) { const i = ici(t);
    if (i >= 0 && !yakalanan.has(i)) yakalanan.set(i, t - pencere(i)[0]); }
  const yanlis = uyari.filter(([t]) => ici(t) < 0).length;
  const turlar = [...yakalanan.values()];
  return { p, uyari: uyari.length, yakalanan, kacan: OLAY.length - yakalanan.size, yanlis,
    tur: turlar.length ? turlar.reduce((a, b) => a + b, 0) / turlar.length : null };
}

const TARAMA = { esik: [2, 3, 5, 8], oran: [10, 30, 60, 180], anomali: [1, 3, 7] };
const BASLIK = { esik: "esik (medyan kati)", oran: "oran penceresi (dk)", anomali: "ogrenme penceresi (gun)" };
const secim = {};
for (const tur of Object.keys(TARAMA)) {
  console.log(`${BASLIK[tur].padEnd(24)}${"uyari".padStart(7)}${"yakalanan".padStart(11)}` +
    `${"kacan".padStart(7)}${"yanlis alarm".padStart(14)}${"fark etme turu".padStart(16)}`);
  const satir = TARAMA[tur].map((p) => kosr(tur, p));
  for (const d of satir) console.log(`${String(d.p).padEnd(24)}${String(d.uyari).padStart(7)}` +
    `${`${d.yakalanan.size}/${OLAY.length}`.padStart(11)}${String(d.kacan).padStart(7)}` +
    `${String(d.yanlis).padStart(14)}${(d.tur === null ? "-" : `${d.tur.toFixed(0)} tur`).padStart(16)}`);
  const uygun = satir.filter((d) => d.yanlis <= BUTCE);
  secim[tur] = (uygun.length ? uygun : satir).slice()
    .sort((a, b) => b.yakalanan.size - a.yakalanan.size || a.yanlis - b.yanlis)[0];
  console.log(`secilen: ${secim[tur].p}\n`);
}

const T = Object.keys(TARAMA);
console.log(`${"olay".padEnd(24)}${T.map((t) => t.padStart(12)).join("")}  yalniz`);
const yalniz = [];
OLAY.forEach((o, i) => {
  const h = T.map((t) => secim[t].yakalanan.get(i));
  const kac = h.filter((x) => x !== undefined).length;
  if (kac === 1) yalniz.push([o[3], T[h.findIndex((x) => x !== undefined)]]);
  console.log(`${o[3].padEnd(24)}${h.map((x) => (x === undefined ? "-" : `${x} tur`).padStart(12)).join("")}` +
    `  ${kac === 1 ? T[h.findIndex((x) => x !== undefined)] : kac === 0 ? "hicbiri" : ""}`);
});
const birlesim = new Set(T.flatMap((t) => [...secim[t].yakalanan.keys()]));
console.log(`\nucu birlikte ${birlesim.size}/${OLAY.length} olay, toplam yanlis alarm ` +
  `${T.reduce((a, t) => a + secim[t].yanlis, 0)}, toplam uyari ${T.reduce((a, t) => a + secim[t].uyari, 0)}`);
console.log(`yalniz tek turle yakalanan ${yalniz.length} olay: ` +
  `${yalniz.map(([a, t]) => `${a} (${t})`).join(", ")}`);
const KUME = [["esik"], ["oran"], ["anomali"], ["esik", "anomali"], ["esik", "oran"],
  ["oran", "anomali"], ["esik", "oran", "anomali"]];
console.log(`\n${"kural kumesi".padEnd(24)}${"kapsanan olay".padStart(14)}${"yanlis alarm".padStart(14)}` +
  `${"uyari".padStart(7)}`);
for (const k of KUME) {
  const kaps = new Set(k.flatMap((t) => [...secim[t].yakalanan.keys()]));
  console.log(`${k.join("+").padEnd(24)}${`${kaps.size}/${OLAY.length}`.padStart(14)}` +
    `${String(k.reduce((a, t) => a + secim[t].yanlis, 0)).padStart(14)}` +
    `${String(k.reduce((a, t) => a + secim[t].uyari, 0)).padStart(7)}`);
}
```

```
esik (medyan kati)        uyari  yakalanan  kacan  yanlis alarm  fark etme turu
2                            15        4/8      4            11          13 tur
3                            14        5/8      3             9          21 tur
5                             4        4/8      4             0          52 tur
8                             3        3/8      5             0           1 tur
secilen: 3

oran penceresi (dk)       uyari  yakalanan  kacan  yanlis alarm  fark etme turu
10                           18        5/8      3            13           1 tur
30                           18        5/8      3            13           0 tur
60                           19        6/8      2            12           8 tur
180                          74        8/8      0            57          29 tur
secilen: 60

ogrenme penceresi (gun)   uyari  yakalanan  kacan  yanlis alarm  fark etme turu
1                            12        6/8      2             6          21 tur
3                             8        6/8      2             0          22 tur
7                             9        6/8      2             0          22 tur
secilen: 3

olay                            esik        oran     anomali  yalniz
ani hata sicramasi             0 tur       0 tur       0 tur  
yavas hata tirmanmasi        104 tur      48 tur      58 tur  
gece trafik kaybi                  -       1 tur       2 tur  
kisa derin kesinti                 -       0 tur           -  oran
sabit kayma                    1 tur       1 tur       0 tur  
yayin sonrasi artis            0 tur       0 tur       2 tur  
gece istek tirmanmasi          0 tur           -      68 tur  
kademeli trafik dususu             -           -           -  hicbiri

ucu birlikte 7/8 olay, toplam yanlis alarm 21, toplam uyari 41
yalniz tek turle yakalanan 1 olay: kisa derin kesinti (oran)

kural kumesi             kapsanan olay  yanlis alarm  uyari
esik                               5/8             9     14
oran                               6/8            12     19
anomali                            6/8             0      8
esik+anomali                       6/8             9     22
esik+oran                          7/8            21     33
oran+anomali                       7/8            12     27
esik+oran+anomali                  7/8            21     41
```

Taramaların her biri kendi ödünleşimini gösteriyor. **Eşik** sıkılaştıkça yanlış alarm sıfıra
iniyor (medyanın beş katında 0 yanlış alarm) ama yakalanan olay da düşüyor ve fark etme turu 52'ye
çıkıyor. Sekiz katlık eşiğin ortalama fark etme turu 1'dir; bu sayı kuralın hızlı olmasından değil,
**yalnız hızlı olayları yakalamasından** gelir — ortalama yalnız yakalanan olaylar üzerinden
alınıyor.

**Oran** kuralında pencere büyüdükçe kapsam artıyor: 180 dakikalık pencere sekiz olayın sekizini
yakalıyor. Bedeli 57 yanlış alarm, çünkü mevsimsel ölçütte sabah yükselişi de üç saat öncesine göre
iki katı aşıyor. Pencere seçimi burada olay biçimi ile günlük desen arasındaki bir uzlaşmadır.

**Anomali** kuralında öğrenme penceresi bir gün olduğunda band tek bir güne dayanıyor, dolayısıyla
dar kalıyor ve altı yanlış alarm üretiyor. Üç güne çıkınca yanlış alarm sıfırlanıyor ve kapsam
düşmüyor. Yedi gün üç günden daha iyi değil; öğrenme penceresini uzatmanın getirisi üçüncü günden
sonra tükeniyor.

#### Tamamlayıcılık

Olay tablosu üç türün aynı olaylarda farklı davrandığını gösteriyor. Ani sıçramayı üçü de sıfırıncı
turda yakalıyor. Yavaş tırmanmada eşik 104. turda, oran 48. turda, anomali 58. turda çalıyor — eşik
kuralı olayın sonuna doğru geliyor, çünkü değer eşiği ancak o zaman aşıyor. Dört dakikalık derin
kesintiyi **yalnız oran kuralı** yakalıyor: olay eşiğin üstüne çıkıyor ama beş dakikalık ardışıklık
koşulunu doldurmadan bitiyor, oran kuralının üç turluk koşulu ise doluyor.

Kural kümesi tablosu asıl kararı taşıyor. Anomali tek başına sekiz olayın altısını **sıfır yanlış
alarmla** yakalıyor. Eşik kuralı bu kümeye eklendiğinde kapsam değişmiyor — eşiğin yakaladığı beş
olayın hepsi zaten anomali tarafından yakalanıyor — ama dokuz yanlış alarm ekliyor. Oran kuralı
eklendiğinde kapsam altıdan yediye çıkıyor: kazanılan tek olay dört dakikalık derin kesinti, bedeli
on iki yanlış alarm. Bir olay daha yakalamak on iki yanlış alarm ediyor ve bu, bir sonraki dersin
konusudur.

Sekizinci olay üç türün hiçbiriyle yakalanmıyor. Kademeli trafik düşüşü mutlak eşiğin altına hiç
inmiyor, saatlik değişimi iki katı bulmuyor ve öğrenilmiş bandın alt sınırını aşacak kadar
sapmıyor. Yanıtsız kalan sorunun bedeli burada altı saatlik bir düşüşün fark edilmemesidir; bu
olayın görülmesi kural türü değiştirmekle değil, ölçütü değiştirmekle olur — mutlak istek sayısı
yerine günlük desene göre normalleştirilmiş bir oran.

#### Özet

- Üç kural türü aynı ölçüt üzerinde farklı olayları yakalar: eşik değere, oran değişim hızına,
  anomali öğrenilmiş banda bakar.
- Parametre taraması her türde bir ödünleşim gösterdi: eşik sıkılaştıkça yanlış alarm sıfırlanıyor
  ama fark etme turu 52'ye çıkıyor; oran penceresi 180 dakikaya çıkınca kapsam 8/8 oluyor ama
  yanlış alarm 57'ye fırlıyor.
- Anomali kuralının öğrenme penceresini bir günden üç güne çıkarmak yanlış alarmı 6'dan 0'a
  indirdi; yedi güne çıkarmanın ek getirisi olmadı.
- Dört dakikalık derin kesintiyi yalnız oran kuralı yakaladı; ardışıklık koşulu olay süresinden
  uzun olduğu için eşik ve anomali kaçırdı.
- Anomali tek başına 6/8 olayı sıfır yanlış alarmla yakalıyor; eşik eklemek kapsamı değiştirmeden
  dokuz yanlış alarm, oran eklemek bir olay karşılığında on iki yanlış alarm getiriyor.
- Sekizinci olay hiçbir türle yakalanmadı: eksik olan kural türü değil, ölçütün kendisi.

#### Sonraki Adım

Bu dersin üç kuralı birlikte koşturulduğunda on günde 41 uyarı üretti ve bunların 21'i hiçbir olaya
denk gelmedi. Sayılar kâğıt üzerinde küçük görünür; ama bu uyarılar bir listeye değil, bir kişiye
gider. Aynı olay birden çok kuralı birden çaldırdığında o kişi aynı şey için üç kez uyarılır, gece
yarısı gelen dördüncü uyarıda okumadan kapatır ve okunmadan kapatılan uyarıların içinde gerçek bir
olay olduğunda kimse fark etmez. Sonraki ders bir dönem boyunca üretilen uyarılara gruplama,
susturma ve bağımlılık bastırma uygulayıp kişi başına uyarı sayısını, eyleme dönen uyarı oranını ve
bastırmanın kaçırdığı gerçek olayı sayar.

### Uyarı Yorgunluğu

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/uyari-yorgunlugu

Otuz günlük uyarı akışına gruplama, susturma ve bağımlılık bastırma uygulanması: kişi başına uyarı sayısının, eyleme dönen uyarı oranının ve okunmadan kapatılan gerçek olayların sayılması, bastırma penceresinin taranarak bastırmanın kaçırdığı olayın ölçülmesi.

Önceki dersin üç kuralı on günde 41 uyarı üretti ve bunların 21'i hiçbir olaya denk gelmedi. Bir
sistemde üç kural yoktur; her servis için birkaç kural vardır ve hepsi aynı kişiye bağlanır. Bu
ders otuz günlük bir uyarı akışını baştan sona kurar, üç süzgeci sırayla uygular ve her aşamada
aynı üç sayıyı ölçer: kişiye kaç bildirim gidiyor, bunların kaçı bir işe dönüşüyor ve kaç gerçek
olay o kişiye ulaşmadan kayboluyor.

Akış bölgesel ölçüm ağının (kurgu) altı servisinden ve on dört kuralından doğuyor; servislerin
altında ortak bir veri deposu duruyor ve olayların bir kısmı oradan yukarı yayılıyor.

Uyarı yorgunluğu bir ruh hâli değil, ölçülebilir bir eşiktir: bir kişinin yirmi dört saatte aldığı
uyarı sayısı arttıkça yanıt süresi uzar ve belirli bir sayıdan sonra uyarılar okunmadan kapatılır.
Bu dersteki model o eğriyi varsayım olarak alır ve sonucunu sayar.

#### Otuz Günlük Akış

```js
// yorgunluk/akis.mjs — otuz gunluk uyari akisinin MODELI. IG25: alti servis ve aralarindaki
// bagimlilik kurgudur; veri deposu ucunun altinda dort servis vardir. IG26: yirmi gercek olay
// bilinen olaydir; olay servisinde 1-3 kural, ona bagli her serviste 1-2 turev kural calar.
// IG27: on dort kuraldan uc tanesi gurultucudur ve olaydan bagimsiz uyari uretir.
export const TOHUM = 20260805, GUN = 30, NOBETCI = 2;
export const BAGIMLILIK = { gecit: ["okuma", "fatura"], okuma: ["depo"], dogrulama: ["depo"],
  fatura: ["isemri", "depo"], isemri: ["depo"], depo: [] };
export const SERVIS = Object.keys(BAGIMLILIK);
export const KURAL = SERVIS.flatMap((s) => [`${s}.hata_orani`, `${s}.gecikme`])
  .concat(["depo.baglanti", "depo.disk"]);
export const GURULTUCU = ["gecit.gecikme", "depo.baglanti", "isemri.gecikme"];
// Bir servisin ustunde duran servisler: o servis bozulunca bunlar da uyarir.
export const ustler = (s) => SERVIS.filter((u) => BAGIMLILIK[u].includes(s));

export function akis() {
  let s = TOHUM;
  const r = () => ((s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32);
  const dk = GUN * 1440, olay = [], uyari = [];
  for (let i = 0; i < 20; i += 1) {
    const t = Math.floor(r() * dk), servis = SERVIS[Math.floor(r() * SERVIS.length)];
    olay.push({ id: i, t, servis, sure: 30 + Math.floor(r() * 150) });
  }
  olay.sort((a, b) => a.t - b.t).forEach((o, i) => { o.id = i; });
  for (const o of olay) {
    const kendi = KURAL.filter((k) => k.startsWith(`${o.servis}.`));
    for (const k of kendi.slice(0, 1 + Math.floor(r() * kendi.length)))
      uyari.push({ t: o.t + Math.floor(r() * 8), kural: k, servis: o.servis, olay: o.id, turev: false });
    for (const u of ustler(o.servis)) {                       // kaskad: ust servisler de calar
      const ku = KURAL.filter((k) => k.startsWith(`${u}.`));
      for (const k of ku.slice(0, 1 + Math.floor(r() * 2)))
        uyari.push({ t: o.t + 2 + Math.floor(r() * 12), kural: k, servis: u, olay: o.id, turev: true });
    }
  }
  for (const k of KURAL) {                                     // olaydan bagimsiz gurultu
    const n = GURULTUCU.includes(k) ? 40 + Math.floor(r() * 30) : 2 + Math.floor(r() * 6);
    for (let i = 0; i < n; i += 1)
      uyari.push({ t: Math.floor(r() * dk), kural: k, servis: k.split(".")[0], olay: null, turev: false });
  }
  uyari.sort((a, b) => a.t - b.t);
  return { olay, uyari };
}

if (import.meta.filename === process.argv[1]) {
  const { olay, uyari } = akis();
  const gercek = uyari.filter((u) => u.olay !== null);
  console.log(`tohum ${TOHUM}, ${GUN} gun, ${KURAL.length} kural, ${SERVIS.length} servis, ` +
    `${olay.length} gercek olay, ${uyari.length} ham uyari`);
  console.log(`olaya bagli uyari ${gercek.length} (${gercek.filter((u) => u.turev).length} turev), ` +
    `olaydan bagimsiz ${uyari.length - gercek.length}`);
  console.log(`gunde ${(uyari.length / GUN).toFixed(1)} uyari, nobetci basina ` +
    `${(uyari.length / GUN / NOBETCI).toFixed(1)}\n`);
  const say = new Map();
  for (const u of uyari) say.set(u.kural, (say.get(u.kural) || 0) + 1);
  console.log(`${"en cok uyaran kural".padEnd(22)}${"uyari".padStart(7)}${"olayli".padStart(8)}`);
  [...say].sort((a, b) => b[1] - a[1]).slice(0, 5).forEach(([k, n]) =>
    console.log(`${k.padEnd(22)}${String(n).padStart(7)}` +
      `${String(uyari.filter((u) => u.kural === k && u.olay !== null).length).padStart(8)}`));
}
```

```
tohum 20260805, 30 gun, 14 kural, 6 servis, 20 gercek olay, 268 ham uyari
olaya bagli uyari 56 (26 turev), olaydan bagimsiz 212
gunde 8.9 uyari, nobetci basina 4.5

en cok uyaran kural     uyari  olayli
isemri.gecikme             70       2
gecit.gecikme              58       3
depo.baglanti              40       0
gecit.hata_orani           16       9
fatura.hata_orani          13       9
```

Otuz günde 268 uyarı üretildi; günde 8,9. Bunların 212'si hiçbir olaya bağlı değil ve 56'sı yirmi
gerçek olaydan doğdu — 56'nın 26'sı **türev**, yani olayın kendisinde değil, ona bağlı bir üst
serviste doğan uyarı. Veri deposu ucunun altında dört servis olduğu için depoya değen her olay
dörde kadar servisten uyarı üretiyor.

En çok uyaran kural listesi ikinci bir ayrımı gösteriyor: iş emri gecikme kuralı otuz günde 70
uyarı üretti ve bunların yalnız ikisi bir olaya denk geldi. Geçit hata oranı kuralı 16 uyarı
üretti, dokuzu olaylı. Kural sayısı değil, **kural başına boş uyarı** sayılır.

#### Üç Süzgeç

Süzgeçler sırayla uygulanır: aynı servisteki yakın uyarılar tek bildirimde toplanır, kısa sürede
çok uyarı üreten kural geçici olarak susturulur ve bir servisin bağımlılığı zaten uyarıyorsa o
servisin uyarısı bastırılır.

Ölçümdeki "eyleme dönen bildirim" dar tanımlıdır: bir bildirim ancak gerçek bir olaya bağlıysa
**ve** o olay için okunan ilk bildirimse eyleme dönmüş sayılır. Aynı olayın ikinci uyarısı bir iş
tanımlamaz, çünkü iş zaten başlamıştır; olaysız uyarı da bir iş tanımlamaz. Bu tanım oranı düşük
gösterir, ama kişinin gerçekten yaptığı işi sayar.

```js
// yorgunluk/suzge.mjs — ham uyari akisina uc suzgec sirayla uygulanir ve her asamada ayni olcumler
// yeniden alinir. IG28: yanit suresi tabani 4 dk; nobetcinin son 24 saatte aldigi her uyari icin
// yuzde 18 uzar; son 24 saatteki dokuzuncu ve sonraki uyarilar okunmadan kapatilir.
// IG29: gruplama penceresi 15 dk (ayni servis), susturma esigi son 24 saatte 3 uyari (ayni kural),
// bagimlilik bastirma penceresi 20 dk. IG30: nobet iki kisi arasinda on beser gunluk donusumle
// paylasilir.
import { akis, BAGIMLILIK, GUN, NOBETCI, TOHUM } from "./akis.mjs";
const { olay, uyari } = akis();
const TABAN = 4, ARTIS = 0.18, KOR = 9, PENCERE = { grup: 15, sustur: 3, bagimlilik: 45 };

const yorgunlukEsigi = Math.ceil(1 + 1 / ARTIS);   // yanit suresinin iki katina ciktigi sira

const gruplama = (U) => U.filter((u, i) => !U.some((v, j) =>
  j < i && v.servis === u.servis && u.t - v.t <= PENCERE.grup));
const susturma = (U) => U.filter((u) =>
  U.filter((v) => v.kural === u.kural && v.t <= u.t && u.t - v.t < 1440).length <= PENCERE.sustur);
// Bastirma nedensel: once bagimlilik uyardiysa, ustteki servisin uyarisi bastirilir.
const bastirma = (U) => U.filter((u) => !U.some((v) =>
  BAGIMLILIK[u.servis].includes(v.servis) && v.t <= u.t && u.t - v.t <= PENCERE.bagimlilik));

function olc(U) {
  const gorulen = new Set(), sure = [], siralar = [], teslim = new Set(U.map((u) => u.olay));
  let eyleme = 0, korlenen = 0;   // sure: gorulen olayin ilk okunan bildiriminin yanit suresi
  for (let i = 0; i < U.length; i += 1) {
    const u = U[i];
    const sira = U.filter((v, j) => j <= i && u.t - v.t < 1440).length;
    siralar.push(sira);
    if (sira >= KOR) { korlenen += 1; continue; }        // okunmadan kapatildi
    if (u.olay !== null && !gorulen.has(u.olay)) {
      gorulen.add(u.olay); eyleme += 1; sure.push(TABAN * (1 + ARTIS * (sira - 1))); }
  }
  const ort = (x) => (x.length ? x.reduce((a, b) => a + b, 0) / x.length : 0);
  const teslimsiz = olay.filter((o) => !teslim.has(o.id)).length;
  return { bildirim: U.length, kisi: U.length / GUN, eyleme: eyleme / U.length * 100,
    kapsanan: gorulen.size, teslimsiz, korOlay: olay.length - gorulen.size - teslimsiz,
    yanit: ort(sure), korlenen, yorgun: siralar.filter((x) => x >= yorgunlukEsigi).length / U.length * 100 };
}

const ASAMA = [["ham akis", uyari]];
ASAMA.push(["gruplama", gruplama(ASAMA[0][1])]);
ASAMA.push(["+ susturma", susturma(ASAMA[1][1])]);
ASAMA.push(["+ bagimlilik bastirma", bastirma(ASAMA[2][1])]);
console.log(`yorgunluk esigi: ${yorgunlukEsigi}. uyaridan sonra yanit suresi tabanin iki kati ` +
  `(${TABAN} dk -> ${(TABAN * (1 + ARTIS * (yorgunlukEsigi - 1))).toFixed(1)} dk)\n`);
console.log(`${"asama".padEnd(22)}${"bildirim".padStart(9)}${"gun".padStart(6)}${"eyleme donen".padStart(14)}` +
  `${"kapsanan".padStart(10)}${"teslimsiz".padStart(11)}${"korlenen".padStart(10)}` +
  `${"olay yaniti".padStart(12)}${"esik ustu".padStart(11)}`);
const sonuc = ASAMA.map(([ad, U]) => {
  const d = olc(U);
  console.log(`${ad.padEnd(22)}${String(d.bildirim).padStart(9)}${d.kisi.toFixed(1).padStart(6)}` +
    `${`%${d.eyleme.toFixed(1)}`.padStart(14)}${`${d.kapsanan}/${olay.length}`.padStart(10)}` +
    `${String(d.teslimsiz).padStart(11)}${String(d.korOlay).padStart(10)}` +
    `${`${d.yanit.toFixed(1)} dk`.padStart(12)}${`%${d.yorgun.toFixed(0)}`.padStart(11)}`);
  return d;
});
const [ilk, son] = [sonuc[0], sonuc[3]];
console.log(`\nkisi basina ${GUN / NOBETCI} nobet gunu: ham akista ` +
  `${(ilk.bildirim / NOBETCI).toFixed(0)} bildirim, suzgeclerden sonra ${(son.bildirim / NOBETCI).toFixed(0)}`);
console.log(`okunmadan kapatilan uyari ${ilk.korlenen} -> ${son.korlenen}`);
const kalan = olay.filter((o) => !ASAMA[3][1].some((u) => u.olay === o.id));
console.log(`suzgeclerin teslim etmedigi gercek olay ${kalan.length}: ` +
  `${kalan.map((o) => `${o.id}. olay (${o.servis})`).join(", ") || "yok"}`);
for (const [ad, once, sonra] of [["gruplama", ASAMA[0][1], ASAMA[1][1]],
  ["susturma", ASAMA[1][1], ASAMA[2][1]]]) {
  const k = once.filter((u) => !sonra.includes(u));
  console.log(`${ad} ${k.length} bildirim kaldirdi, ${k.filter((u) => u.olay !== null).length}'i olayli`);
}
console.log(`\n${"bastirma penceresi".padEnd(20)}${"kaldirilan".padStart(11)}${"turev".padStart(7)}` +
  `${"bagimsiz olay".padStart(15)}${"gurultu".padStart(9)}${"teslimsiz olay".padStart(16)}`);
for (const w of [15, 45, 120, 360]) {
  PENCERE.bagimlilik = w;
  const B = bastirma(ASAMA[2][1]), kaldirilan = ASAMA[2][1].filter((u) => !B.includes(u));
  const teslimsiz = olay.filter((o) => !B.some((u) => u.olay === o.id)).length;
  console.log(`${`${w} dk`.padEnd(20)}${String(kaldirilan.length).padStart(11)}` +
    `${String(kaldirilan.filter((u) => u.turev).length).padStart(7)}` +
    `${String(kaldirilan.filter((u) => u.olay !== null && !u.turev).length).padStart(15)}` +
    `${String(kaldirilan.filter((u) => u.olay === null).length).padStart(9)}` +
    `${String(teslimsiz).padStart(16)}`);
}
```

```
yorgunluk esigi: 7. uyaridan sonra yanit suresi tabanin iki kati (4 dk -> 8.3 dk)

asama                  bildirim   gun  eyleme donen  kapsanan  teslimsiz  korlenen olay yaniti  esik ustu
ham akis                    268   8.9          %3.0      8/20          0        12      7.8 dk        %80
gruplama                    247   8.2          %3.2      8/20          0        12      7.6 dk        %77
+ susturma                  208   6.9          %5.8     12/20          0         8      7.8 dk        %64
+ bagimlilik bastirma       191   6.4          %6.8     13/20          0         7      7.8 dk        %59

kisi basina 15 nobet gunu: ham akista 134 bildirim, suzgeclerden sonra 96
okunmadan kapatilan uyari 152 -> 40
suzgeclerin teslim etmedigi gercek olay 0: yok
gruplama 21 bildirim kaldirdi, 18'i olayli
susturma 39 bildirim kaldirdi, 1'i olayli

bastirma penceresi   kaldirilan  turev  bagimsiz olay  gurultu  teslimsiz olay
15 dk                        15     14              0        1               0
45 dk                        17     14              0        3               0
120 dk                       25     15              3        7               3
360 dk                       46     16              6       24               6
```

#### Yorgunluğun Sayısı

Yorgunluk eşiği hesaptan çıkıyor: yedinci uyarıdan sonra yanıt süresi tabanın iki katına, 4
dakikadan 8,3 dakikaya çıkıyor. Ham akışta bildirimlerin yüzde 80'i bu eşiğin üstünde bir sırada
geliyor. Yani nöbetçiye ulaşan uyarıların beşte dördü, o kişinin son yirmi dört saatte zaten altı
uyarı aldığı bir anda geliyor.

Sonucu üçüncü sütun taşıyor. Ham akışta yirmi gerçek olayın yalnız **sekizi** görülüyor; on ikisi
okunmadan kapatılan uyarıların içinde kalıyor. Hiçbir uyarı kaybolmadı, hiçbir kural yanlış yazılmadı,
teslim edilmeyen olay sıfır — olaylar yalnızca sırada çok gerideydiler.

Süzgeçler bu sayıyı sekizden on üçe çıkarıyor. Kazancın kaynağı şudur: süzgeçler hiçbir yeni bilgi
eklemiyor, aynı bilgiyi daha az bildirimle veriyor; gürültü kalktıkça gerçek olayın bildirimi
sıranın önüne geliyor. Eyleme dönen bildirim oranı yüzde 3,0'dan 6,8'e, yani iki katına çıkıyor —
ve yine de bildirimlerin yüzde 93'ü bir işe dönüşmüyor.

Üç süzgecin katkısı eşit değil. Gruplama 21 bildirim kaldırdı ve bunların 18'i olaylıydı: aynı
olayda aynı servisin birkaç kuralı birden çalıyor ve gruplama bunları tek bildirimde topluyor.
Kaldırılan bildirim sayısı küçük, çünkü gürültü tek bir servise toplanmıyor, on dört kurala
dağılıyor. Susturma tam tersi: 39 bildirim kaldırdı ve yalnız biri olaylıydı. Görülen olay sayısını
sekizden on ikiye çıkaran adım bu — üç gürültücü kuralın günlük payı kesilince nöbetçinin sırası
kısalıyor ve arkada kalan gerçek olaylar eşiğin altına iniyor.

Görülen olayların yanıt süresi neredeyse değişmiyor: gruplamada 7,6 dakika, diğer üç aşamada 7,8
dakika. Bunun nedeni süzgeçlerin sıranın kendisini değil sayısını düşürmesidir — yeni görülen
olaylar da yüksek sıralarda geliyor. Kazanç yanıt süresinde değil, **görülen olay sayısındadır.**

#### Bastırmanın Bedeli

Bağımlılık bastırması en tehlikeli süzgeçtir, çünkü bilgi siler. Pencere taraması bedeli
gösteriyor. On beş dakikalık pencerede kaldırılan 15 bildirimin 14'ü türev, biri gürültü; hiçbir
bağımsız olayın kendi uyarısı silinmiyor. Kırk beş dakikada tablo aynı: türev kazancı 14'te
duruyor, çünkü türev uyarılar zaten olayın ilk kırk beş dakikasında doğuyor.

Pencereyi büyütmek bundan sonrası için yalnız zarar veriyor. Yüz yirmi dakikada üç bağımsız olayın
kendi uyarısı bastırılıyor ve üç gerçek olay hiçbir bildirim almıyor; üç yüz altmış dakikada bu
sayı altıya çıkıyor. Bastırma penceresi, bağımlılığın etkisinin sürdüğü süreye göre seçilir; daha
uzunu üstteki servisin **kendi** olayını bağımlılığın gölgesinde bırakır.

Buradaki asıl ayrım şudur: gruplama ve susturma bildirimi geciktirir ya da toplar, bağımlılık
bastırması ise bildirimi **yok eder**. İlk ikisinin hatası fark edilir, üçüncüsünün hatası
fark edilmez — bastırılan uyarı hiçbir listede görünmez.

#### Özet

- Otuz günlük akışta 268 uyarının 212'si hiçbir olaya bağlı değildi; tek bir gürültücü kural 70
  uyarı üretti ve bunların yalnız ikisi bir olaya denk geldi.
- Yorgunluk eşiği yedinci uyarıdır: o sıradan sonra yanıt süresi 4 dakikadan 8,3 dakikaya çıkıyor
  ve ham akışta bildirimlerin yüzde 80'i bu eşiğin üstünde geliyor.
- Ham akışta yirmi gerçek olayın sekizi görüldü; on ikisi teslim edildiği hâlde okunmadan
  kapatıldı — kayıp toplamada değil, sıradaydı.
- Üç süzgeç bildirimi 268'den 191'e, gün başına 8,9'dan 6,4'e indirdi; görülen olay sekizden on
  üçe, eyleme dönen bildirim oranı yüzde 3,0'dan 6,8'e çıktı. Görülen olayı asıl artıran susturma
  oldu: kaldırdığı 39 bildirimin yalnız biri olaylıydı.
- Görülen olayların yanıt süresi dört aşamada da 7,6-7,8 dakika bandında kaldı: süzgeçler sırayı değil sayıyı
  düşürüyor, kazanç görülen olay sayısında.
- Bağımlılık bastırmasının kazancı kırk beş dakikada doyuyor; yüz yirmi dakikalık pencerede üç,
  üç yüz altmış dakikalık pencerede altı gerçek olay hiçbir bildirim almıyor.

#### Sonraki Adım

Bu ders boyunca her sinyal gerçek trafikten doğdu: bir istek geldi, bir kural çaldı, bir kişi
uyarıldı. Gerçek trafiğin görmediği durumlar da vardır. Gece üç ile beş arasında fatura sorgusu
neredeyse hiç gelmez; o saatte bozulan bir akış sabah dokuza kadar hiçbir uyarı üretmez, çünkü
uyarıyı doğuracak istek yoktur. Yılda birkaç kez kullanılan bir akış aylardır bozuk olabilir. Dış
bir bağımlılığın kendi arızası ise ancak birisi ona istek gönderdiğinde görünür. Sonraki ders
dışarıdan periyodik yoklama kurar, yoklama sıklığını tarayarak fark etme gecikmesiyle yoklama
maliyetini birlikte ölçer ve yoklamanın geçtiği hâlde gerçek kullanıcı akışının bozuk olduğu
durumu adıyla yazar.

### Sentetik İzleme

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/sentetik-izleme

Gerçek trafiğin görmediği durumların sayılması ve dışarıdan periyodik yoklamayla karşılanması: on arızanın gerçek trafik kuralı ile yoklama üzerinde ayrı ayrı ölçülmesi, yoklama sıklığının fark etme gecikmesi ve maliyetle birlikte taranması, yoklamanın yanlış güven verdiği durumların adlandırılması.

Buraya kadar üretilen her sinyalin bir ortak yanı vardı: hepsi gerçek trafikten doğdu. Bir istek
geldi, bir adım kaydı yazıldı, bir ölçüt kovası doldu, bir kural çaldı. Bu zincirin ilk halkası
koparsa geri kalanı hiç çalışmaz — **istek gelmiyorsa ölçülecek bir şey de yoktur.**

Bu ders bölgesel ölçüm ağının (kurgu) on dört günlük trafiğini beş akış üzerinden modelleyip on
arızayı iki ayrı yolla ölçer: gerçek trafikten doğan bir kural ve dışarıdan periyodik yoklama.
Sayılan üç şey şudur: gerçek trafiğin hiç göremediği arıza, yoklamanın fark etme gecikmesi ile
maliyeti ve yoklamanın geçtiği hâlde kullanıcının etkilendiği durum.

#### Gerçek Trafiğin Kör Noktaları

```js
// sentetik/trafik.mjs — on dort gunluk gercek trafigin ve on arizanin MODELI. IG31: bes akisin
// dakikalik istek sayisi kurgudur; fatura sorgusu gunduz yogun gece bostur, yillik kapanis ayda
// birkac kez cagrilir. IG32: bir ariza uc bicimden biridir — "tam" butun istekleri bozar,
// "kismi" yalniz bir abone grubunu bozar, "veri" onbellekten donmeyen yolu bozar.
export const TOHUM = 20260806, GUN = 14, DK = GUN * 1440;
export const SAAT = [2, 1, 1, 1, 1, 4, 14, 32, 46, 52, 55, 53, 48, 51, 54, 50, 44, 34, 26, 18, 12, 8, 5, 3];
// [ad, gunduz carpani, mesai disi calisir mi, kismi bozulmanin etkiledigi oran]
export const AKIS = [["fatura_sorgu", 1, true, 0.18], ["odeme_alma", 0.35, true, 0.22],
  ["sayac_degisim", 0.012, false, 0.30], ["yillik_kapanis", 0.00006, false, 0.5],
  ["dis_dogrulama", 0.12, true, 0.25]];
// [akis, gun, saat, sure dk, tip, ad]
export const ARIZA = [
  [0, 2, 14, 40, "tam", "gunduz fatura kesintisi"], [0, 4, 3, 120, "tam", "gece fatura kesintisi"],
  [0, 6, 10, 90, "kismi", "bir abone grubunda hata"], [0, 9, 11, 60, "veri", "onbellek disi yol bozuk"],
  [1, 3, 20, 75, "tam", "aksam odeme kesintisi"], [1, 7, 2, 180, "tam", "gece odeme kesintisi"],
  [2, 5, 22, 600, "tam", "hafta sonu sayac degisimi"], [3, 8, 4, 1440, "tam", "yillik kapanis akisi"],
  [4, 10, 1, 240, "tam", "dis bagimlilik arizasi"], [4, 12, 9, 50, "kismi", "dis dogrulama kismi"],
];
export const pencere = (i) => [ARIZA[i][1] * 1440 + ARIZA[i][2] * 60, ARIZA[i][3]];

export function trafik() {
  let s = TOHUM;
  const r = () => ((s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32);
  const T = AKIS.map(() => ({ istek: new Float64Array(DK), hata: new Float64Array(DK) }));
  for (let t = 0; t < DK; t += 1) {
    const saat = Math.floor(t / 60) % 24, gun = Math.floor(t / 1440) % 7;
    for (let a = 0; a < AKIS.length; a += 1) {
      const [, carpan, hepGun] = AKIS[a];
      const mesai = hepGun || (saat >= 8 && saat < 18 && gun < 5);
      const n = SAAT[saat] * carpan * (mesai ? 1 : 0.02) * (0.85 + r() * 0.3);
      T[a].istek[t] = Math.max(0, Math.floor(n + (r() < n % 1 ? 1 : 0)));
      let bozuk = 0;
      for (let i = 0; i < ARIZA.length; i += 1) {
        const [ak, , , sr, tip] = ARIZA[i], [bas] = pencere(i);
        if (ak !== a || t < bas || t >= bas + sr) continue;
        bozuk = Math.max(bozuk, tip === "tam" ? 1 : tip === "kismi" ? AKIS[a][3] : 0.45);
      }
      T[a].hata[t] = Math.round(T[a].istek[t] * bozuk);
    }
  }
  return T;
}

if (import.meta.filename === process.argv[1]) {
  const T = trafik();
  const topla = (a, f, b, e) => { let x = 0; for (let t = b; t < e; t += 1) x += T[a][f][t]; return x; };
  console.log(`tohum ${TOHUM}, ${GUN} gun, ${AKIS.length} akis, ${ARIZA.length} ariza\n`);
  console.log(`${"akis".padEnd(16)}${"gunluk istek".padStart(13)}${"gece 03-05 dk".padStart(14)}` +
    `${"bos dakika".padStart(12)}`);
  AKIS.forEach(([ad], a) => {
    let bos = 0;
    for (let t = 0; t < DK; t += 1) if (T[a].istek[t] === 0) bos += 1;
    console.log(`${ad.padEnd(16)}${(topla(a, "istek", 0, DK) / GUN).toFixed(0).padStart(13)}` +
      `${((topla(a, "istek", 180, 300) + topla(a, "istek", 1620, 1740)) / 240).toFixed(2).padStart(14)}` +
      `${`%${(bos / DK * 100).toFixed(0)}`.padStart(12)}`);
  });
}
```

```
tohum 20260806, 14 gun, 5 akis, 10 ariza

akis             gunluk istek gece 03-05 dk  bos dakika
fatura_sorgu            36899          1.02          %1
odeme_alma              12936          0.35         %12
sayac_degisim             251          0.00         %83
yillik_kapanis              2          0.00        %100
dis_dogrulama            4438          0.11         %24
```

Tablo üç ayrı körlük gösteriyor. **Boş saat:** fatura sorgusu günde 36.899 istek alıyor ama gece üç
ile beş arasında dakikada 1,02 istek düşüyor. Beş dakikalık bir pencerede bu beş istek eder ve hata
oranı hesaplamak için beş istek yetmez; kural çalmaz, çünkü paydanın kendisi yok. **Boş akış:**
sayaç değişimi akışının dakikalarının yüzde 83'ü, yıllık kapanış akışının yüzde 100'ü boştur —
yıllık kapanış günde iki istek alıyor. Böyle bir akış aylarca bozuk kalabilir ve hiçbir ölçüt bunu
göstermez. **Dış bağımlılık:** dış doğrulama ucu ancak biz ona istek gönderdiğimizde görünür; o
ucun kendi arızası, bizim çağırmadığımız saatlerde ölçütlerimizde yer almaz.

#### Yoklama ile Trafik Yan Yana

Yoklama her akışa belirli aralıklarla bir istek gönderir ve yanıtı denetler. Üç seçim bu isteği
tanımlar: nereden gönderildiği (kullanıcının geldiği yönden, sistemin dışından), hangi akışın
koşturulduğu (tek bir uç değil, uçtan uca bir iş) ve ne bıraktığı — yazma yapan bir akış
yokladığında sistemde her seferinde bir kayıt kalır, bu yüzden yoklama ya salt okuma yapan bir yol
seçer ya da bıraktığını kendisi siler. Aşağıdaki karşılaştırma aynı on arızayı iki yolla ölçüyor.

```js
// sentetik/yoklama.mjs — gercek trafikten dogan kural ile disaridan periyodik yoklama ayni on
// ariza uzerinde karsilastirilir. IG33: gercek trafik kurali bes dakikalik pencerede en az 20
// istek gormeden calmaz; hata orani yuzde 5'i asip uc dakika surerse uyarir. IG34: yoklama her P
// dakikada bir akis basina bir istek gonderir, ust uste iki basarisiz yoklama uyari uretir.
// IG35: yoklama sabit bir sayac kimligi ve tek bir hesapla kosar; bu yuzden "kismi" ve "veri"
// tipi arizalarda yoklama gecer. IG36: dis dogrulama ucuna giden her yoklama ucretlidir.
import { trafik, AKIS, ARIZA, pencere, DK, GUN } from "./trafik.mjs";
const T = trafik(), MIN = 20, ORAN = 0.05, ARDISIK = 3;

function gercekTespit(i) {
  const ak = ARIZA[i][0], sr = ARIZA[i][3], [bas] = pencere(i);
  let ard = 0;
  for (let t = bas; t < bas + sr; t += 1) {
    let n = 0, h = 0;
    for (let u = Math.max(0, t - 4); u <= t; u += 1) { n += T[ak].istek[u]; h += T[ak].hata[u]; }
    if (n >= MIN && h / n > ORAN) { ard += 1; if (ard >= ARDISIK) return t - bas; } else ard = 0;
  }
  return null;
}
// Yoklama yalniz "tam" arizada duser; sabit girdiyle kostugu icin oteki iki tipi gormez (IG35).
const yoklamaDuser = (i, t) => {
  const [, , , sr, tip] = ARIZA[i], [bas] = pencere(i);
  return tip === "tam" && t >= bas && t < bas + sr;
};
function sentetikTespit(i, P) {
  const [, , , sr] = ARIZA[i], [bas] = pencere(i);
  let ard = 0;
  for (let t = Math.ceil(bas / P) * P; t < bas + sr; t += P) {
    if (yoklamaDuser(i, t)) { ard += 1; if (ard >= 2) return t - bas; } else ard = 0;
  }
  return null;
}

const P0 = 5;
console.log(`${"ariza".padEnd(28)}${"akis".padEnd(16)}${"tip".padStart(6)}` +
  `${"gercek trafik".padStart(15)}${"yoklama (5 dk)".padStart(16)}`);
const bic = (x) => (x === null ? "-" : `${x} dk`);
ARIZA.forEach(([ak, , , , tip, ad], i) =>
  console.log(`${ad.padEnd(28)}${AKIS[ak][0].padEnd(16)}${tip.padStart(6)}` +
    `${bic(gercekTespit(i)).padStart(15)}${bic(sentetikTespit(i, P0)).padStart(16)}`));
const g = ARIZA.map((_, i) => gercekTespit(i)), y = ARIZA.map((_, i) => sentetikTespit(i, P0));
const gormedigi = ARIZA.filter((_, i) => g[i] === null);
console.log(`\ngercek trafigin hic gormedigi ${gormedigi.length} ariza: ` +
  `${gormedigi.map((a) => a[5]).join(", ")}`);
const yanlisGuven = ARIZA.filter((_, i) => y[i] === null && ARIZA[i][4] !== "tam");
console.log(`yoklamanin gectigi ama kullanicinin etkilendigi ${yanlisGuven.length} ariza: ` +
  `${yanlisGuven.map((a) => `${a[5]} (${a[4]})`).join(", ")}`);
const ikisi = ARIZA.filter((_, i) => g[i] === null && y[i] === null);
console.log(`gercek trafik ${g.filter((x) => x !== null).length}/${ARIZA.length}, yoklama ` +
  `${y.filter((x) => x !== null).length}/${ARIZA.length}, ikisi birlikte ` +
  `${ARIZA.length - ikisi.length}/${ARIZA.length}`);

const gunlukIstek = T.reduce((x, a) => x + [...a.istek].reduce((p, q) => p + q, 0), 0) / GUN;
console.log(`\n${"yoklama araligi".padEnd(17)}${"yakalanan".padStart(11)}${"ort. gecikme".padStart(14)}` +
  `${"yoklama/gun".padStart(13)}${"ucretli/gun".padStart(13)}${"sentetik pay".padStart(14)}` +
  `${"seyrek akista".padStart(15)}`);
for (const P of [1, 5, 15, 60]) {
  const t = ARIZA.map((_, i) => sentetikTespit(i, P)).filter((x) => x !== null);
  const gunluk = AKIS.length * (1440 / P), seyrek = [...T[3].istek].reduce((p, q) => p + q, 0) / GUN;
  console.log(`${`${P} dk`.padEnd(17)}${`${t.length}/${ARIZA.length}`.padStart(11)}` +
    `${`${(t.reduce((a, b) => a + b, 0) / t.length).toFixed(1)} dk`.padStart(14)}` +
    `${String(gunluk).padStart(13)}${String(1440 / P).padStart(13)}` +
    `${`%${(gunluk / (gunlukIstek + gunluk) * 100).toFixed(2)}`.padStart(14)}` +
    `${`%${((1440 / P) / (seyrek + 1440 / P) * 100).toFixed(1)}`.padStart(15)}`);
}
```

```
ariza                       akis               tip  gercek trafik  yoklama (5 dk)
gunduz fatura kesintisi     fatura_sorgu       tam           2 dk            5 dk
gece fatura kesintisi       fatura_sorgu       tam              -            5 dk
bir abone grubunda hata     fatura_sorgu     kismi           3 dk               -
onbellek disi yol bozuk     fatura_sorgu      veri           2 dk               -
aksam odeme kesintisi       odeme_alma         tam           2 dk            5 dk
gece odeme kesintisi        odeme_alma         tam              -            5 dk
hafta sonu sayac degisimi   sayac_degisim      tam              -            5 dk
yillik kapanis akisi        yillik_kapanis     tam              -            5 dk
dis bagimlilik arizasi      dis_dogrulama      tam              -            5 dk
dis dogrulama kismi         dis_dogrulama    kismi           2 dk               -

gercek trafigin hic gormedigi 5 ariza: gece fatura kesintisi, gece odeme kesintisi, hafta sonu sayac degisimi, yillik kapanis akisi, dis bagimlilik arizasi
yoklamanin gectigi ama kullanicinin etkilendigi 3 ariza: bir abone grubunda hata (kismi), onbellek disi yol bozuk (veri), dis dogrulama kismi (kismi)
gercek trafik 5/10, yoklama 7/10, ikisi birlikte 10/10

yoklama araligi    yakalanan  ort. gecikme  yoklama/gun  ucretli/gun  sentetik pay  seyrek akista
1 dk                    7/10        1.0 dk         7200         1440        %11.66          %99.9
5 dk                    7/10        5.0 dk         1440          288         %2.57          %99.4
15 dk                   7/10       15.0 dk          480           96         %0.87          %98.3
60 dk                   6/10       60.0 dk          120           24         %0.22          %93.6
```

Gerçek trafik on arızanın beşini yakaladı ve yakaladıklarında hızlıydı: gündüz fatura kesintisini
2. dakikada gördü, yoklama aynı arızayı 5. dakikada. Gündüz saatlerinde gerçek trafik yoklamadan
üstündür, çünkü dakikada elli isteklik bir örneklem her yoklamadan büyüktür.

Kaçırdığı beş arıza da bir listeye sığıyor: iki gece kesintisi, hafta sonu bozulan sayaç değişimi,
yıllık kapanış akışı ve dış bağımlılığın kendi arızası. Beşinin ortak yanı, arıza sırasında o akışa
yeterli istek gelmemesidir. Yoklama bu beşinin hepsini yakaladı, çünkü yoklamanın gönderdiği istek
saatten ve mevsimden bağımsızdır.

#### Sıklık ile Maliyet

Sıklık taraması iki eğriyi aynı tabloda tutuyor. Bir dakikalık aralıkta fark etme gecikmesi 1
dakikaya iniyor, ama günde 7.200 yoklama gönderiliyor ve bunların 1.440'ı ücretli dış çağrı. Daha
ağır bir bedel sağdaki iki sütunda: sentetik istekler toplam trafiğin yüzde 11,66'sına çıkıyor,
seyrek akışta ise yüzde 99,9'una. O akışın gösterge tablosunda görülen her şey artık kendi
yoklamamızdır; gerçek kullanım ölçüsü yok olur.

Altmış dakikalık aralıkta maliyet yüzde 0,22'ye iniyor ama yakalanan arıza yediden altıya düşüyor:
kırk dakika süren gündüz kesintisi iki ardışık yoklamaya yetişmeden kapanıyor. **Yoklama aralığı,
görülmek istenen en kısa arızadan küçük olmalıdır** — iki ardışık başarısız yoklama koşulu, aralığı
iki katına çıkarır.

On beş dakikalık aralık bu taramada dengeyi tutuyor: yedi arıza, 15 dakika gecikme, günde 480
yoklama, 96 ücretli çağrı ve toplam trafiğin yüzde 0,87'si. Seçim yoklama başına maliyetle fark
etme gecikmesinin karşılaştırılmasıdır ve akış başına ayrı verilebilir: gece boş kalan akışa sık,
gündüz yoğun akışa seyrek yoklama gönderilir, çünkü ikincisini zaten gerçek trafik görür.

#### Yanlış Güven

Yoklamanın geçtiği hâlde kullanıcının etkilendiği üç arıza var ve ikisinin adı bellidir. **Sabit
girdili yoklama:** yoklama tek bir sayaç kimliği ve tek bir hesapla koşuyor; bir abone grubunu
etkileyen bozulmada o hesap etkilenmediği için yoklama geçiyor. Aynı biçim dış doğrulamanın kısmi
arızasında da tekrarlanıyor. **Önbellekten dönen yoklama:** yoklama hep aynı kaydı istediği için
yanıt önbellekten geliyor; önbelleğin arkasındaki veri yolu bozukken yoklama yeşil kalıyor.

İki durumun ortak kökü şudur: yoklama, sistemin **bir yolunu** ölçer, sistemin kendisini değil.
Yeşil bir yoklama panosu "her şey çalışıyor" demez, "denenen yol çalışıyor" der. Bu yüzden yoklama
gerçek trafiğin yerine geçmez; ikisi birlikte on arızanın onunu kapsıyor, tek başına hiçbiri
kapsamıyor.

#### Özet

- Gerçek trafikten doğan kural, istek gelmeyen yerde çalışmaz: gece dakikada bir isteğe düşen bir
  akışta beş dakikalık pencere hata oranı hesaplamaya yetmiyor.
- On arızanın beşini gerçek trafik hiç görmedi; hepsinin ortak yanı arıza sırasında o akışa yeterli
  istek gelmemesiydi (iki gece kesintisi, hafta sonu, yılda birkaç kez kullanılan akış, dış
  bağımlılığın kendi arızası).
- Yoklama bu beşini de yakaladı ama üç arızayı kaçırdı ve ikisi gündüz trafiğinde gerçek trafikten
  yavaş kaldı; ikisi birlikte on arızanın onunu kapsıyor.
- Sıklık taraması iki bedeli birlikte gösterdi: bir dakikalık aralık gecikmeyi 1 dakikaya indiriyor
  ama günde 7.200 yoklama, 1.440 ücretli çağrı ve toplam trafiğin yüzde 11,66'sı ediyor; seyrek
  akışta ölçütlerin yüzde 99,9'u sentetik hâle geliyor.
- Yoklama aralığı iki ardışık başarısız yoklamayla uyardığı için görülmek istenen en kısa arızanın
  yarısından küçük seçilir; altmış dakikada kırk dakikalık kesinti kaçıyor.
- Yanlış güvenin iki adı var: sabit girdili yoklama bir abone grubunu etkileyen bozulmayı, önbellekten
  dönen yoklama veri yolu bozukluğunu göstermez.

#### Sonraki Adım

Bu konuda sinyal üç aşamadan geçti: bir isteğin servisler arasındaki yolu iz ağacıyla görünür oldu,
ortak sözleşmeyle birleştirilebilir hâle geldi, panoda soruya bağlandı, kurallarla süzüldü ve
dışarıdan yoklamayla doğrulandı. Zincirin ucunda hep aynı şey duruyor: sinyal bir **insanı**
uyandırıyor. O insanın düzeni ise hiç ele alınmadı. Kim uyanıyor, ayda kaç gece uyanıyor, uyandıktan
sonra ne yapacağını nereden okuyor, sabah işi kime devrediyor ve olay kapandıktan sonra aynı olayın
bir daha yaşanmaması için açılan madde gerçekten kapanıyor mu — bunların hiçbiri bir ölçüt kovasında
ya da bir panelde durmuyor. Sonraki konu sinyalin bittiği yerden, insanın başladığı yerden devam
eder.

## Olay Yönetimi

Sinyalin insana dönüşmesi: sürdürülebilir nöbet düzeni, önem düzeyi ve tırmandırmayla olay sınıflandırma, yinelenen müdahalenin çalışma yordamı olarak belgelenmesi, suçsuz olay sonrası inceleme ve eylem maddelerinin izlenmesi, hata bütçesiyle değişim hızının düzenlenmesi ve kaynak kullanımının ekonomik yönünün izlenmesi.

### Nöbet Düzeni

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/nobet-duzeni

Nöbetin kendi bedeli: bir yıllık 136 çağrının 61'inin gece gelmesi, sekiz sorudan beşinin çizelgeden yanıtlanıp üçünün yanıtsız kalması, kişi başına yıllık yükün üç kişilik ekipte 17,3 nöbet haftası ve 118,7 toparlanma saatine çıkması, ortalama bandın sekiz kişide geçilmesine karşılık en yüklü kişinin hiçbir düzende banda girmemesi ve gecelik toplu işin saatini kaydırmanın eşiği sekiz kişiden dört kişiye indirmesi.

Sinyal üretildi, süzüldü ve doğrulandı. Ölçüt toplandı, günlük ayrıştırıldı, gösterge tablosu
kuruldu, uyarı kuralı bir eşiğe bağlandı. Zincirin sonunda duran bir gösterge değil, saat 02.40'ta
telefonu çalan bir insandır.

**Nöbet düzeni**, hangi çağrının hangi anda kime gideceğini önceden belirleyen çizelgedir. M20/K05
`İşletim Devri` dersi tam devir ile paylaşımlı nöbeti karşılaştırıp **devrin** bedelini saydı;
burada nöbet biçimi verilidir, ölçülen **nöbetin kendi bedelidir**: kişi başına yıllık nöbet
haftası, gece uyandırma ve **toparlanma penceresi**.

#### Çizelge, Kapsama ve Soru Kümesi

Örnek, kursun kurgu **bölgesel ölçüm ağı**dır: su sayacı okuma toplayıcı, doğrulayıcı, faturalama
ve iş emri servisleri. Ağ da nöbet de kurgudur; gerçek bir çizelge ya da çağrı kaydı yoktur.

**OY1:** Dört servis tek ekibin nöbetindedir; gecelik toplu iş 02.00'de başlar, iki saat sürer.
**OY2:** Yıl 52 haftadır; nöbet sırayla devreder, vardiya 1 ya da 2 hafta tutar, ekip sekiz kişilik
havuzun ilk `n` kişisidir. **OY3:** 00.00–06.00 arasında gelen çağrı uykudan kaldırır, gündüz gelen
kaldırmaz. **OY4:** Gece uyandırmasının toparlanma penceresi 4 saattir; aynı vardiyada her ek
uyandırma pencereyi 2 saat büyütür, vardiya devrinde birikim sıfırlanır. **OY5:** Nöbetçi çağrının
servisine dokunamıyorsa sırada onu kapsayan ilk kişi **yedek** olarak uyandırılır (4 saatlik
pencere) ve ilk adım 10 yerine 35 dakikada başlar. **OY6:** Bant, kişi başına yılda en çok 13 nöbet
haftası, 12 gece uyandırma ve 60 toparlanma saatidir.

```js
// nobet/duzen.mjs — kurgu bolgesel olcum aginin nobet duzeni modeli (model): gercek bir nobet
// cizelgesi, cagri kaydi ya da kisi yok; yil bir tur dizisidir. Rastgelelik kendi uretecimizden.

export const HAFTA = 52, GUN = 7, SAAT = 24, YIL = HAFTA * GUN;
export const SERVIS = ["okuma-toplayici", "dogrulayici", "faturalama", "is-emri"];
export const GECE_SON = 6, TOPLU_IS = 2;  // 00-06 arasi cagri uyandirir; toplu is 02'de baslar
export const TOPARLANMA = 4, BIRIKIM = 2; // ilk uyandirma 4 saat, ayni vardiyada her ek +2 saat
export const YEDEK_PENCERE = 4;           // yedek de uyandirilir: kendi 4 saatlik penceresi
export const ILK_ADIM = 10, YEDEK_ADIM = 35;   // ilk adima baslama gecikmesi (dakika)
export const ESIK = { nobet: 13, gece: 12, toparlanma: 60 };   // kisi basina yillik bantlar

// gunluk cagri olasiligi ve cagrinin gecelik toplu is penceresine dusme payi
export const ORAN = { "okuma-toplayici": 0.16, dogrulayici: 0.09, faturalama: 0.06, "is-emri": 0.05 };
export const TOPLU = { "okuma-toplayici": 0.40, dogrulayici: 0.35, faturalama: 0.30, "is-emri": 0.10 };

// Kapsama: havuzun sekiz kisisi ve dokunabildigi servisler. Ilk uc kisi dort servisi de kapsar.
export const KAPSAM = `
  k1  okuma-toplayici dogrulayici faturalama
  k2  dogrulayici is-emri
  k3  okuma-toplayici faturalama is-emri
  k4  okuma-toplayici dogrulayici
  k5  faturalama is-emri
  k6  okuma-toplayici is-emri
  k7  dogrulayici faturalama
  k8  okuma-toplayici dogrulayici faturalama is-emri`
  .trim().split("\n").map((r) => { const [ad, ...s] = r.trim().split(/\s+/); return { ad, s }; });

// kaydirmali uretec; tohum gorunur, dizi kosumdan kosuma ayni
export function uretec(tohum) {
  let x = tohum >>> 0 || 1;
  return () => { x ^= x << 13; x >>>= 0; x ^= x >>> 17; x ^= x << 5; x >>>= 0;
    return x / 4294967296; };
}

// topluSaat: ayni tohumda cagri kumesi aynidir, yalnizca toplu ise bagli cagrilarin saati kayar.
export function cagrilar(tohum, topluSaat = TOPLU_IS) {
  const r = uretec(tohum), liste = [];
  for (let g = 0; g < YIL; g++)
    for (const s of SERVIS) {
      if (r() >= ORAN[s]) continue;
      const toplu = r() < TOPLU[s];
      const saat = toplu ? topluSaat + Math.floor(r() * 2) : Math.floor(r() * SAAT);
      liste.push({ gun: g, saat, servis: s, toplu, gece: saat < GECE_SON });
    }
  return liste;
}

// duzen: n kisi, vardiya v hafta. "dagitik" karsit kosumda cizelge yoktur, gece cagrisi
// ekibin tamamina duser. kos(): kisi basina yillik nobet/uyandirma/toparlanma sayaci.
export function kos(cagri, n, v, dagitik = false) {
  const kisi = KAPSAM.slice(0, n).map((k) => ({ ...k, hafta: 0, uyandi: 0, yedek: 0,
    toparlanma: 0, vardiya: -1, ardisik: 0 }));
  let disi = 0, gecikme = 0;

  for (let h = 0; h < HAFTA; h++) kisi[Math.floor(h / v) % n].hafta++;
  for (const c of cagri) {
    const vardiya = Math.floor(c.gun / (GUN * v));
    const i = vardiya % n, nobetci = kisi[i];
    const yerinde = dagitik ? kisi.some((k) => k.s.includes(c.servis))
      : nobetci.s.includes(c.servis);
    if (!yerinde) disi++;
    gecikme += yerinde ? ILK_ADIM : YEDEK_ADIM;
    if (!c.gece) continue;
    if (dagitik) {                                  // duzen yok: gece cagrisi herkesi kaldirir
      for (const k of kisi) { k.uyandi++; k.toparlanma += TOPARLANMA; }
      continue;
    }
    if (nobetci.vardiya !== vardiya) { nobetci.vardiya = vardiya; nobetci.ardisik = 0; }
    nobetci.uyandi++;
    nobetci.toparlanma += TOPARLANMA + BIRIKIM * nobetci.ardisik++;
    if (yerinde) continue;
    for (let d = 1; d < n; d++) {                   // kapsama disi: yedek de uyandirilir
      const y = kisi[(i + d) % n];
      if (!y.s.includes(c.servis)) continue;
      y.uyandi++; y.yedek++; y.toparlanma += YEDEK_PENCERE;
      break;
    }
  }
  const en = (f) => Math.max(...kisi.map(f));
  const ort = (f) => kisi.reduce((a, k) => a + f(k), 0) / n;
  const bant = (h, u, t) => h <= ESIK.nobet && u <= ESIK.gece && t <= ESIK.toparlanma;
  return { n, v, kisi, disi,
    hafta: ort((k) => k.hafta), uyandi: ort((k) => k.uyandi), enUyandi: en((k) => k.uyandi),
    toparlanma: ort((k) => k.toparlanma), enToparlanma: en((k) => k.toparlanma),
    yedek: kisi.reduce((a, k) => a + k.yedek, 0), gecikme: gecikme / cagri.length,
    ortBant: bant(ort((k) => k.hafta), ort((k) => k.uyandi), ort((k) => k.toparlanma)),
    kisiBant: kisi.every((k) => bant(k.hafta, k.uyandi, k.toparlanma)) };
}
```

```js
// nobet/olc.mjs — nobetin kendi bedeli: ekip buyuklugu ve vardiya uzunlugu taramasi.
import { cagrilar, kos, KAPSAM, ESIK, HAFTA, YEDEK_PENCERE } from "./duzen.mjs";

const TOHUM = 20260615;
const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const s1 = (x) => x.toFixed(1);
const ea = (b) => (b ? "evet" : "hayir");

const C = cagrilar(TOHUM);
const gece = C.filter((c) => c.gece);
console.log(`tohum ${TOHUM}: ${HAFTA} haftada ${C.length} cagri, ${gece.length} tanesi gece ` +
  `(${gece.filter((c) => c.toplu).length} tanesi gecelik toplu is penceresinde)`);

const S = [-6, -11, 12, 16, 18, 10, 10];
console.log("\n1. nobet duzeni taramasi (kisi basina yillik; ort / en yuklu kisi)");
yaz(S, "kisi", "vardiya", "nobet haf.", "uyandirma", "toparlanma saati", "ort bant", "kisi bant");
const tarama = [];
for (const n of [3, 4, 5, 6, 8])
  for (const v of [1, 2]) {
    const R = kos(C, n, v);
    tarama.push(R);
    yaz(S, n, `${v} haf.`, s1(R.hafta), `${s1(R.uyandi)} / ${R.enUyandi}`,
      `${s1(R.toparlanma)} / ${s1(R.enToparlanma)}`, ea(R.ortBant), ea(R.kisiBant));
  }
const D = kos(C, 5, 1, true);
yaz(S, 5, "duzen yok", "-", `${s1(D.uyandi)} / ${D.enUyandi}`,
  `${s1(D.toparlanma)} / ${s1(D.enToparlanma)}`, ea(D.ortBant), ea(D.kisiBant));
console.log(`bant: nobet <= ${ESIK.nobet} haf., uyandirma <= ${ESIK.gece}, ` +
  `toparlanma <= ${ESIK.toparlanma} saat`);

const Q = [-42, 20, 8];
console.log("\n2. nobet duzeninin yanitladigi soru kumesi");
yaz(Q, "soru", "veri", "yanit");
const SORU = [
  ["gece 02.40'ta kim nobetci", "nobet cizelgesi", true],
  ["nobet ne zaman devrediyor", "nobet cizelgesi", true],
  ["nobetci bu servise dokunabiliyor mu", "kapsama cizelgesi", true],
  ["dokunamiyorsa kim, ne zaman cagrilir", "kapsama cizelgesi", true],
  ["nobetci son otuz gunde kac kez uyandi", "uyandirma kaydi", true],
  ["cagri hangi adimla kapaniyor", "-", false],
  ["uyandirmadan sonra kac saat uretken degil", "-", false],
  ["bu duzen bir yil surdurulur mu", "-", false]];
for (const [q, d, y] of SORU) yaz(Q, q, d, y ? "evet" : "hayir");
console.log(`${SORU.length} sorudan ${SORU.filter((x) => x[2]).length} tanesi cizelgeden ` +
  `yanitlanir, ${SORU.filter((x) => !x[2]).length} tanesi yanitsiz kalir`);

const K = [-6, 14, 18, 20, 13];
console.log("\n3. kapsama disi cagrinin bedeli (vardiya 1 hafta)");
yaz(K, "kisi", "kapsam disi", "yedek uyandirma", "yedegin payi (saat)", "ilk adim dk");
for (const R of tarama.filter((r) => r.v === 1))
  yaz(K, R.n, `${R.disi} (%${((R.disi / C.length) * 100).toFixed(0)})`, R.yedek,
    s1((R.yedek * YEDEK_PENCERE) / R.n), s1(R.gecikme));

const H = [-6, 8, 12, 14, 17];
console.log("\n4. bes kisilik ekipte yuk dagilimi (vardiya 1 haf. / 2 haf.)");
yaz(H, "kisi", "kapsam", "nobet haf.", "uyandirma", "toparlanma saati");
const [A, B] = [kos(C, 5, 1), kos(C, 5, 2)];
for (let i = 0; i < 5; i++)
  yaz(H, KAPSAM[i].ad, KAPSAM[i].s.length, A.kisi[i].hafta,
    `${A.kisi[i].uyandi} / ${B.kisi[i].uyandi}`,
    `${s1(A.kisi[i].toparlanma)} / ${s1(B.kisi[i].toparlanma)}`);

const C9 = cagrilar(TOHUM, 9);                      // ayni cagri kumesi, toplu is 09.00'da
const T = [-6, 16, 20, 11, 10];
console.log(`\n5. gecelik toplu is 02.00 yerine 09.00'da kosarsa (vardiya 1 hafta)`);
console.log(`gece cagrisi ${gece.length} -> ${C9.filter((c) => c.gece).length}`);
yaz(T, "kisi", "uyandirma 02 / 09", "toparlanma 02 / 09", "bant 02", "bant 09");
for (const n of [3, 4, 5, 6, 8]) {
  const [a, b] = [kos(C, n, 1), kos(C9, n, 1)];
  yaz(T, n, `${s1(a.uyandi)} / ${s1(b.uyandi)}`, `${s1(a.toparlanma)} / ${s1(b.toparlanma)}`,
    ea(a.ortBant), ea(b.ortBant));
}
```

```
tohum 20260615: 52 haftada 136 cagri, 61 tanesi gece (41 tanesi gecelik toplu is penceresinde)

1. nobet duzeni taramasi (kisi basina yillik; ort / en yuklu kisi)
kisi  vardiya      nobet haf.       uyandirma  toparlanma saati  ort bant kisi bant
3     1 haf.             17.3       25.7 / 29     118.7 / 138.0     hayir     hayir
3     2 haf.             17.3       28.7 / 38     154.7 / 180.0     hayir     hayir
4     1 haf.             13.0       19.8 / 25      91.0 / 110.0     hayir     hayir
4     2 haf.             13.0       19.3 / 27     107.0 / 146.0     hayir     hayir
5     1 haf.             10.4       16.2 / 20       74.4 / 96.0     hayir     hayir
5     2 haf.             10.4       16.6 / 22      90.4 / 124.0     hayir     hayir
6     1 haf.              8.7       13.3 / 16       61.3 / 82.0     hayir     hayir
6     2 haf.              8.7       14.5 / 20       78.0 / 96.0     hayir     hayir
8     1 haf.              6.5       10.1 / 14       46.5 / 66.0      evet     hayir
8     2 haf.              6.5       11.3 / 16       60.0 / 96.0      evet     hayir
5     duzen yok             -       61.0 / 61     244.0 / 244.0     hayir     hayir
bant: nobet <= 13 haf., uyandirma <= 12, toparlanma <= 60 saat

2. nobet duzeninin yanitladigi soru kumesi
soru                                                      veri   yanit
gece 02.40'ta kim nobetci                      nobet cizelgesi    evet
nobet ne zaman devrediyor                      nobet cizelgesi    evet
nobetci bu servise dokunabiliyor mu          kapsama cizelgesi    evet
dokunamiyorsa kim, ne zaman cagrilir         kapsama cizelgesi    evet
nobetci son otuz gunde kac kez uyandi          uyandirma kaydi    evet
cagri hangi adimla kapaniyor                                 -   hayir
uyandirmadan sonra kac saat uretken degil                    -   hayir
bu duzen bir yil surdurulur mu                               -   hayir
8 sorudan 5 tanesi cizelgeden yanitlanir, 3 tanesi yanitsiz kalir

3. kapsama disi cagrinin bedeli (vardiya 1 hafta)
kisi     kapsam disi   yedek uyandirma yedegin payi (saat)  ilk adim dk
3           42 (%31)                16                21.3         17.7
4           42 (%31)                18                18.0         17.7
5           50 (%37)                20                16.0         19.2
6           44 (%32)                19                12.7         18.1
8           45 (%33)                20                10.0         18.3

4. bes kisilik ekipte yuk dagilimi (vardiya 1 haf. / 2 haf.)
kisi    kapsam  nobet haf.     uyandirma toparlanma saati
k1           3          11       20 / 22     96.0 / 124.0
k2           2          11       18 / 14      84.0 / 90.0
k3           3          10       20 / 21     86.0 / 112.0
k4           2          10       14 / 14      66.0 / 68.0
k5           2          10        9 / 12      40.0 / 58.0

5. gecelik toplu is 02.00 yerine 09.00'da kosarsa (vardiya 1 hafta)
gece cagrisi 61 -> 20
kisi  uyandirma 02 / 09  toparlanma 02 / 09    bant 02   bant 09
3           25.7 / 9.3        118.7 / 38.7      hayir     hayir
4           19.8 / 6.5         91.0 / 27.0      hayir      evet
5           16.2 / 5.0         74.4 / 20.8      hayir      evet
6           13.3 / 4.7         61.3 / 19.3      hayir      evet
8           10.1 / 3.0         46.5 / 12.5       evet      evet
```

Sayılar **ölçüm** sınıfındadır; girdileri OY1–OY6 varsayımlarıdır. Çizelgesiz karşıt koşum birinci
tablonun son satırındadır: düzen yokken her gece çağrısı ekibin tamamını kaldırır, kişi başına
uyandırma 61'e ve toparlanma 244 saate çıkar. **Nöbet düzeninin ilk işi yükü azaltmak değil, tek
kişiye yıkmaktır** — beş kişide aynı çağrı kümesi kişi başına 16,2 uyandırma yapar.

#### Ekip Küçüldükçe Ne Oluyor

Nöbet haftası doğrudan ekip büyüklüğünden çıkar: üç kişide 17,3 hafta, yani yılın üçte biri.
Uyandırma ve toparlanma bundan hızlı bozulur, çünkü kapsama dışı çağrının yedeği de aynı küçük
havuzdan gelir — üç kişide 25,7 uyandırma ve 118,7 saat, sekiz kişide 10,1 ve 46,5.

Vardiya uzunluğu toplamı değiştirmez ama **birikimi** değiştirir. İki haftalık vardiyada toparlanma
üç kişide 118,7'den 154,7, altı kişide 61,3'ten 78,0 saate çıkar; uyandırma sayısı neredeyse sabit
kalır. Nedeni tektir: uzun vardiya uyandırmaları tek kişide üst üste bindirir ve her ek uyandırma
pencereyi iki saat açar. **Aynı sayıda uyandırma, dağıtıldığında daha ucuzdur.**

#### Eşik Ortalamada mı, Kişide mi

Ortalamaya bakıldığında düzen **sekiz kişide** banda girer; altı kişide toparlanma 61,3 ile 60
saatlik sınırın dışında, uyandırma 13,3 ile 12'nin üstündedir. Kişiye bakıldığında **hiçbir düzen
banda girmez**: sekiz kişide bile en yüklü kişi 14 uyandırma ve 66 toparlanma saati taşır.

Dördüncü tablo nedenini gösterir. Beş kişilik ekipte `k1` 20, `k5` 9 kez uyanır; toparlanma 96,0 ile
40,0 saat arasında dağılır, oysa nöbet haftaları 10 ile 11'dir. Fark **kapsamadan** gelir: üç servis
kapsayan kişi hem kendi nöbetinde hem başkasının nöbetinde yedek olarak uyanır. **Ortalama nöbet
yükü, yükü en ağır taşıyan kişi hakkında hiçbir şey söylemez.**

#### Yanıtsız Kalan Üç Soru

Çizelge ile kapsama çizelgesi sekiz sorudan beşini yanıtlar ve beşi de **kim** ile **ne zaman**
biçimindedir. Yanıtsız üçü aynı boşluğa düşer: çağrının **hangi adımla** kapanacağı, uyandırmanın
kaç saat üretkenlik götürdüğü, düzenin bir yıl sürdürülüp sürdürülemeyeceği.

"Hangi adımla" yanıtsızsa çağrı kapsama dışına düşer: üçüncü tabloda bu pay %31 ile %37
arasındadır ve **ekip büyüdükçe düşmez**, çünkü kapsam kişinin özelliğidir, havuzun değil. Faturası
iki kalemdir — ilk adıma başlama 10 dakikadan 17,7–19,2 dakikaya çıkar ve yılda 16 ile 20 arasında
**ikinci bir kişi** uyandırılır; bu ikinci uyandırma beş kişide kişi başına 16,0 toparlanma
saatidir, oradaki 74,4 saatin beşte birinden fazlası. Toparlanma penceresinin kendisi ise hiçbir
işletim verisinde yoktur: modelde varsayımdır, alanda ölçülmez, bu yüzden nöbetin bedeli kayda
geçmez ve düzen ancak bir kişi ayrıldığında görünür.

#### Uyandırmayı Kim Üretiyor

Beşinci tablo aynı çağrı kümesini tek değişiklikle koşturur: gecelik toplu iş 02.00 yerine 09.00'da
başlar. Çağrı sayısı değişmez, gece çağrısı 61'den 20'ye iner ve bant sekiz kişide değil **dört
kişide** geçilir; beş kişide uyandırma 16,2'den 5,0'a, toparlanma 74,4'ten 20,8 saate düşer. Üç
kişilik ekip bundan sonra bile banda girmez — 9,3 uyandırma içeride, 17,3 nöbet haftası dışarıda.
**Nöbet düzeni bir çizelge sorusu gibi görünür; faturası iş takviminde yazılıdır.**

#### Özet

- Yıllık 136 çağrının 61'i gece gelir; çizelge olmadığında kişi başına yük 61 uyandırma ile 244
  toparlanma saatidir. Çizelgeyle bu yük üç kişide 17,3 nöbet haftası, 25,7 uyandırma ve 118,7
  toparlanma saatine, sekiz kişide 6,5 / 10,1 / 46,5'e iner.
- Vardiyayı iki haftaya çıkarmak uyandırma sayısını değiştirmez, toparlanmayı büyütür: üç kişide
  118,7 → 154,7, altı kişide 61,3 → 78,0 saat.
- Ortalamaya göre bant sekiz kişide geçilir, kişiye göre hiçbir düzende geçilmez; beş kişide aynı
  çizelgeyle 20 ve 9 uyandırma, 96,0 ve 40,0 toparlanma saati yan yana durur.
- Sekiz sorudan beşi yanıtlanır, üçü yanıtsız kalır; "hangi adımla" yanıtsızlığı çağrıların
  %31–%37'sini kapsama dışına düşürür ve yılda 16–20 ikinci uyandırma üretir.
- Gecelik toplu işi 09.00'a almak gece çağrısını 61'den 20'ye indirir, eşiği sekizden dört kişiye
  çeker.

#### Sonraki Adım

Bu ders her çağrının bir insanı uyandırmaya değdiğini varsaydı. Sonraki ders bilinen bir olay
kümesini **önem düzeyi** kuralıyla etiketler ve yanlış sınıflandırmayı iki yönde sayar: fazla
yükseltilenin gereksiz uyandırması, fazla düşürülenin geciken müdahalesi. **Tırmandırma** zinciri
de aynı kümede taranır — kaç basamak, basamak başına kaç dakika, kaç olay kimseye ulaşmadan
kalır.

### Olay Sınıflandırma

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/olay-siniflandirma

Önem düzeyi ve tırmandırma sayıyla: altmış olayın iki kuralla etiketlenmesi, eşik kuralının 37 doğru etiketine karşılık 4 sessiz veri kaybını d4'e düşürüp 11.040 etki-dakika üretmesi, ihtiyatlı kuralın bunu 180'e indirirken gereksiz uyandırmayı 3'ten 7'ye çıkarması, uyanık kalınan saat başına 678,8 etki-dakikalık değiş tokuş ve tırmandırma zincirini iki basamaktan üçe çıkarmanın kimseye ulaşmayan olayı 5'ten 2'ye indirmesi.

Nöbet düzeni "kim" ve "ne zaman" sorularını yanıtladı, ama her çağrının bir insanı uyandırmaya
değdiğini varsaydı. Uyandırma kararı çağrıdan önce verilir ve bu karar bir etiketle verilir.

**Önem düzeyi**, bir olayın hangi hızda ve hangi güçle karşılanacağını belirleyen etikettir;
**tırmandırma**, etiketin gerektirdiği yanıt gelmediğinde sıradaki basamağın çağrılmasıdır. Bu
dersin ölçtüğü şey etiketin kendisi değil, **yanlış etiketin iki yöndeki bedelidir**: fazla
yükseltme geceyi böler, fazla düşürme müdahaleyi geciktirir.

#### Olay Kümesi, Gerçek Düzey ve İki Kural

Örnek yine kursun kurgu **bölgesel ölçüm ağı**dır: su sayacı okuma toplayıcı, doğrulayıcı,
faturalama ve iş emri servisleri, üç ortam. Ağ da olay kümesi de kurgudur.

**OY7:** Altmış olay üretilir; her olayın **gerçek** önem düzeyi ancak kapandıktan sonra bilinen
etkilenen abone sayısı ve veri kaybından çıkar — `d1` en ağır, `d4` en hafif. **OY8:** Çağrı anında
yalnız **görünür imza** vardır: ortam, servis, hata oranı, gecikme katı, gecelik toplu iş
penceresi. **OY9:** `d1` ile `d2` çağrı üretir ve gece de uyandırır; `d3` sabaha kalır, `d4` iş
listesine düşer. **OY10:** Gece düşen fazla yükseltmenin bedeli 4 saatlik toparlanma penceresidir
(nöbet dersiyle aynı birim); fazla düşürmede olay gece ise 06.00'ı bekler, üstüne `d4` etiketi 240,
`d3` etiketi 60 dakika ekler. **OY11:** Gecikmenin bedeli **etki-dakika**dır: gecikme dakikası ×
gerçek düzeyin ağırlığı (`d1` 8, `d2` 3, `d3` 1, `d4` 0). **OY12:** Tırmandırma sıralıdır; bir
basamak gündüz 0,70, gece 0,40 olasılıkla yanıt verir, yanıt gelmezse bekleme süresi sonunda
sıradaki basamak çağrılır.

```js
// olay/kural.mjs — kurgu bolgesel olcum aginin olay kumesi ve siniflandirma modeli (model):
// gercek bir olay kaydi, cagri sirasi ya da kisi yok. Uretec kendi yazildi, tohum gorunur.

export const SERVIS = ["okuma-toplayici", "dogrulayici", "faturalama", "is-emri"];
export const DUZEY = ["d1", "d2", "d3", "d4"];        // d1 en agir
export const AGIRLIK = { d1: 8, d2: 3, d3: 1, d4: 0 };  // etki-dakika carpani
export const UYANDIRAN = ["d1", "d2"];                // gece de cagri uretir
export const PENCERE = 4;                             // gereksiz uyandirmanin toparlanma penceresi
export const SABAH = 6 * 60;                          // sabaha kalan olay 06.00'da ele alinir
export const YANIT = { gunduz: 0.70, gece: 0.40 };    // bir basamagin yanit verme olasiligi

export function uretec(tohum) {
  let x = tohum >>> 0 || 1;
  return () => { x ^= x << 13; x >>>= 0; x ^= x >>> 17; x ^= x << 5; x >>>= 0;
    return x / 4294967296; };
}

// Gizli alanlar (olay kapandiktan sonra bilinir): etkilenen abone, veri kaybi -> gercek duzey.
// Gorunur imza (cagri aninda): ortam, servis, hata orani, gecikme kati, toplu is penceresi.
export function olaylar(tohum, adet = 60) {
  const r = uretec(tohum), liste = [];
  for (let i = 0; i < adet; i++) {
    const servis = SERVIS[Math.floor(r() * SERVIS.length)];
    const u = r();
    const ortam = u < 0.72 ? "uretim" : u < 0.88 ? "hazirlik" : "gelistirme";
    const dk = Math.floor(r() * 1440);
    const buyuk = r();                                // etkinin buyuklugu, uzun kuyruk
    const abone = ortam === "uretim" ? Math.floor(buyuk ** 3 * 60000) : 0;
    const veriKaybi = ortam === "uretim" && servis === "faturalama" && r() < 0.45;
    const sessiz = veriKaybi || (servis === "dogrulayici" && ortam === "uretim" && r() < 0.35);
    const hataOrani = +(sessiz ? 0.01 + r() * 0.05
      : ortam !== "uretim" ? 0.35 + r() * 0.6 : 0.04 + buyuk * 0.8).toFixed(2);
    const gecikmeKat = +(1 + (sessiz ? r() : ortam !== "uretim" ? 4 + r() * 5
      : buyuk * 8)).toFixed(1);
    const gercek = veriKaybi || abone >= 20000 ? "d1" : abone >= 5000 ? "d2"
      : abone >= 500 ? "d3" : "d4";
    liste.push({ i, servis, ortam, dk, gece: dk < SABAH, toplu: dk >= 120 && dk < 240,
      abone, veriKaybi, hataOrani, gecikmeKat, gercek });
  }
  return liste;
}

// Iki siniflandirma kurali. Ikisi de yalnizca gorunur imzaya bakar.
export const KURAL = {
  // A: esik temelli. Uretim disini eler, kalani hata orani ve gecikme katina bakarak etiketler
  A: (o) => o.ortam !== "uretim" ? "d4"
    : o.hataOrani >= 0.50 && o.gecikmeKat >= 4 ? "d1"
    : o.hataOrani >= 0.25 || o.gecikmeKat >= 3 ? "d2"
    : o.toplu ? "d3" : "d4",
  // B: ihtiyatli. Esikler dusuk; faturalama servisi sessiz bozuldugu icin taban d2'ye cekilir
  B: (o) => o.ortam !== "uretim" ? "d4"
    : o.hataOrani >= 0.30 ? "d1"
    : o.hataOrani >= 0.10 || o.gecikmeKat >= 2 ? "d2"
    : o.servis === "faturalama" ? "d2" : "d3",
};

const sira = (d) => DUZEY.indexOf(d);
export const yon = (etiket, gercek) => sira(etiket) < sira(gercek) ? "yukseltme"
  : sira(etiket) > sira(gercek) ? "dusurme" : "dogru";

// Bir etiketin bedeli. Fazla yukseltme gece gereksiz uyandirma yapar; fazla dusurme mudahaleyi
// geciktirir ve gecikme gercek duzeyin agirligiyla carpilarak etki-dakika olur.
export function bedel(o, etiket) {
  const cagirir = UYANDIRAN.includes(etiket);
  const y = yon(etiket, o.gercek);
  const uyandirma = cagirir && o.gece && y === "yukseltme" ? 1 : 0;
  const gecikme = !cagirir && UYANDIRAN.includes(o.gercek)
    ? (o.gece ? SABAH - o.dk : 0) + (etiket === "d4" ? 240 : 60) : 0;
  return { uyandirma, pencere: uyandirma * PENCERE, gecikme,
    etkiDk: gecikme * AGIRLIK[o.gercek], y, cagirir };
}

// Tirmandirma zinciri: basamak sayisi ve basamak basina bekleme dakikasi. Zar onceden uretilir,
// boylece zincir uzatildiginda ayni olay ayni cekilisleri gorur.
export function zar(tohum, adet, enCok = 6) {
  const r = uretec(tohum);
  return Array.from({ length: adet }, () => Array.from({ length: enCok }, () => r()));
}

export function tirmandir(o, z, basamak, bekle) {
  const p = o.gece ? YANIT.gece : YANIT.gunduz;
  for (let b = 0; b < basamak; b++)
    if (z[b] < p) return { ulasti: true, basamak: b + 1, dakika: b * bekle, uyanan: b + 1 };
  return { ulasti: false, basamak, dakika: basamak * bekle, uyanan: basamak };
}
```

```js
// olay/olc.mjs — siniflandirmanin iki yonlu hatasi, bedeli ve tirmandirma zinciri taramasi.
import { olaylar, KURAL, DUZEY, bedel, yon, zar, tirmandir, UYANDIRAN, PENCERE }
  from "./kural.mjs";

const TOHUM = 20260921;
const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const s1 = (x) => x.toFixed(1);
const say = (a, f) => a.filter(f).length;

const O = olaylar(TOHUM);
const Z = zar(TOHUM + 1, O.length);
console.log(`tohum ${TOHUM}: ${O.length} olay, ${say(O, (o) => o.gece)} tanesi gece, ` +
  `${say(O, (o) => o.ortam !== "uretim")} tanesi uretim disi`);
console.log("gercek duzey dagilimi: " +
  DUZEY.map((d) => `${d} ${say(O, (o) => o.gercek === d)}`).join(", "));

const A = [-7, 8, 18, 16, 15, 15];
console.log("\n1. iki siniflandirma kurali ayni olay kumesinde");
yaz(A, "kural", "dogru", "fazla yukseltme", "fazla dusurme", "cagri ureten", "gercek cagri");
for (const [ad, k] of Object.entries(KURAL)) {
  const e = O.map((o) => yon(k(o), o.gercek));
  yaz(A, ad, say(e, (x) => x === "dogru"), say(e, (x) => x === "yukseltme"),
    say(e, (x) => x === "dusurme"), say(O, (o) => UYANDIRAN.includes(k(o))),
    say(O, (o) => UYANDIRAN.includes(o.gercek)));
}

const B = [-7, 17, 13, 17, 14, 14];
console.log("\n2. yanlis siniflandirmanin iki yonlu bedeli");
yaz(B, "kural", "ger. uyandirma", "kayip saat", "gec. mudahale", "gecikme dk", "etki-dakika");
const T2 = {};
for (const [ad, k] of Object.entries(KURAL)) {
  const b = O.map((o) => bedel(o, k(o)));
  const gec = b.filter((x) => x.gecikme > 0);
  T2[ad] = { saat: b.reduce((a, x) => a + x.pencere, 0),
    etki: b.reduce((a, x) => a + x.etkiDk, 0) };
  yaz(B, ad, b.reduce((a, x) => a + x.uyandirma, 0), T2[ad].saat,
    gec.length, gec.length ? s1(gec.reduce((a, x) => a + x.gecikme, 0) / gec.length) : "-",
    T2[ad].etki);
}
const dSaat = T2.B.saat - T2.A.saat, dEtki = T2.A.etki - T2.B.etki;
console.log(`A -> B degis tokusu: kayip saat +${dSaat}, etki-dakika -${dEtki} ` +
  `(uyanik kalinan saat basina ${s1(dEtki / dSaat)} etki-dakika)`);

const C = [-16, 8, 8, 8, 8];
console.log("\n3. kural A'nin karistirdigi olaylar (etiket -> gercek)");
yaz(C, "etiket \\ gercek", ...DUZEY);
for (const e of DUZEY)
  yaz(C, e, ...DUZEY.map((g) => say(O, (o) => KURAL.A(o) === e && o.gercek === g)));

const T = [-9, -9, 13, 16, 19, 14];
console.log("\n4. tirmandirma zinciri taramasi (kural B'nin cagri urettigi olaylar)");
yaz(T, "basamak", "bekleme", "ort basamak", "ort ulasma dk", "ulasilamayan olay", "uyanan kisi");
const cagri = O.filter((o) => UYANDIRAN.includes(KURAL.B(o)));
for (const basamak of [2, 3, 4])
  for (const bekle of [5, 15]) {
    const R = cagri.map((o) => tirmandir(o, Z[o.i], basamak, bekle));
    yaz(T, basamak, `${bekle} dk`, s1(R.reduce((a, x) => a + x.basamak, 0) / R.length),
      s1(R.reduce((a, x) => a + x.dakika, 0) / R.length), say(R, (x) => !x.ulasti),
      R.reduce((a, x) => a + x.uyanan, 0));
  }
console.log(`${cagri.length} cagri, ${say(cagri, (o) => o.gece)} tanesi gece; ` +
  `gereksiz uyandirmanin penceresi ${PENCERE} saat`);

const Q = [-40, 22, 8];
console.log("\n5. siniflandirmanin yanitladigi soru kumesi");
yaz(Q, "soru", "veri", "yanit");
const SORU = [
  ["bu olay birini uyandirmali mi", "gorunur imza", true],
  ["hangi onem duzeyinde", "gorunur imza", true],
  ["yanit gelmezse kim cagrilir", "tirmandirma zinciri", true],
  ["ne zaman bir sonraki basamak", "tirmandirma zinciri", true],
  ["olay gercekten kac aboneyi etkiledi", "-", false],
  ["etiket dogru muydu", "-", false],
  ["kimseye ulasmadiysa ne oldu", "-", false]];
for (const [q, d, y] of SORU) yaz(Q, q, d, y ? "evet" : "hayir");
console.log(`${SORU.length} sorudan ${say(SORU, (x) => x[2])} tanesi cagri aninda yanitlanir, ` +
  `${say(SORU, (x) => !x[2])} tanesi olay kapanmadan yanitlanamaz`);
```

```
tohum 20260921: 60 olay, 15 tanesi gece, 17 tanesi uretim disi
gercek duzey dagilimi: d1 12, d2 14, d3 13, d4 21

1. iki siniflandirma kurali ayni olay kumesinde
kural     dogru   fazla yukseltme   fazla dusurme   cagri ureten   gercek cagri
A            37                16               7             31             26
B            27                28               5             40             26

2. yanlis siniflandirmanin iki yonlu bedeli
kural     ger. uyandirma   kayip saat    gec. mudahale    gecikme dk   etki-dakika
A                      3           12                5         306.0         11040
B                      7           28                1          60.0           180
A -> B degis tokusu: kayip saat +16, etki-dakika -10860 (uyanik kalinan saat basina 678.8 etki-dakika)

3. kural A'nin karistirdigi olaylar (etiket -> gercek)
etiket \ gercek       d1      d2      d3      d4
d1                     8       6       0       0
d2                     0       7      10       0
d3                     0       0       1       0
d4                     4       1       2      21

4. tirmandirma zinciri taramasi (kural B'nin cagri urettigi olaylar)
basamak  bekleme    ort basamak   ort ulasma dk  ulasilamayan olay   uyanan kisi
2        5 dk               1.4             2.8                  5            57
2        15 dk              1.4             8.3                  5            57
3        5 dk               1.6             3.0                  2            62
3        15 dk              1.6             9.0                  2            62
4        5 dk               1.6             3.3                  2            64
4        15 dk              1.6             9.8                  2            64
40 cagri, 12 tanesi gece; gereksiz uyandirmanin penceresi 4 saat

5. siniflandirmanin yanitladigi soru kumesi
soru                                                      veri   yanit
bu olay birini uyandirmali mi                     gorunur imza    evet
hangi onem duzeyinde                              gorunur imza    evet
yanit gelmezse kim cagrilir                tirmandirma zinciri    evet
ne zaman bir sonraki basamak               tirmandirma zinciri    evet
olay gercekten kac aboneyi etkiledi                          -   hayir
etiket dogru muydu                                           -   hayir
kimseye ulasmadiysa ne oldu                                  -   hayir
7 sorudan 4 tanesi cagri aninda yanitlanir, 3 tanesi olay kapanmadan yanitlanamaz
```

Sayılar **ölçüm** sınıfındadır; girdileri OY7–OY12 varsayımlarıdır. Altmış olayın 15'i gece düşer,
17'si üretim dışı ortamdadır ve gerçekten çağrı hak eden (`d1` ya da `d2`) olay sayısı 26'dır. Eşik
kuralı A 31, ihtiyatlı kural B 40 çağrı üretir; ikisi de gerçeğin üstündedir.

#### Doğruluk Bedeli Ölçmez

Birinci tablo iki kuralı doğru etiket sayısıyla karşılaştırırsa A açık ara kazanır: 60 olayın
37'sini doğru etiketler, B ise 27'sini. Fazla yükseltme A'da 16, B'de 28'dir. Bu ölçüyle bakan biri
A'yı seçer.

İkinci tablo kararı tersine çevirir. A'nın 16 fazla yükseltmesinin yalnız **3'ü** gece düşer, yani
12 saatlik toparlanma penceresi maliyeti vardır; B'nin 28 yükseltmesinin 7'si geceye denk gelir ve
28 saat götürür. Buna karşılık A'nın 5 geciken müdahalesi ortalama 306 dakika bekler ve **11.040
etki-dakika** üretir; B'nin tek geciken müdahalesi 60 dakikada 180 etki-dakika. Değiş tokuş tek
satırda okunur: A'dan B'ye geçiş 16 saatlik uykuya karşılık 10.860 etki-dakika satın alır, yani
**uyanık kalınan saat başına 678,8 etki-dakika**. **Doğru etiket oranı bir kalite ölçüsü değildir;
iki yönün bedeli farklı birimdedir ve ancak ayrı ayrı sayılırsa karşılaştırılabilir.**

#### Kuralın Göremediği Sessiz Bozulma

Üçüncü tablo A'nın nerede yanıldığını gösterir. `d4` satırında dört gerçek `d1` vardır: kural bu
dört olayı iş listesine atmıştır. Dördü de aynı yerdedir — `faturalama` servisinde veri kaybı, hata
oranı 0,01 ile 0,05 arasında, gecikme katı 1,2 ile 1,8 arasında. **Sessiz bozulma görünür imzada
sağlıklı bir servisten ayırt edilemez**; 11.040 etki-dakikanın 10.320'si bu dört olaydan gelir.

B bu dördünü yakalar, ama bunu bir kuralla değil bir **istisnayla** yapar: `faturalama` servisinin
tabanını `d2`'ye çeker. İstisna sessizliği görmez, sessizliğin nerede olduğunu ezberler. Fiyatı da
budur — o servisin hafif olayları da çağrı üretmeye başlar ve B'nin gereksiz uyandırması 3'ten
7'ye çıkar. B'nin kaçırdığı tek olay `dogrulayici` servisindeki sessiz bir `d2`'dir: **istisna
yazılmayan yerde aynı boşluk durmaktadır.**

`d2` satırındaki on olay ters yöndedir: gerçek `d3` olan olaylar üretim ortamında 0,25 üstü hata
oranı gösterdiği için yükseltilmiştir. Bu on yükseltmenin bedeli neredeyse sıfırdır, çünkü
çoğu gündüz düşer. **Aynı sayıdaki yanlış etiket, düştüğü saate göre bedelsiz ya da dört saatliktir.**

#### Zincir Kaç Basamak, Basamak Kaç Dakika

Dördüncü tablo B'nin ürettiği 40 çağrıyı tırmandırma zincirinden geçirir; 12'si gecedir ve gece
yanıt olasılığı düşüktür. İki basamaklı zincirde **5 olay kimseye ulaşmaz**. Üçüncü basamak bu
sayıyı 2'ye indirir, ortalama basamak 1,4'ten 1,6'ya çıkar ve toplam uyanan kişi 57'den 62'ye
yükselir: beş olayın üçünü kurtarmak beş ek uyandırmaya mal olur. **Dördüncü basamak hiçbir şey
kazandırmaz** — ulaşılamayan olay 2'de kalır, uyanan kişi 64'e çıkar.

Bekleme süresi ikinci eksendir ve ulaşılamayanı hiç değiştirmez: 5 dakikadan 15 dakikaya çıkarmak
ortalama ulaşmayı 2,8'den 8,3 dakikaya taşır, karşılığında tek bir olay kazandırmaz. **Zincirin
uzunluğu kaç olayın karşılandığını, bekleme süresi yalnız ne kadar geç karşılandığını belirler.**

#### Özet

- Altmış olayın 26'sı gerçekten çağrı hak eder; eşik kuralı 31, ihtiyatlı kural 40 çağrı üretir ve
  her ikisi de gerçeğin üstünde kalır.
- Doğru etiket sayısı A'da 37, B'de 27'dir; buna karşılık A 11.040, B 180 etki-dakika üretir —
  doğruluk oranı iki yönün bedelini ölçmez.
- İki yön ayrı birimdedir: A'da 3 gereksiz gece uyandırma (12 saat) ve 5 geciken müdahale
  (ortalama 306 dakika); B'de 7 uyandırma (28 saat) ve 1 geciken müdahale (60 dakika). Geçişin
  fiyatı uyanık kalınan saat başına 678,8 etki-dakikadır.
- A'nın kaçırdığı dört `d1` olayının dördü de `faturalama` servisinde sessiz veri kaybıdır: hata
  oranı 0,01–0,05, gecikme katı 1,2–1,8. Görünür imza sessizliği sağlıklıdan ayıramaz.
- Tırmandırmada iki basamak 5 olayı kimseye ulaştıramaz; üçüncü basamak bunu 2'ye indirir ve 5 ek
  uyandırmaya mal olur, dördüncü basamak yalnız 2 kişi daha uyandırır.
- Bekleme süresini 5'ten 15 dakikaya çıkarmak ortalama ulaşmayı 2,8'den 8,3 dakikaya taşır,
  ulaşılamayan olay sayısını hiç değiştirmez.

#### Sonraki Adım

Yedi sorudan dördü çağrı anında yanıtlanır; "olay kaç aboneyi etkiledi", "etiket doğru muydu" ve
"kimseye ulaşmadıysa ne oldu" ancak olay kapandıktan sonra yanıtlanabilir. Çağrı doğru kişiye
doğru düzeyde ulaştığında geriye tek soru kalır: **hangi adımla** kapanacak. Sonraki ders bu adımı
bir belge olarak ölçer — kaç adım, kaç karar noktası, kaçı otomatikleştirilebilir, yordamla ve
yordamsız kapanış süresi ne kadar farklı ve bir dönem sonra kaç adım geçersiz.

### Çalışma Yordamları

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/calisma-yordamlari

Yordamın kendisi ölçülür: dört yordamın 33 adımı, 6 karar noktası ve 14 otomatikleştirilebilir adımı, aynı 40 olayın yordamsız 203,1 dakikada 113 hata adımıyla, yazılı yordamla 72,8 dakikada 40 hata adımıyla kapanması, iki dönem eskiyen yordamın kapanışı yalnız 83,3 dakikaya taşırken hata adımını 161'e çıkarması ve dört dönem sonra 33 adımın 24'ünün geçersiz olup ilk koşumlarda 384 dakika gecikme üretmesi.

Nöbet düzeni "kim" ve "ne zaman" sorularını yanıtladı, sınıflandırma "hangi düzeyde" sorusunu
ekledi. Doğru kişi doğru anda uyandığında elinde tek bir soru kalır: **hangi adımla**.

**Çalışma yordamı**, yinelenen bir müdahalenin adım adım yazılmış hâlidir. M20/K05 `İşletim Devri`
dersi **yazılmamış yordamın** devir üzerindeki bedelini saydı; burada yordam yazılıdır ve ölçülen
**yordamın kendisidir**: kaç adım, kaç karar noktası, kaçı makineye verilebilir ve yazıldıktan bir
süre sonra kaçı hâlâ doğru.

#### Yordam Bir Belge Değil, Bir Adım Dizisi

Örnek yine kursun kurgu **bölgesel ölçüm ağı**dır: su sayacı okuma toplayıcı, doğrulayıcı,
faturalama ve iş emri servisleri. Ağ da yordamlar da kurgudur; gerçek bir yordam metni ya da koşum
geçmişi yoktur.

**OY13:** Dört yinelenen müdahale için birer yordam yazılır; adım türü **gözle**, **doğrula**,
**müdahale** ya da **karar**dır ve karar noktası hiçbir koşulda otomatikleştirilemez. **OY14:** Her
adım bir **dayanağa** bağlıdır — gösterge adı, seri adı, eşik değeri, dosya yolu, bayrak adı, kuyruk
adı, kimlik alanı, sürüm etiketi. Dayanak değişirse o dayanağa bağlı her adım geçersizdir.
**OY15:** Yordamsız koşumda adımı bulmak süreyi 2,8 katına çıkarır ve adım başına hata olasılığı
0,34'tür; yazılı yordamla 0,08. Hatalı adımın düzeltilmesi 9 dakikadır. **OY16:** Karar noktasında
yanlış dal seçme olasılığı 0,18, bedeli 12 dakikadır. **OY17:** Geçersiz adım ilk koşumda 16 dakika
gecikme üretir; sonraki koşumlarda bilindiği için 3 dakikada dolanılır, ama her iki durumda da hata
adımı sayılır. **OY18:** Her dönemde iki dayanak değişir; aynı yordam kümesi 40 olayda koşulur.

```js
// yordam/yordam.mjs — kurgu bolgesel olcum aginin calisma yordami modeli (model): gercek bir
// yordam metni, olay kaydi ya da kosum gecmisi yok. Uretec kendi yazildi, tohum gorunur.

export const SERVIS = ["okuma-toplayici", "dogrulayici", "faturalama", "is-emri"];
export const TUR = ["gozle", "dogrula", "mudahale", "karar"];
// Adimin bagli oldugu sistem gercegi. Bu dayanak degisirse adim gecersiz olur.
export const DAYANAK = ["gosterge-adi", "seri-adi", "esik-degeri", "dosya-yolu", "bayrak-adi",
  "kuyruk-adi", "kimlik-alani", "surum-etiketi"];

export const KESIF = 2.8;        // yordamsiz kosumda adimi bulmanin sure carpani
export const HATA = { yok: 0.34, var: 0.08 };   // adim basina hata olasiligi
export const DUZELT = 9;         // hatali adimin duzeltilmesi (dakika)
export const YANLIS_DAL = 0.18;  // karar noktasinda yanlis dal secme olasiligi
export const DAL_CEZA = 12;      // yanlis dalin bedeli (dakika)
export const ILK_CEZA = 16;      // gecersiz adim ilk kosumda: denenir, tutmaz, elle bulunur
export const SONRAKI_CEZA = 3;   // ayni adim sonraki kosumlarda: bilinir, dolanilir
export const DEGISIM = 2;        // her donemde sistemde degisen dayanak sayisi

export function uretec(tohum) {
  let x = tohum >>> 0 || 1;
  return () => { x ^= x << 13; x >>>= 0; x ^= x >>> 17; x ^= x << 5; x >>>= 0;
    return x / 4294967296; };
}
const sec = (r, a) => a[Math.floor(r() * a.length)];

// Her servis icin bir yordam: 6-10 adim. Otomatiklestirilebilirlik adimin turune baglidir;
// karar noktasi hicbir kosulda otomatiklestirilemez.
export function yordamlar(tohum) {
  const r = uretec(tohum);
  return SERVIS.map((servis) => {
    const adet = 6 + Math.floor(r() * 5);
    const adim = [];
    for (let i = 0; i < adet; i++) {
      const u = r();
      const tur = u < 0.22 ? "gozle" : u < 0.52 ? "dogrula" : u < 0.82 ? "mudahale" : "karar";
      const otomatik = tur === "karar" ? false
        : r() < (tur === "mudahale" ? 0.40 : 0.75);
      adim.push({ tur, otomatik, dakika: 2 + Math.floor(r() * 11),
        dayanak: sec(r, DAYANAK) });
    }
    return { servis, adim };
  });
}

// mod: "yok" yordamsiz, "var" yazili yordamla, "oto" otomatiklestirilebilir adimlar makinede.
// gecersiz: gecersiz dayanaklar. gorulen: daha once bir kosumda ortaya cikmis gecersiz adimlar;
// gecersiz adim yalnizca ILK kosumda tam bedelini uretir, sonrakilerde dolanilir.
export function kos(y, mod, r, gecersiz = new Set(), gorulen = new Set()) {
  let dakika = 0, hataAdim = 0, ilkGecikme = 0, atlanan = 0;
  for (const [i, a] of y.adim.entries()) {
    const oto = mod === "oto" && a.otomatik;
    if (oto) { atlanan++; } else { dakika += a.dakika * (mod === "yok" ? KESIF : 1); }
    if (gecersiz.has(a.dayanak)) {      // yordam sistemin gerisinde kaldi
      const anahtar = `${y.servis}:${i}`;
      if (gorulen.has(anahtar)) { dakika += SONRAKI_CEZA; hataAdim++; continue; }
      gorulen.add(anahtar);
      dakika += ILK_CEZA; ilkGecikme += ILK_CEZA; hataAdim++;
      continue;
    }
    if (oto) continue;                  // makinede kosan adim yanilmaz
    if (r() < HATA[mod === "yok" ? "yok" : "var"]) { dakika += DUZELT; hataAdim++; }
    if (a.tur === "karar" && r() < YANLIS_DAL) { dakika += DAL_CEZA; hataAdim++; }
  }
  return { dakika, hataAdim, ilkGecikme, atlanan };
}

// Eskime: her donemde DEGISIM dayanak degisir. Degisen dayanaga bagli her adim gecersizdir.
export function eskit(tohum, donem) {
  const r = uretec(tohum), g = new Set();
  for (let d = 0; d < donem; d++)
    for (let i = 0; i < DEGISIM; i++) g.add(sec(r, DAYANAK));
  return g;
}
```

```js
// yordam/olc.mjs — yordamin kendisi: adim, karar noktasi, otomatiklestirme ve eskime.
import { yordamlar, kos, eskit, uretec, TUR, DAYANAK, DEGISIM } from "./yordam.mjs";

const TOHUM = 20261107;
const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const s1 = (x) => x.toFixed(1);
const say = (a, f) => a.filter(f).length;

const Y = yordamlar(TOHUM);
const tumAdim = Y.flatMap((y) => y.adim);
const KOSUM = 40;                      // ayni yordam kumesi 40 olayda kosulur

// Ayni olay kumesini bir bicimde kosar. Her kosum ayni tohumdan baslar, boylece bicimler
// arasindaki fark bicimden gelir, cekilislerden degil.
const dene = (mod, gecersiz) => {
  const r = uretec(TOHUM + 7), gorulen = new Set(), kayit = [];
  for (let i = 0; i < KOSUM; i++) kayit.push(kos(Y[i % Y.length], mod, r, gecersiz, gorulen));
  const t = (f) => kayit.reduce((a, x) => a + f(x), 0);
  return { dakika: t((x) => x.dakika) / KOSUM, hata: t((x) => x.hataAdim),
    ilk: t((x) => x.ilkGecikme), atlanan: t((x) => x.atlanan) };
};

const E = [-16, 7, 12, 15, 10, 11];
console.log(`tohum ${TOHUM}: ${Y.length} yordam, ${tumAdim.length} adim, ${KOSUM} kosum`);
console.log("\n1. yordam envanteri");
yaz(E, "yordam", "adim", "karar nok.", "otomatik adim", "dakika", "dayanak");
for (const y of Y)
  yaz(E, y.servis, y.adim.length, say(y.adim, (a) => a.tur === "karar"),
    say(y.adim, (a) => a.otomatik), y.adim.reduce((a, x) => a + x.dakika, 0),
    new Set(y.adim.map((a) => a.dayanak)).size);
yaz(E, "toplam", tumAdim.length, say(tumAdim, (a) => a.tur === "karar"),
  say(tumAdim, (a) => a.otomatik), tumAdim.reduce((a, x) => a + x.dakika, 0),
  new Set(tumAdim.map((a) => a.dayanak)).size);
console.log("adim turu: " + TUR.map((t) => `${t} ${say(tumAdim, (a) => a.tur === t)}`).join(", "));

const g2 = eskit(TOHUM + 3, 2);        // iki donem eskimis yordam
const M = [-22, 17, 14, 16, 16];
console.log("\n2. ayni 40 olay uc kosum biciminde (taze yordam / iki donem eskimis)");
yaz(M, "bicim", "ort kapanis dk", "hata adimi", "makinede adim", "yordamsiza gore");
const taze = {}, eski = {};
for (const [ad, b] of [["yordamsiz", "yok"], ["yazili yordamla", "var"],
  ["otomatiklestirilmis", "oto"]]) {
  taze[b] = dene(b, new Set());
  eski[b] = b === "yok" ? taze[b] : dene(b, g2);
  const pay = (x) => `%${((x.dakika / taze.yok.dakika) * 100).toFixed(0)}`;
  yaz(M, ad, `${s1(taze[b].dakika)} / ${s1(eski[b].dakika)}`,
    `${taze[b].hata} / ${eski[b].hata}`, `${taze[b].atlanan} / ${eski[b].atlanan}`,
    `${pay(taze[b])} / ${pay(eski[b])}`);
}

const D = [-8, 15, 15, 19, 16, 13];
console.log(`\n3. yordamin eskimesi (yazili yordam, donem basina ${DEGISIM} degisim)`);
yaz(D, "donem", "gecersiz day.", "gecersiz adim", "ilk kosum gecikme", "ort kapanis dk",
  "hata adimi");
for (const donem of [0, 1, 2, 3, 4]) {
  const g = eskit(TOHUM + 3, donem);
  const r = dene("var", g);
  yaz(D, donem, `${g.size}/${DAYANAK.length}`,
    `${say(tumAdim, (a) => g.has(a.dayanak))}/${tumAdim.length}`,
    `${r.ilk} dk`, s1(r.dakika), r.hata);
}

const Q = [-38, 20, 8];
console.log("\n4. yordamin yanitladigi soru kumesi");
yaz(Q, "soru", "veri", "yanit");
const SORU = [
  ["bu olay daha once oldu mu", "yordam dizini", true],
  ["hangi adimla kapanir", "yordam metni", true],
  ["kac adim, kac karar noktasi", "yordam metni", true],
  ["hangi adim makineye verilebilir", "adim turu", true],
  ["yordam en son ne zaman kosuldu", "kosum kaydi", true],
  ["bu adim hala gecerli mi", "-", false],
  ["karar noktasinda dogru dal hangisi", "-", false],
  ["kac adim artik gecersiz", "-", false]];
for (const [q, d, y] of SORU) yaz(Q, q, d, y ? "evet" : "hayir");
console.log(`${SORU.length} sorudan ${say(SORU, (x) => x[2])} tanesi yordamdan yanitlanir, ` +
  `${say(SORU, (x) => !x[2])} tanesi yordam kosulmadan yanitlanamaz`);
```

```
tohum 20261107: 4 yordam, 33 adim, 40 kosum

1. yordam envanteri
yordam             adim  karar nok.  otomatik adim    dakika    dayanak
okuma-toplayici       6           2              2        47          3
dogrulayici           9           1              5        64          5
faturalama           10           0              5        86          6
is-emri               8           3              2        56          5
toplam               33           6             14       253          8
adim turu: gozle 7, dogrula 8, mudahale 12, karar 6

2. ayni 40 olay uc kosum biciminde (taze yordam / iki donem eskimis)
bicim                    ort kapanis dk    hata adimi   makinede adim yordamsiza gore
yordamsiz                 203.1 / 203.1     113 / 113           0 / 0     %100 / %100
yazili yordamla             72.8 / 83.3      40 / 161           0 / 0       %36 / %41
otomatiklestirilmis         37.5 / 49.8      25 / 154       140 / 140       %18 / %24

3. yordamin eskimesi (yazili yordam, donem basina 2 degisim)
donem     gecersiz day.  gecersiz adim  ilk kosum gecikme  ort kapanis dk   hata adimi
0                   0/8           0/33               0 dk            72.8           40
1                   2/8          10/33             160 dk            80.6          126
2                   3/8          14/33             224 dk            83.3          161
3                   5/8          20/33             320 dk            88.1          214
4                   6/8          24/33             384 dk            91.6          251

4. yordamin yanitladigi soru kumesi
soru                                                  veri   yanit
bu olay daha once oldu mu                    yordam dizini    evet
hangi adimla kapanir                          yordam metni    evet
kac adim, kac karar noktasi                   yordam metni    evet
hangi adim makineye verilebilir                  adim turu    evet
yordam en son ne zaman kosuldu                 kosum kaydi    evet
bu adim hala gecerli mi                                  -   hayir
karar noktasinda dogru dal hangisi                       -   hayir
kac adim artik gecersiz                                  -   hayir
8 sorudan 5 tanesi yordamdan yanitlanir, 3 tanesi yordam kosulmadan yanitlanamaz
```

Sayılar **ölçüm** sınıfındadır; girdileri OY13–OY18 varsayımlarıdır. Dört yordam 33 adım, 6 karar
noktası ve 253 dakikalık nominal süre taşır. Envanter tek başına iki şeyi söyler. `faturalama` en
uzun yordamdır (10 adım, 86 dakika) ama hiç karar noktası yoktur — baştan sona düz koşar.
`is-emri` yalnız 8 adımdır, ama 3 karar noktası taşır: kısa yordam kolay yordam değildir.

#### Yordamsız, Yordamla, Makineyle

İkinci tablonun sol yarısı aynı 40 olayı üç biçimde kapatır. Yordamsız koşumda ortalama kapanış
203,1 dakika ve 113 hata adımıdır; adımı bulmak süreyi katlar ve her bulunan adım yanılabilir.
Yazılı yordam kapanışı 72,8 dakikaya, yani **yordamsızın %36'sına** indirir ve hata adımını 113'ten
40'a düşürür. Kazanç iki kaynaklıdır ve ayrılabilir: keşif çarpanının kalkması süreyi, hata
olasılığının 0,34'ten 0,08'e inmesi yanılmayı azaltır.

Otomatikleştirme üçüncü sırayı alır. 33 adımın 14'ü makineye verilebilir (%42) ve 40 koşumda
toplam 140 adım makinede koşar; kapanış 37,5 dakikaya, yordamsızın **%18'ine** iner, hata adımı
25'e düşer. Bu tavan tesadüf değildir: kalan 19 adımın 6'sı **karar noktasıdır** ve varsayım gereği
otomatikleştirilemez. **Yordamın otomatikleştirilemeyen çekirdeği, sayılabilen bir büyüklüktür** —
burada altı karar.

#### Yordamın Eskimesi

Üçüncü tablo yordamı olduğu yerde bırakıp sistemi değiştirir. Bir dönemde iki dayanak değişir ve
33 adımın **10'u** geçersiz olur; dört dönem sonra sekiz dayanağın altısı değişmiş, geçersiz adım
24'e çıkmıştır. Geçersiz adımın ilk koşumdaki bedeli doğrudan okunur: birinci dönemde 160, dördüncü
dönemde 384 dakika.

Asıl bulgu iki sütunun **farklı hızda** bozulmasıdır. Ortalama kapanış 72,8'den 91,6 dakikaya
çıkar — dört dönemde yalnız %26. Hata adımı ise 40'tan 251'e, altı katına çıkar. Nedeni varsayımın
içindedir: geçersiz adım ilk koşumda 16 dakika yer, sonraki koşumlarda 3 dakikada dolanılır, ama
her seferinde bir hata adımı olarak kalır. **Eskiyen yordam yavaşlamaz, güvenilmez hâle gelir**;
saati izleyen bir ölçüm bunu göremez.

İkinci tablonun sağ yarısı bunu keskinleştirir. İki dönem eskimiş yordam kapanışı yalnız 72,8'den
83,3 dakikaya taşır ve hâlâ yordamsızdan çok hızlıdır (%41'e karşı %100). Ama hata adımı 161'dir —
**yordamsız koşumun 113 hata adımından fazla**. Eskimiş yordam koşanı hızlandırırken yanlış adıma
daha çok kez sokar.

Otomatikleştirme bu bozulmayı durdurmaz. Makineye verilen adım da aynı dayanağa bağlıdır: iki dönem
sonra otomatikleştirilmiş biçimin hata adımı 25'ten 154'e çıkar, yani yazılı yordamın 161'iyle
neredeyse aynı yerdedir. Kapanış 37,5'ten 49,8 dakikaya çıkar. **Otomatikleştirme adımı hızlandırır,
adımın dayanağını doğrulamaz.**

#### Yordamın Bilmediği

Dördüncü tablo sekiz sorunun beşinin yordamdan yanıtlandığını gösterir: olayın daha önce olup
olmadığı, hangi adımla kapanacağı, kaç adım ve kaç karar noktası olduğu, hangi adımın makineye
verilebileceği, yordamın en son ne zaman koşulduğu. Yanıtsız üçü tek bir eksikliğe indirgenir —
**yordam kendi geçerliliğini bilmez**. "Bu adım hâlâ geçerli mi", "karar noktasında doğru dal
hangisi" ve "kaç adım artık geçersiz" soruları ancak yordam koşulduğunda, yani bir olayın ortasında
yanıtlanır. Üçüncü tablodaki 160 ile 384 dakika arasındaki gecikme, bu üç sorunun faturasıdır.

#### Özet

- Dört yordam 33 adım, 6 karar noktası ve 253 dakikalık nominal süre taşır; adımların 14'ü (%42)
  makineye verilebilir. En uzun yordamda hiç karar noktası yok, 8 adımlık yordamda üç tane var.
- Aynı 40 olay yordamsız 203,1 dakikada ve 113 hata adımıyla, yazılı yordamla 72,8 dakikada (%36)
  ve 40 hata adımıyla kapanır.
- Otomatikleştirme kapanışı 37,5 dakikaya (%18) ve hata adımını 25'e indirir; tavanı belirleyen
  şey otomatikleştirilemeyen 6 karar noktasıdır.
- Bir dönemde iki dayanak değişince 33 adımın 10'u, dört dönem sonra 24'ü geçersiz olur; geçersiz
  adımların ilk koşumda ürettiği gecikme 160'tan 384 dakikaya çıkar.
- Eskime süreyi ve güveni farklı hızda bozar: kapanış 72,8'den 91,6 dakikaya (%26) çıkarken hata
  adımı 40'tan 251'e (altı katı) çıkar.
- İki dönem eskimiş yordam yordamsızdan hâlâ iki kattan fazla hızlıdır (83,3'e karşı 203,1
  dakika) ama
  yordamsızdan çok yanılır (161'e karşı 113 hata adımı); otomatikleştirme bunu değiştirmez (154).

#### Sonraki Adım

Yordam bir olayın **nasıl** kapanacağını yazar, **neden** açıldığını yazmaz. Üçüncü tablodaki
geçersiz adımlar da kendiliğinden düzelmez; birinin onları görüp yordamı güncellemesi gerekir.
Sonraki ders olay kapandıktan sonrasına bakar: olayın suçsuz biçimde incelenmesi, incelemeden çıkan
eylem maddelerinin izlenmesi ve kapanmayan maddenin aynı olayı yeniden üretmesi.

### Olay Sonrası İnceleme

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/olay-sonrasi-inceleme

Eylem maddesinin izlenmesinin ölçülmesi: 18 dönemde incelemesiz koşumun 48 olay ve %90 tekrar bırakması, kök neden kişi yazıldığında 96 maddenin %84'ünün 6,9 günde kapanmasına karşılık yalnız 15'inin sistemsel düzeltme olması ve tekrarın %84'te kalması, süreç yazıldığında 75 maddenin 42'sinin sistemsel çıkıp olayın 25'e inmesi, takip bırakıldığında 61 sistemsel maddenin 46'sının hiç kapanmayıp yinelenen olay oranının %84'e ve yineleme kesintisinin 1105 dakikaya çıkması, sekiz sorudan yedisinin 76.800 baytla yanıtlanıp sekizincisinin hiçbir kayıt katmanında bulunmaması.

Önceki ders çalışma yordamının kendisini saydı: adım sayısı, karar noktası ve eskimiş adım. Yordam
yazıldı, olay kapandı, hat açıldı. Sonrasında hiç sorulmayan bir soru kaldı: aynı olay bir daha
olacak mı, olmaması için ne yapıldı ve o iş bitti mi.

Olay sonrası çözümlemenin kendisi M16/K07'de ölçüldü. Burada ölçülen incelemenin **çıktısı** değil,
çıktının **izlenmesidir**. Ölçü şudur: bir dönemde kaç eylem maddesi açıldı, kaçı kapandı, kapanma
ne kadar sürdü ve **kapanmayan madde kaç kez aynı olayı yeniden üretti**. Suçsuz incelemenin de
ölçülebilir bir karşılığı vardır: kök neden **kişi** olarak yazıldığında ve **süreç** olarak
yazıldığında kaç sistemsel düzeltme çıkıyor.

#### Soru Kümesi ve Kayıt Katmanları

Örnek yine kurgu **bölgesel ölçüm ağı**dır; sayaç okuma toplayıcısı, doğrulayıcı, faturalama ve iş
emri servisleri. Olay geçmişi de inceleme kütüğü de kurgudur.

**OY19:** on sekiz dönem koşulur, dönem 30 gündür; beş neden sınıfının her birinin sabit bir günlük
olay olasılığı ve sabit bir kesinti dakikası vardır. **OY20:** her olay üç gün sonra incelenir,
inceleme beş kişi-saat tutar. **OY21:** her inceleme üç eylem maddesi açar; kök neden ya kişi ya
süreç olarak yazılır ve yazım, madde türlerinin payını belirler — kişide hatırlatma 0,55, belge
0,30, sistemsel 0,15; süreçte sistemsel 0,55, belge 0,25, hatırlatma 0,20. **OY22:** madde türü
kapanma olasılığını, kapanma süresini ve kapanan madde başına kişi-saati belirler; takip çarpanı
kapanma olasılığını ölçekler, 0,98'de tavanlanır. **OY23:** kapanan bir **sistemsel** madde, kendi
sınıfının günlük olay olasılığını 0,70 ile çarpar; belge ve hatırlatma hiçbir olasılığı
değiştirmez. **OY24:** *tekrar*, sınıfın daha önce olay üretmiş olmasıdır; *yinelenen olay*,
sınıfın hiç kapanmayacak bir sistemsel maddesi açıkta beklerken sınıfın yeniden olay üretmesidir.
Tohum 20260812'dir ve bütün zarlar baştan atılır, böylece beş koşum aynı diziyi paylaşır.

Olaylar, incelemeler ve maddeler süreç içi bir **modeldir**; gerçek bir olay kaydı yoktur.

```js
// inceleme/model.mjs — olay sonrasi inceleme modeli: gercek bir olay kaydi yok; gunler,
// olaylar ve eylem maddeleri veri yapisidir. Uretec kendi yazilir, tohum gorunur.

export const DONEM = 30, DONEM_SAY = 18, GUN = DONEM * DONEM_SAY;
export const TOHUM = 20260812, MADDE = 3, GECIKME = 3, DUSUS = 0.70;
// neden sinifi: ad, gunluk olay olasiligi, kesinti dakikasi
export const SINIF = [["yapilandirma kaymasi", 0.030, 25], ["kapasite", 0.022, 40],
  ["bagimlilik zaman asimi", 0.026, 18], ["veri kalitesi", 0.020, 55],
  ["toplu is penceresi", 0.016, 70]];
// madde turu: kapanma olasiligi, kapanma gunu, kapanan madde basina kisi-saat
export const TUR = { sistemsel: [0.55, 25, 12], belge: [0.80, 8, 3], hatirlatma: [0.95, 2, 0.5] };
// kok neden kisi ya da surec olarak yazildiginda acilan madde turlerinin paylari
export const KARISIM = { kisi: [["hatirlatma", 0.55], ["belge", 0.30], ["sistemsel", 0.15]],
  surec: [["sistemsel", 0.55], ["belge", 0.25], ["hatirlatma", 0.20]] };
export const INCELEME_SAAT = 5;                    // olay basina inceleme kisi-saati

export function uretec(tohum) {                    // dogrusal eslesmeli uretec
  let x = tohum >>> 0;
  return () => ((x = (x * 1664525 + 1013904223) >>> 0) / 2 ** 32);
}

// butun zarlar bastan atilir: kosumlar ayni olay ve madde dizisini paylasir
const Z = (() => { const z = uretec(TOHUM);
  return Array.from({ length: GUN * SINIF.length }, () => ({ olay: z(),
    madde: Array.from({ length: MADDE }, () => ({ tur: z(), kapanma: z(), sure: z() })) })); })();
const sec = (pay, p) => { let e = 0; for (const [ad, y] of pay) { e += y; if (p < e) return ad; } };

export function kos({ inceleme = true, yazim = "surec", takip = 1.0 } = {}) {
  const carpan = SINIF.map(() => 1), acikSis = SINIF.map(() => 0);   // sinif basina durum
  const oluSis = SINIF.map(() => 0), gorulen = SINIF.map(() => 0), olaylar = [], maddeler = [];
  for (let g = 0; g < GUN; g++) {
    for (const m of maddeler)                      // kapanis gunu gelen madde kapanir
      if (m.durum === "acik" && m.kapanis === g) {
        m.durum = "kapandi";
        if (m.tur === "sistemsel") { carpan[m.sinif] *= DUSUS; acikSis[m.sinif]--; }
      }
    for (let s = 0; s < SINIF.length; s++) {
      const z = Z[g * SINIF.length + s];
      if (z.olay >= SINIF[s][1] * carpan[s]) continue;
      // tekrar: sinif daha once olay uretti. yinelenen: sinifin hic kapanmayacak
      // sistemsel maddesi acikta beklerken ayni sinif yeniden olay uretti
      olaylar.push({ g, sinif: s, kesinti: SINIF[s][2],
        tekrar: gorulen[s]++ > 0, yinelenen: oluSis[s] > 0 });
      if (!inceleme) continue;
      for (const d of z.madde) {
        const tur = sec(KARISIM[yazim], d.tur), [kap, sure] = TUR[tur];
        const kapanir = d.kapanma < Math.min(0.98, kap * takip);
        const gecen = Math.round(sure * (0.6 + 0.8 * d.sure));
        maddeler.push({ sinif: s, tur, acilis: g + GECIKME, durum: "acik",
          kapanis: kapanir ? g + GECIKME + gecen : null, gecen: kapanir ? gecen : null });
        if (tur === "sistemsel") { acikSis[s]++; if (!kapanir) oluSis[s]++; }
      }
    }
  }
  return { olaylar, maddeler };
}

const ort = (a) => (a.length ? (a.reduce((s, v) => s + v, 0) / a.length).toFixed(1) : "-");
const yuz = (a, b) => (b ? (100 * a / b).toFixed(0) + "%" : "-");

export function olc(ayar) {
  const { olaylar, maddeler } = kos(ayar), M = maddeler.length;
  const kapanan = maddeler.filter((m) => m.durum === "kapandi");
  const yin = olaylar.filter((o) => o.yinelenen), tek = olaylar.filter((o) => o.tekrar);
  const dk = (a) => a.reduce((s, o) => s + o.kesinti, 0);
  const sis = maddeler.filter((m) => m.tur === "sistemsel");
  return { olay: olaylar.length, kesinti: dk(olaylar), acilan: M, kapanan: kapanan.length,
    tekrar: tek.length, tekrarOran: yuz(tek.length, olaylar.length), tekrarKesinti: dk(tek),
    yinelenen: yin.length, yinOran: yuz(yin.length, olaylar.length), yinKesinti: dk(yin),
    donemMadde: (M / DONEM_SAY).toFixed(1), kapanmaOran: yuz(kapanan.length, M),
    kapanmaSure: ort(kapanan.map((m) => m.gecen)), sis: sis.length, sisPay: yuz(sis.length, M),
    sisKapanan: sis.filter((m) => m.durum === "kapandi").length,
    saat: olaylar.length * (ayar.inceleme === false ? 0 : INCELEME_SAAT)
      + kapanan.reduce((s, m) => s + TUR[m.tur][2], 0) };
}
```

Ölçüm dosyası sekiz soruluk bir küme kurar ve her sorunun yanıtı için gereken kayıt alanlarını
yazar. Katmanlar üst üste binerek eklenir.

```js
// inceleme/olc.mjs — inceleme sorulari hangi kayit katmaniyla yanitlaniyor, eylem maddesi
// izlendiginde ne degisiyor, kapanmayan madde kac olayi yeniden uretiyor.
import { DONEM, DONEM_SAY, SINIF, TOHUM, MADDE, olc } from "./model.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const t0 = process.hrtime.bigint();

// soru kumesi: her sorunun yanitlanmasi icin gereken kayit alanlari
const SORU = [
  ["olay ne zaman oldu, ne kadar surdu", ["olay"]],
  ["kok neden ne yazildi", ["not"]],
  ["kok neden kisi mi surec mi yazildi", ["yazim"]],
  ["incelemeden kac madde acildi", ["kutuk"]],
  ["maddelerin kaci kapandi, ne surede", ["kutuk", "kapanis"]],
  ["kisi yazimi kac sistemsel duzeltme uretti", ["yazim", "kutuk"]],
  ["kapanmayan madde hangi olayi yeniden uretti", ["kutuk", "bag"]],
  ["maddenin kapanmasi hangi kesintiyi onledi", ["karsiOlgu"]],
];
// kayit katmani: ad, actigi alanlar, birim bayt, birimin sayildigi nesne
const KATMAN = [["olay kaydi", ["olay"], 240, "olay"], ["+ inceleme notu", ["not"], 1800, "olay"],
  ["+ yazim alani", ["yazim"], 24, "olay"], ["+ madde kutugu", ["kutuk", "kapanis"], 320, "madde"],
  ["+ madde-sinif bagi", ["bag"], 16, "madde"]];

const K = { "inceleme yok": { inceleme: false }, "kisi yazimi": { yazim: "kisi" },
  "surec yazimi": { yazim: "surec" }, "surec + takip yok": { yazim: "surec", takip: 0.5 },
  "surec + haftalik takip": { yazim: "surec", takip: 1.35 } };
const R = Object.fromEntries(Object.entries(K).map(([a, y]) => [a, olc(y)]));
const T = R["surec yazimi"];

console.log(`${DONEM_SAY} donem x ${DONEM} gun, ${SINIF.length} neden sinifi, ` +
  `inceleme basina ${MADDE} madde; tohum ${TOHUM}`);

console.log("\n1. hangi kayit katmani kac soruyu yanitliyor (surec yazimi kosumu)");
const A = [-21, 8, 13, 10, 12];
yaz(A, "katman", "birim", "kumul. bayt", "yanit/8", "bayt/soru");
let alan = [], bayt = 0;
for (const [ad, ac, b, birim] of KATMAN) {
  alan = alan.concat(ac);
  bayt += b * (birim === "olay" ? T.olay : T.acilan);
  const y = SORU.filter(([, g]) => g.every((f) => alan.includes(f))).length;
  yaz(A, ad, birim, bayt, `${y}/8`, Math.round(bayt / y));
}
console.log("  yanitsiz: " + SORU.filter(([, g]) => g.includes("karsiOlgu")).map(([s]) => s)
  .join("") + " — karsi olgu, hicbir katmanda yok");

console.log("\n2. eylem maddesinin izlenmesi ve madde turu");
const B = [-24, 6, 8, 10, 9, 9, 8, 11, 10];
yaz(B, "kosum", "olay", "acilan", "donem/md", "kapanan", "kapanma", "gun", "sistemsel", "sis. pay");
for (const [ad, r] of Object.entries(R))
  yaz(B, ad, r.olay, r.acilan, r.donemMadde, r.kapanan, r.kapanmaOran, r.kapanmaSure,
    `${r.sis} (${(r.sis / r.olay).toFixed(2)})`, r.sisPay);   // sistemsel: sayi (olay basina)

console.log("\n3. kapanmayan madde ve yinelenen olay");
const C = [-24, 9, 8, 11, 8, 14, 17];
yaz(C, "kosum", "tekrar", "oran", "yinelenen", "oran", "yin. kesinti", "kapanmayan sis.");
for (const [ad, r] of Object.entries(R))
  yaz(C, ad, r.tekrar, r.tekrarOran, r.yinelenen, r.yinOran, r.yinKesinti + " dk",
    `${r.sis - r.sisKapanan}/${r.sis}`);

console.log("\n4. incelemenin bedeli ve yanitsiz sorunun karsiligi");
const D = [-24, 11, 11, 11, 14];
yaz(D, "kosum", "kisi-saat", "saat/olay", "kesinti", "tekrar dk");
for (const [ad, r] of Object.entries(R))
  yaz(D, ad, r.saat.toFixed(0), (r.saat / r.olay).toFixed(1), r.kesinti + " dk",
    `${r.tekrarKesinti} (${(100 * r.tekrarKesinti / r.kesinti).toFixed(0)}%)`);

const ms = Number(process.hrtime.bigint() - t0) / 1e6;   // ham olcum basilmaz, bant denetlenir
console.log(`\nbes kosum ve katman taramasi 2000 ms bandinda: ${ms < 2000 ? "evet" : "hayir"}`);
```

```
18 donem x 30 gun, 5 neden sinifi, inceleme basina 3 madde; tohum 20260812

1. hangi kayit katmani kac soruyu yanitliyor (surec yazimi kosumu)
katman                  birim  kumul. bayt   yanit/8   bayt/soru
olay kaydi               olay         6000       1/8        6000
+ inceleme notu          olay        51000       2/8       25500
+ yazim alani            olay        51600       3/8       17200
+ madde kutugu          madde        75600       6/8       12600
+ madde-sinif bagi      madde        76800       7/8       10971
  yanitsiz: maddenin kapanmasi hangi kesintiyi onledi — karsi olgu, hicbir katmanda yok

2. eylem maddesinin izlenmesi ve madde turu
kosum                     olay  acilan  donem/md  kapanan  kapanma     gun  sistemsel  sis. pay
inceleme yok                48       0       0.0        0        -       -   0 (0.00)         -
kisi yazimi                 32      96       5.3       81      84%     6.9  15 (0.47)       16%
surec yazimi                25      75       4.2       52      69%    15.5  42 (1.68)       56%
surec + takip yok           38     114       6.3       38      33%    14.0  61 (1.61)       54%
surec + haftalik takip      23      69       3.8       60      87%    16.5  40 (1.74)       58%

3. kapanmayan madde ve yinelenen olay
kosum                      tekrar    oran  yinelenen    oran  yin. kesinti  kapanmayan sis.
inceleme yok                   43     90%          0      0%          0 dk              0/0
kisi yazimi                    27     84%          8     25%        335 dk             5/15
surec yazimi                   20     80%         14     56%        593 dk            16/42
surec + takip yok              33     87%         32     84%       1105 dk            46/61
surec + haftalik takip         18     78%          8     35%        433 dk             8/40

4. incelemenin bedeli ve yanitsiz sorunun karsiligi
kosum                     kisi-saat  saat/olay    kesinti     tekrar dk
inceleme yok                      0        0.0    1791 dk    1583 (88%)
kisi yazimi                     376       11.7    1173 dk     965 (82%)
surec yazimi                    480       19.2     966 dk     758 (78%)
surec + takip yok               404       10.6    1353 dk    1145 (85%)
surec + haftalik takip          556       24.2     878 dk     670 (76%)

bes kosum ve katman taramasi 2000 ms bandinda: evet
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır.

#### Sekiz Sorunun Yedisi

Birinci tablo kayıt katmanlarını soruya çevirir. Yalnız olay kaydıyla 6.000 baytta sekiz sorudan
biri yanıtlanır. İnceleme notu 51.000 bayta çıkarır ve yanıt yalnız ikiye gider — not bir alan değil
bir metindir, pahalıdır ve kendi başına sayılamaz. Yazım alanı 600 bayta üçüncü soruyu, madde
kütüğü 24.000 bayta üç soru birden açar; soru başına bayt 17.200'den 12.600'e iner. Son katman,
maddeyi neden sınıfına bağlayan 16 baytlık alandır: 1.200 bayta **kapanmayan madde hangi olayı
yeniden üretti** sorusunu açar. **En ucuz katman en geç eklenendir ve en pahalı soruyu yanıtlar.**

Sekizinci soru hiçbir katmanda yoktur: bu maddenin kapanması hangi kesintiyi önledi. Karşılığı
gözlenmemiş bir durumdur, kayıt genişletilerek yanıtlanamaz. Kütüğün verdiği en yakın şey
"kapanmayan madde şu kadar olay üretti"dir — önlenen değil, önlenmeyen sayılır.

#### Kapanma Oranı Neyi Ölçmez

İkinci tablo ilk bakışta kişi yazımını iyi gösterir: 96 madde açılır, 81'i kapanır (%84) ve kapanma
6,9 gün sürer — beş koşumun en hızlısı. Süreç yazımında 75 maddenin 52'si kapanır (%69), kapanma
15,5 gün sürer. Son iki sütun farkı söyler. Kişi yazımının 96 maddesinden yalnız **15'i** sistemsel düzeltmedir
(%16); geri kalanı hatırlatma ve belgedir. Süreç yazımının 75 maddesinin **42'si** sistemseldir
(%56); olay başına 0,47'ye karşı 1,68. Hatırlatma iki günde kapanır ve hiçbir olasılığı
değiştirmez; sistemsel düzeltme yirmi beş günde kapanır ve sınıfın olay olasılığını 0,70 ile çarpar.
**Kapanma oranı, kapanan şeyin ne olduğunu ölçmez.**

Sonucu üçüncü ve dördüncü tablo verir. Kişi yazımında 32 olay ve 1173 dakika kesinti ölçülür; tekrar
oranı %84'tür — incelemesiz koşumun %90'ından altı puan aşağıda. Süreç yazımında olay 25'e, kesinti
966 dakikaya, tekrar %80'e iner. Suçsuzluğun ölçülebilir karşılığı budur: kişi yazıldığında maddeler
açılır, hızla kapanır ve **sistem aynı kalır**.

#### Açılan Madde ile İzlenen Madde

Üçüncü koşum takibi bırakır: kök neden yine süreç yazılır, kapanma olasılığı yarıya iner. Açılan
madde düşmez, tersine 75'ten 114'e çıkar — daha çok olay olur, daha çok inceleme yapılır. Kapanan
38'de kalır (%33). Kritik sayı sistemsel maddelerdedir: 61 düzeltme açılır, **46'sı hiç kapanmaz**.
Yinelenen olay oranı %84'e, yineleme kesintisi 1105 dakikaya çıkar, toplam kesinti 966'dan 1353
dakikaya gider.

Haftalık takip tersini yapar: 69 maddenin 60'ı kapanır (%87), 40 sistemsel maddenin 32'si kapanır,
açıkta yalnız 8 kalır. Yinelenen olay 14'ten 8'e, toplam kesinti 878 dakikaya iner. Bedeli dördüncü
tablodadır: kişi-saat 480'den 556'ya, olay başına 24,2 kişi-saate çıkar — beş koşumun en pahalısı.
**Ödenen şey inceleme değil, incelemenin izlenmesidir.**

Aynı tabloda incelemesiz koşum bedava görünür: sıfır kişi-saat. Karşılığı 1791 dakikadır ve bunun
1583 dakikası (%88) tekrar eden olaylardandır.

#### Farkın Saklandığı Yer

Fark **açılan madde ile kapanan sistemsel madde arasında** saklıdır: takipsiz koşumda kütükte 114
satır görünür ve dönem başına 6,3 madde raporlanır — beş koşumun en yüksek üretimi. Aynı koşumda 61
sistemsel maddenin 46'sı hiç kapanmaz ve olayların %84'ü kapanmayan bir madde açıkta beklerken olur.
Bildirilmiş kısım açılan madde sayısı; bildirilmemiş kısım maddenin türü ve durumudur.

Kişi yazımında kapanmayan sistemsel madde yalnız 5'tir ve yinelenen olay oranı %25 ile düşük
görünür. Bu iyi bir haber değildir — açılmış sistemsel madde yalnız 15 olduğu için kapanmayan madde
yüzünden yineleyen olay da sayılamaz. **Hiç açılmamış madde, kapanmamış madde olarak da görünmez.**
Oradaki gerçek sayı tekrar oranıdır: %84.

#### Özet

- Sekiz sorudan yedisi beş kayıt katmanı ve 76.800 baytla yanıtlanır (soru başına 10.971 bayt);
  maddeyi neden sınıfına bağlayan 16 baytlık son alan, 1.200 bayta en pahalı soruyu açar.
- Yanıtsız kalan soru "bu maddenin kapanması hangi kesintiyi önledi"dir; karşı olgu hiçbir
  katmanda yoktur.
- Kök neden kişi yazıldığında 96 maddenin %84'ü ve en hızlısı (6,9 gün) kapanır, ama yalnız 15'i
  sistemsel düzeltmedir (olay başına 0,47) ve tekrar oranı %84'te kalır — incelemesiz koşumun
  %90'ına yakın. Süreç yazıldığında 75 maddenin 42'si sistemseldir (1,68) ve olay 25'e iner.
- Takip bırakıldığında 114 madde açılır ama yalnız 38'i kapanır; 61 sistemsel maddenin 46'sı hiç
  kapanmaz, yinelenen olay oranı %84'e ve yineleme kesintisi 1105 dakikaya çıkar.
- Haftalık takip 556 kişi-saat karşılığında kesintiyi 878 dakikaya indirir; incelemesiz koşumun
  bedeli sıfır kişi-saat ve 1791 dakikadır.

#### Sonraki Adım

Madde kapanınca olay olasılığı düştü, ama hepsi olay olduktan sonra çalıştı: sistemsel düzeltme
yirmi beş günde kapanırken aynı sınıf yeniden olay üretmeye devam etti. Değişimin hızını **olaydan
önce** düzenleyen bir kural hiç konmadı. Sonraki ders hata bütçesini böyle bir kurala çevirir: bütçe
tükendiğinde yeni dağıtım durur — dağıtım sıklığı ne olur, kuyrukta ne birikir, bütçe ne kadar
sürede geri kazanılır ve tek bir büyük olay hattı aylarca durdurduğunda kural nasıl gevşetilir.

### Hata Bütçesi Yönetimi

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/hata-butcesi-yonetimi

Hata bütçesinin değişim hızını düzenleyen bir kurala çevrilmesi: 360 günde 90 günlük kayan pencerede 129,6 dakikalık bütçenin tek bir ağır olayla (150 dakika, bütçenin %116'sı) bitmesi ve dört durma epizodunun dördünün de tek olayla tetiklenmesi, tam durdurmanın dağıtım sıklığını 5,9'dan 1,8'e indirirken 154'lük kuyruğu 40'lık partiler hâlinde boşaltarak kesintiyi 402'den 901 dakikaya çıkarması, kısmi durdurmanın 437 dakikada ve 3,9 kuyrukta kalması, yalnız riskli değişikliğin durdurulmasının 480 dakika vermesi ve kademeli açılışın aynı kuralı koruyup kesintiyi 437 dakikaya indirmesi.

Önceki ders eylem maddelerini saydı ve kapanmayan maddenin aynı olayı yeniden ürettiğini gösterdi.
Düzeltmelerin hepsi olay olduktan sonra çalıştı; değişimin hızını olaydan önce düzenleyen bir kural
hiç konmadı.

Hata bütçesinin kendisi M22/K01'de ölçüldü: hedeften türetilir, tek bir ağır olayın onu ne kadar
götürdüğü sayılır. Burada bütçe bir **kurala** çevrilir — tükendiğinde yeni dağıtım durur — ve
kuralın kendisi ölçülür. Ölçülen dört şey vardır: dağıtım sıklığı, kuyrukta **biriken iş**,
bütçenin **geri kazanılma süresi** ve kuralın **tek bir olayla tetiklenmesi**. Sonra kural gevşetilir
ve her gevşetmenin dağıtım sıklığı ile olay sayısına etkisi sayılır.

#### Kuralın Kurulması

Örnek yine kurgu **bölgesel ölçüm ağı**dır; dağıtım hattı da olay dizisi de kurgudur.

**OY25:** 360 gün koşulur ve bütçe **kayan pencere** üzerinde işler: her gün son 90 günün kesintisi
bütçeden düşülür. Pencere bütçesi 129,6 dakikadır; türetimi M22/K01'de ölçüldü, burada girdidir.
**OY26:** her gün akışa bir değişiklik girer; parti tabanı beş, hazırlık bir gün, parti tavanı
kırktır. **OY27:** değişikliklerin dörtte biri riskli etiketlidir; kusur olasılığı riskli için 0,09,
öteki için 0,014'tür. **OY28:** kusurlu değişiklik yayına çıkarsa aynı gün olay olur; sınıflar hafif
8 dakika (pay 0,58), orta 35 dakika (0,30), ağır 150 dakika (0,12). **OY29:** parti tabanının
üstündeki her değişiklik kusur olasılığını 0,04 katsayısıyla büyütür. **OY30:** kural devredeyken
*tam durdurma* hiçbir partiyi çıkarmaz, *kısmi durdurma* hazırlığı on güne çıkarır, *yalnız riskli*
biçimi riskli etiketlileri kuyrukta bırakır, *kademeli açılış* parti tavanını ona indirir. Tohum
20260819'dur ve bütün koşumlar aynı değişiklik dizisini paylaşır.

Günler, değişiklikler ve olaylar süreç içi bir **modeldir**; gerçek bir dağıtım hattı yoktur.

```js
// butce/kural.mjs — hata butcesi kurali modeli: gercek bir dagitim hatti yok; gunler,
// degisiklikler ve olaylar veri yapisidir. Uretec kendi yazilir, tohum gorunur.

export const GUN = 360, PENCERE = 90, GUN_DK = 1440, HEDEF = 0.999, TOHUM = 20260819;
export const BUTCE = PENCERE * GUN_DK * (1 - HEDEF);   // M22/K01'de turetildi, burada girdi
export const PARTI = 5, PARTI_TAVAN = 40, HAZIRLIK = 1, KISMI_HAZIRLIK = 10;
export const BAGLASIM = 0.04;   // partideki her ek degisiklik kusur olasiligini bu kadar buyutur
export const RISK_PAY = 0.25, KUSUR_RISKLI = 0.09, KUSUR_DUZ = 0.014;
export const SINIF = [["hafif", 8, 0.58], ["orta", 35, 0.30], ["agir", 150, 0.12]];

export function uretec(tohum) {                    // dogrusal eslesmeli uretec
  let x = tohum >>> 0;
  return () => ((x = (x * 1664525 + 1013904223) >>> 0) / 2 ** 32);
}
// zarlar bastan atilir: butun kosumlar ayni degisiklik dizisini paylasir
const Z = (() => { const z = uretec(TOHUM);
  return Array.from({ length: GUN }, () => ({ risk: z(), kusur: z(), sinif: z() })); })();

export function kos({ kural = "yok", tavan = PARTI_TAVAN } = {}) {
  const D = Z.map((z, i) => {                      // her gun akisa bir degisiklik girer
    const riskli = z.risk < RISK_PAY;
    let e = 0, dk = 0;
    for (const [, sure, pay] of SINIF) { e += pay; if (dk === 0 && z.sinif < e) dk = sure; }
    return { i, riskli, zar: z.kusur, taban: riskli ? KUSUR_RISKLI : KUSUR_DUZ,
      kesinti: dk, durum: "kuyrukta", yayinGun: null };
  });
  const olaylar = [], epizotlar = [];
  const S = { yayin: 0, durgunGun: 0, kuyrukToplam: 0, enBuyukKuyruk: 0,
    partiToplam: 0, enBuyukParti: 0 };
  let aktif = null, bas = null, tek = false;

  for (let t = 0; t < GUN; t++) {
    if (aktif && aktif.bitis === t) {               // parti uretime cikar
      S.yayin++; S.partiToplam += aktif.grup.length;
      S.enBuyukParti = Math.max(S.enBuyukParti, aktif.grup.length);
      // parti buyudukce kusur olasiligi baglasim katsayisiyla buyur
      const carpan = 1 + BAGLASIM * (aktif.grup.length - PARTI);
      for (const x of aktif.grup) {
        x.durum = "bitti"; x.yayinGun = t;
        if (x.zar < x.taban * carpan) olaylar.push({ gun: t, kesinti: x.kesinti });
      }
      aktif = null;
    }
    // kayan pencere: son PENCERE gunun kesintisi butceden dusulur
    const pen = olaylar.filter((o) => o.gun > t - PENCERE);
    const kalan = BUTCE - pen.reduce((s, o) => s + o.kesinti, 0);
    const devrede = kural !== "yok" && kalan < 0;   // butce tukendi mi
    if (devrede) {
      if (bas === null) { bas = t; tek = pen.some((o) => o.kesinti >= BUTCE); }
      S.durgunGun++;
    } else if (bas !== null) { epizotlar.push({ uzunluk: t - bas, tek }); bas = null; }

    const kuyruk = D.filter((x) => x.durum === "kuyrukta" && x.i <= t);
    S.kuyrukToplam += kuyruk.length;
    S.enBuyukKuyruk = Math.max(S.enBuyukKuyruk, kuyruk.length);
    if (aktif) continue;
    let parti = PARTI, hazirlik = HAZIRLIK, aday = kuyruk;
    if (devrede) {                                  // kuralin gevsetilme bicimleri
      if (kural === "tam") aday = [];
      else if (kural === "kismi") hazirlik = KISMI_HAZIRLIK;
      else if (kural === "riskli") aday = kuyruk.filter((x) => !x.riskli);
    }
    if (aday.length < parti) continue;
    const grup = aday.slice(0, Math.min(aday.length, tavan));
    for (const x of grup) x.durum = "yayinda";
    aktif = { grup, bitis: t + hazirlik };
  }
  if (bas !== null) epizotlar.push({ uzunluk: GUN - bas, tek });
  return { D, olaylar, epizotlar, S };
}

const ort = (a) => (a.length ? (a.reduce((s, v) => s + v, 0) / a.length).toFixed(1) : "-");

export function olc(ayar) {
  const { D, olaylar, epizotlar, S } = kos(ayar);
  const U = epizotlar.map((e) => e.uzunluk);
  return { yayin: S.yayin, dagitim: (S.yayin / (GUN / 30)).toFixed(1),
    olay: olaylar.length, kesinti: olaylar.reduce((s, o) => s + o.kesinti, 0),
    agir: olaylar.filter((o) => o.kesinti === SINIF[2][1]).length,
    epizot: epizotlar.length, durgunGun: S.durgunGun,
    enUzun: U.length ? Math.max(...U) : 0, geriKazanma: ort(U),
    tekOlay: epizotlar.filter((e) => e.tek).length,
    ortKuyruk: (S.kuyrukToplam / GUN).toFixed(1), enBuyukKuyruk: S.enBuyukKuyruk,
    ortParti: (S.partiToplam / S.yayin).toFixed(1), enBuyukParti: S.enBuyukParti,
    cikmayan: D.filter((x) => x.yayinGun === null).length };
}
```

Ölçüm dosyası önce altı soruluk bir küme kurar — kural devredeyken işletimde gerçekten sorulan
sorular — ve her sorunun hangi kayıtla yanıtlandığını yazar.

```js
// butce/olc.mjs — butce bir kurala cevrilir ve bir donem kosturulur: dagitim sikligi,
// biriken is, butcenin geri kazanilma suresi ve kuralin erken tetiklenmesi sayilir.
import { GUN, PENCERE, BUTCE, HEDEF, SINIF, TOHUM, BAGLASIM, PARTI, olc } from "./kural.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const t0 = process.hrtime.bigint();

const K = { "kural yok": { kural: "yok" }, "tam durdurma": { kural: "tam" },
  "kismi durdurma": { kural: "kismi" }, "yalniz riskli durur": { kural: "riskli" },
  "tam + kademeli acilis": { kural: "tam", tavan: 10 } };
const R = Object.fromEntries(Object.entries(K).map(([a, y]) => [a, olc(y)]));
const T = R["tam durdurma"];

// soru kumesi: her sorunun yanitlanmasi icin gereken kayit, birim bayti ve birim sayisi
const SORU = [
  ["butceden su an ne kadar kaldi", "gunluk kesinti kaydi", 48, GUN],
  ["hat neden durdu", "durdurma gunlugu", 96, T.epizot],
  ["hat ne zaman yeniden acilacak", "pencere dusme takvimi", 32, T.olay],
  ["durus kac degisiklik biriktirdi", "kuyruk kaydi", 24, GUN],
  ["hangi degisiklik riskli sayildi", "risk etiketi", 8, GUN],
  ["durdurma hangi olayi onledi", "karsi olgu", 0, 0],
];

console.log(`${GUN} gun, kayan pencere ${PENCERE} gun, hedef ${(100 * HEDEF).toFixed(1)}%, ` +
  `pencere butcesi ${BUTCE.toFixed(1)} dk; tohum ${TOHUM}`);
console.log("olay siniflari: " + SINIF.map(([a, d, p]) => `${a} ${d} dk (pay ${p})`).join(", "));
console.log(`agir olay / butce = %${(100 * SINIF[2][1] / BUTCE).toFixed(0)} (tek olay butceyi ` +
  `bitirir); parti tabani ${PARTI}, baglasim katsayisi ${BAGLASIM}`);

console.log("\n1. hangi soru hangi kayitla yanitlaniyor (tam durdurma kosumu)");
const A = [-33, -23, 10, 8];
yaz(A, "soru", "gereken kayit", "bayt", "yanit");
let bayt = 0, yanit = 0;
for (const [s, k, b, n] of SORU) {
  const var_ = b > 0;
  if (var_) { bayt += b * n; yanit++; }
  yaz(A, s, k, var_ ? b * n : "-", var_ ? "evet" : "hayir");
}
console.log(`  toplam ${bayt} bayt, ${yanit}/6 soru, soru basina ` +
  `${Math.round(bayt / yanit)} bayt`);

console.log("\n2. kural degisim hizini nasil duzenliyor");
const B = [-21, 8, 12, 7, 7, 11];
yaz(B, "kosum", "yayin", "dagitim/30g", "olay", "agir", "kesinti");
for (const [ad, r] of Object.entries(R))
  yaz(B, ad, r.yayin, r.dagitim, r.olay, r.agir, r.kesinti + " dk");

console.log("\n3. durus ve butcenin geri kazanilmasi");
const C = [-21, 9, 12, 11, 15, 15];
yaz(C, "kosum", "epizot", "durgun gun", "en uzun", "geri kazanma", "tek olayla");
for (const [ad, r] of Object.entries(R))
  yaz(C, ad, r.epizot, r.durgunGun, r.enUzun + " g", r.geriKazanma + " g",
    `${r.tekOlay}/${r.epizot}`);

console.log("\n4. biriken is");
const D = [-21, 13, 15, 12, 16, 11];
yaz(D, "kosum", "ort. kuyruk", "en buyuk kuy.", "ort. parti", "en buyuk parti", "cikmayan");
for (const [ad, r] of Object.entries(R))
  yaz(D, ad, r.ortKuyruk, r.enBuyukKuyruk, r.ortParti, r.enBuyukParti, r.cikmayan);

const ms = Number(process.hrtime.bigint() - t0) / 1e6;   // ham olcum basilmaz, bant denetlenir
console.log(`\nbes kosum ve soru taramasi 2000 ms bandinda: ${ms < 2000 ? "evet" : "hayir"}`);
```

```
360 gun, kayan pencere 90 gun, hedef 99.9%, pencere butcesi 129.6 dk; tohum 20260819
olay siniflari: hafif 8 dk (pay 0.58), orta 35 dk (pay 0.3), agir 150 dk (pay 0.12)
agir olay / butce = %116 (tek olay butceyi bitirir); parti tabani 5, baglasim katsayisi 0.04

1. hangi soru hangi kayitla yanitlaniyor (tam durdurma kosumu)
soru                             gereken kayit                bayt   yanit
butceden su an ne kadar kaldi    gunluk kesinti kaydi        17280    evet
hat neden durdu                  durdurma gunlugu              384    evet
hat ne zaman yeniden acilacak    pencere dusme takvimi         576    evet
durus kac degisiklik biriktirdi  kuyruk kaydi                 8640    evet
hangi degisiklik riskli sayildi  risk etiketi                 2880    evet
durdurma hangi olayi onledi      karsi olgu                      -   hayir
  toplam 29760 bayt, 5/6 soru, soru basina 5952 bayt

2. kural degisim hizini nasil duzenliyor
kosum                   yayin dagitim/30g   olay   agir    kesinti
kural yok                  71         5.9      8      2     402 dk
tam durdurma               22         1.8     18      4     901 dk
kismi durdurma             58         4.8      9      2     437 dk
yalniz riskli durur        62         5.2     11      2     480 dk
tam + kademeli acilis      51         4.3      9      2     437 dk

3. durus ve butcenin geri kazanilmasi
kosum                   epizot  durgun gun    en uzun   geri kazanma     tek olayla
kural yok                    0           0        0 g            - g            0/0
tam durdurma                 4         274       90 g         68.5 g            4/4
kismi durdurma               1         134      134 g        134.0 g            1/1
yalniz riskli durur          2         180       90 g         90.0 g            2/2
tam + kademeli acilis        2         180       90 g         90.0 g            2/2

4. biriken is
kosum                  ort. kuyruk  en buyuk kuy.  ort. parti  en buyuk parti   cikmayan
kural yok                      3.0              5         5.0               5          5
tam durdurma                  65.6            154        14.5              40         40
kismi durdurma                 3.9             10         6.1              10          5
yalniz riskli durur            9.6             31         5.8              31          3
tam + kademeli acilis         44.4            154         7.0              10          5

bes kosum ve soru taramasi 2000 ms bandinda: evet
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır.

#### Kuralın Sorduğu Sorular

Birinci tablo kural devredeyken sorulan altı soruyu kayda bağlar. Beşi yanıtlanır, toplam 29.760
bayt tutar; soru başına 5.952 bayt. Pahalı olan ikisi gün başına tutulur: günlük kesinti kaydı
(17.280 bayt) ve kuyruk kaydı (8.640 bayt). Ucuz olan **hat ne zaman yeniden açılacak** sorusudur:
576 bayt. Kayan pencere bu soruyu kesin bir tarihe çevirir, çünkü her olayın pencereden düşeceği gün
bellidir. Takvim yoksa soru "bilmiyoruz"la yanıtlanır ve kuyruktaki her değişiklik için yeniden
sorulur.

Yanıtsız kalan altıncısıdır: durdurma hangi olayı önledi. Burada da hiçbir kayıtla yanıtlanmaz.
Kural devredeyken **kesinti ölçülür, önlenen kesinti ölçülmez**.

#### Bütçe Bir Olayda Bitiyor

Üçüncü tablo kuralın nasıl tetiklendiğini söyler. Ağır olay 150 dakika, pencere bütçesi 129,6
dakikadır: **tek bir ağır olay bütçenin %116'sını götürür**. Son sütun sonucu verir — tam durdurmada
dört duruş epizodunun **dördü de** tek olayla tetiklenmiştir; kural kesinti birikimine değil, tek
olaya tepki verir.

Geri kazanılma süresi buradan çıkar. Kayan pencerede bütçe ancak olay pencereden düştüğünde geri
gelir; ağır bir olay tek başına bütçeyi bitirdiği için hat **doksan gün** kapalı kalır — en uzun
duruş tam olarak pencere uzunluğudur. Tam durdurmada ortalama epizot 68,5 gün, durgun gün 274'tür:
360 günün dörtte üçü. Kısmi durdurmada tek epizot 134 gün sürer, çünkü yavaşlayan hat pencereye yeni
olay eklemeye devam eder.

#### Kural Kesintiyi Artırıyor

İkinci tablonun okunması gereken satırı tam durdurmadır. Dağıtım sıklığı 30 günde 5,9'dan 1,8'e
iner — kuralın amaçladığı budur. Ama olay 8'den **18'e**, kesinti 402'den **901 dakikaya**, ağır olay
2'den 4'e çıkar.

Nedeni dördüncü tablodadır. Kural yokken ortalama kuyruk 3,0, ortalama parti 5,0'dır. Tam durdurmada
kuyruk ortalama 65,6'ya, en büyük 154'e çıkar ve hat açıldığında **40'lık partiler** hâlinde boşalır
— ortalama parti 14,5. Bağlaşım katsayısı 0,04 olduğu için 40'lık partide kusur olasılığı tabanın
2,4 katıdır. **Durdurma değişikliği yok etmez, biriktirir; biriken iş büyük parti olarak çıkar ve
büyük parti daha çok olay üretir.** Yeni olaylar yeni duruş tetikler: epizot 4'e çıkar ve kırk
değişiklik hiç çıkamaz.

#### Gevşetmenin Üç Biçimi

Kısmi durdurma hattı durdurmaz, yavaşlatır: hazırlık on güne çıkar. Dağıtım sıklığı 4,8'de kalır,
ortalama kuyruk 3,9'dur ve kesinti 437 dakikada durur — kuralsız koşumun 402 dakikasına yakın. Bedeli
134 günlük tek bir yavaşlama epizodudur.

Yalnız riskli değişikliğin durdurulması ortada durur: dağıtım sıklığı 5,2, kuyruk 9,6, kesinti 480
dakika. Kısmi durdurmadan kötüdür, çünkü bekleyen riskliler sonunda 31'lik bir partide birlikte
çıkar. Etiketin kendisi 2.880 bayttır; karşılığı kuyruğun 154 yerine 31'de kalmasıdır.

Üçüncü gevşetme kuralın kendisine değil, **açılışına** dokunur: tam durdurma korunur ama hat
açılırken parti tavanı 40'tan 10'a çekilir. Aynı kural, aynı eşik, iki koşumda da 90 günlük en
uzun duruş — ama durgun gün 274'ten 180'e, epizot 4'ten 2'ye, ortalama parti 14,5'ten 7,0'a, olay
18'den 9'a ve kesinti 901'den **437 dakikaya** iner. Dağıtım sıklığı 1,8'den 4,3'e çıkar ve
çıkmayan değişiklik 40'tan 5'e düşer. **Kuralın bedelini duruşun uzunluğu değil, duruştan çıkışın
biçimi belirler.**

#### Farkın Saklandığı Yer

Fark **duruşun süresi ile duruş sonrası partinin boyu arasında** saklıdır: tam durdurma ile
kademeli açılış aynı kuralı, aynı eşiği ve aynı 90 günlük en uzun duruşu paylaşır, ikisinde de en
büyük kuyruk 154'tür. Bildirilen ölçüt en uzun duruştur ve o ikisinde aynıdır. Bildirilmeyen kısım
parti tavanıdır; kesintiyi 901 ile 437 dakika arasında ayıran tek şey odur.

Ağır olayın payı yalnız 0,12'dir ama bütçenin %116'sını tek başına götürür; kuralın devreye girip
girmemesi neredeyse tamamen o tek sınıfa bağlıdır. Kural, kesinti birikimini değil, **bir olayın
büyüklüğünü** okur.

#### Özet

- Kayan pencerede bütçe 129,6, ağır olay 150 dakikadır: tek olay bütçenin %116'sını götürür; tam
  durdurmada dört epizodun dördü de tek olayla tetiklenir ve en uzun duruş 90 gündür — tam pencere
  uzunluğu.
- Tam durdurma dağıtım sıklığını 5,9'dan 1,8'e indirir, ama kuyruk 154'e çıkıp 40'lık partiler
  hâlinde boşaldığı için olay 8'den 18'e, kesinti 402'den 901 dakikaya çıkar ve 40 değişiklik hiç
  çıkamaz.
- Kısmi durdurma (hazırlık 1 → 10 gün) dağıtım sıklığını 4,8'de, kuyruğu 3,9'da ve kesintiyi 437
  dakikada tutar; bedeli 134 günlük tek bir yavaşlama epizodudur.
- Yalnız riskli değişikliğin durdurulması dağıtım sıklığını 5,2'de tutar ama kesinti 480 dakikadır,
  çünkü bekleyen riskliler 31'lik tek bir partide birlikte çıkar.
- Kural korunup açılışta parti tavanı 40'tan 10'a çekilince durgun gün 274'ten 180'e, kesinti
  901'den 437 dakikaya ve olay 18'den 9'a iner; dağıtım sıklığı 4,3'e çıkar.
- Altı sorudan beşi 29.760 baytla yanıtlanır (soru başına 5.952 bayt); "durdurma hangi olayı önledi"
  hiçbir kayıtla yanıtlanmaz.

#### Sonraki Adım

Kural kondu, hat durdu, kuyruk birikti ve çıkışın biçimi kesintiyi ikiye katladı ya da yarıya
indirdi. Bu sayıların hepsi dakika ve değişiklik cinsindendir. Duran hattın, biriken kuyruğun ve
gece boyunca koşan toplu işin bir de kaynak karşılığı vardır. Sonraki ders kapasiteyi işletim
maliyeti olarak ele alır — kaynak kullanımı nasıl bir fiyata dönüşür, hangi soru bu fiyatla
yanıtlanır ve toplanan izleme verisinin kendi maliyeti ne kadardır.

### Kapasite ve Maliyet İzleme

Source: https://academia.sh/tr/kurslar/devops-gozlemlenebilirlik/kapasite-ve-maliyet-izleme

İşletim maliyetinin soru kümesine bağlanması: günlük 753 kurgu biriminin %30'unun sahipsiz kalması yüzünden sekiz maliyet sorusundan yalnız dördünün tam yanıtlanması, izleme verisinin kendi payının %16 olması, %90 hedef kullanımın 30 günün sekizinde doyup 360 dakika kesinti üretmesine karşılık %75'te doyumun sıfırlanıp kaçınılan dakikanın 5,1 birime mal olması, ölçek sekiz katına çıkarken altyapının milyon istek başına 507'den 344 birime inmesi ama izlemenin 100'den 244'e çıkıp payını %41'e taşıması.

Önceki ders hata bütçesini bir kurala çevirdi: hat durdu, kuyruk birikti ve duruştan çıkışın
biçimi kesintiyi ikiye katladı ya da yarıya indirdi. O sayıların hepsi dakika ve değişiklik
cinsindendi. Hiç sorulmayan soru şuydu: bunların hepsi **ne kadara** koşuyor.

Kapasite kararının kendisi M19/K06'da ölçüldü. Burada kapasite bir **işletim maliyeti** olarak ele
alınır: kaynak kullanımı bir fiyata dönüşür, o fiyat bir soru kümesine uygulanır ve toplanan izleme
verisinin kendi maliyeti ayrı bir kalem olarak sayılır. Gözlemlenebilirlik bu tabloda hem ölçen
taraftır hem ölçülen.

#### Maliyet Soru Kümesi

Örnek yine kurgu **bölgesel ölçüm ağı**dır. Kalemler, fiyatlar ve talep kurgudur; **para birimi de
kurgudur** ve `br` diye anılır, gerçek bir fiyat listesine karşılık gelmez.

**OY31:** dokuz maliyet kalemi vardır; her kalemin bir sabit ve bir değişken günlük bedeli, bir de
ölçek üssü yazılıdır. Dönem 30 gündür. **OY32:** kalemlerin bir bölümü **sahip etiketi** taşır;
paylaşılan veri deposu ile bölgeler arası aktarım etiketsizdir ve servislere bölüştürülemez.
**OY33:** fatura verisi üç gün gecikmelidir; son üç günün ayrıntısı hiç yoktur. **OY34:** günlük
talep ortalaması 1,0 olan bir dizidir (üreteç kendi yazılır, tohum 20260826); kapasite hedef
kullanım oranından türetilir — kapasite hesabının kendisi M19/K06'da ölçüldü, burada girdidir.
**OY35:** talebin kapasiteyi aştığı her gün **doyum** sayılır ve 45 dakika kesinti üretir.
**OY36:** ölçek `k` katına çıktığında örnek sayısı `k`, etiket kardinalite çarpanı `√k` katına
çıkar; izleme serisi ikisinin çarpımıdır, yani ölçek üssü 1,5'tir.

Kalemler, talep ve fatura süreç içi bir **modeldir**; gerçek bir fatura yoktur.

```js
// maliyet/kalem.mjs — isletim maliyeti modeli: gercek bir fatura yok; kalemler, fiyatlar ve
// talep bir veri yapisidir. Para birimi kurgudur ve `br` diye anilir. Tohum gorunur.

export const DONEM = 30, TOHUM = 20260826, GECIKME = 3, DOYUM_DK = 45;
// kalem: ad, sabit br/gun, degisken br/gun, olcek ussu, sahip etiketi var mi, izleme kalemi mi
export const KALEM = [
  ["servis ornekleri", 40, 134, 1.00, true, false],
  ["bellek ve yerel disk", 0, 86, 1.00, true, false],
  ["blok depolama", 12, 58, 1.00, true, false],
  ["gecelik toplu is kumesi", 55, 20, 0.70, true, false],
  ["paylasilan veri deposu", 90, 60, 0.80, false, false],
  ["bolgeler arasi aktarim", 0, 74, 1.00, false, false],
  ["zaman serisi deposu", 8, 46, 1.50, true, true],
  ["gunluk deposu", 6, 38, 1.50, true, true],
  ["iz deposu", 4, 22, 1.50, true, true],
];
export const ISTEK = 1240000;                      // olcek 1'de gunluk istek sayisi
export const KAPASITE_BR = 278;                    // kapasiteye bagli kalemlerin gunluk br'si

export const br = (k, x) => x[1] + x[2] * Math.pow(k, x[3]);
export const gunluk = (k, f = () => true) => KALEM.filter(f).reduce((t, x) => t + br(k, x), 0);

export function uretec(tohum) {                    // dogrusal eslesmeli uretec
  let x = tohum >>> 0;
  return () => ((x = (x * 1664525 + 1013904223) >>> 0) / 2 ** 32);
}
// gunluk talep: ortalamasi 1,0 olan bir dizi; tepe taban orani varsayimdan gelir
export const talep = (() => { const z = uretec(TOHUM);
  return Array.from({ length: DONEM }, () => 0.78 + 0.44 * z()); })();

// hedef kullanim oraninin bedeli: bosta duran kapasite ile doyum gunu birlikte
export function kullanim(hedef) {
  const ort = talep.reduce((a, b) => a + b, 0) / DONEM;
  const kapasite = ort / hedef;
  const doyum = talep.filter((t) => t > kapasite).length;
  const maliyet = KAPASITE_BR * kapasite * DONEM;
  return { hedef, kapasite, maliyet, bosta: maliyet * (1 - hedef), doyum,
    kesinti: doyum * DOYUM_DK, tepe: Math.max(...talep) };
}
```

```js
// maliyet/olc.mjs — maliyet soru kumesi, izleme verisinin kendi payi, bosta kaynak ile doyum,
// ve olcek buyudukce birim maliyetin hangi kalemde dusmedigi.
import { KALEM, DONEM, GECIKME, DOYUM_DK, ISTEK, br, gunluk, kullanim } from "./kalem.mjs";

const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const t0 = process.hrtime.bigint();
const G1 = gunluk(1), etiketli = gunluk(1, (x) => x[4]), izleme = gunluk(1, (x) => x[5]);
const pay = (a) => `%${(100 * a / G1).toFixed(0)}`;

console.log(`${DONEM} gun, ${KALEM.length} maliyet kalemi, gunluk ${G1.toFixed(0)} br ` +
  `(kurgu para birimi); fatura ${GECIKME} gun gecikmeli`);

// soru kumesi: [soru, yanit, kapsanan maliyet payi, yanitlanamamanin nedeni]
const SORU = [
  ["toplam ne kadar tutuyor", "evet", 1, "-"],
  ["hangi servis ne kadar tutuyor", "kismi", etiketli / G1, "etiketsiz kaynak"],
  ["dunku artis nereden geldi", "hayir", 0, "gecikmeli fatura verisi"],
  ["hangi kaynak bosta duruyor", "evet", 1, "-"],
  ["bir istek kaca mal oluyor", "evet", 1, "-"],
  ["bir servisin istegi kaca mal oluyor", "hayir", etiketli / G1,
    "paylasilan kalem bolusturulemez"],
  ["izleme verisi ne kadar tutuyor", "evet", 1, "-"],
  ["olcek iki katina ciksa fiyat ne olur", "kismi", 1, "faturadan okunmaz"],
];
console.log("\n1. maliyet soru kumesi");
const A = [-37, 8, 11, 32];
yaz(A, "soru", "yanit", "kapsanan", "yanitlanamamanin nedeni");
for (const [s, y, p, n] of SORU) yaz(A, s, y, `%${(100 * p).toFixed(0)}`, n);
const tam = SORU.filter((s) => s[1] === "evet").length;
console.log(`  ${tam}/${SORU.length} soru tam yanitlanir; ` +
  `${SORU.filter((s) => s[1] === "kismi").length} kismi, ` +
  `${SORU.filter((s) => s[1] === "hayir").length} yanitsiz`);

console.log("\n2. kalem dokumu ve izlemenin kendi payi");
const B = [-26, 11, 8, 10, 12];
yaz(B, "kalem", "gunluk br", "pay", "sahip", "tur");
for (const x of KALEM)
  yaz(B, x[0], br(1, x).toFixed(0), pay(br(1, x)), x[4] ? "etiketli" : "yok",
    x[5] ? "izleme" : "altyapi");
yaz(B, "toplam", G1.toFixed(0), "%100", pay(etiketli), pay(izleme));
console.log(`  (son satir: etiketli pay, izleme payi) izleme ${izleme.toFixed(0)} br/gun`);

console.log("\n3. hedef kullanim orani: bosta kaynak ile doyum yan yana");
const C = [-9, 11, 12, 11, 9, 11, 14];
yaz(C, "hedef", "kapasite", "donem br", "bosta br", "doyum", "kesinti", "bosta br/dk");
const K = [0.30, 0.45, 0.60, 0.75, 0.90].map(kullanim);
const taban = K[K.length - 1];
for (const r of K) {
  const kacinilan = taban.kesinti - r.kesinti, fark = r.bosta - taban.bosta;
  yaz(C, `%${(100 * r.hedef).toFixed(0)}`, r.kapasite.toFixed(2), r.maliyet.toFixed(0),
    r.bosta.toFixed(0), `${r.doyum}/${DONEM}`, `${r.kesinti} dk`,
    kacinilan > 0 ? (fark / kacinilan).toFixed(1) : "-");
}
console.log(`  talep tepesi ${taban.tepe.toFixed(2)}; doyan gun ${DOYUM_DK} dk kesinti uretir`);

console.log("\n4. olcek buyurken birim maliyet");
const D = [-7, 12, 13, 13, 12, 12];
yaz(D, "olcek", "gunluk br", "br/M istek", "altyapi/M", "izleme/M", "izleme pay");
for (const k of [1, 2, 4, 8]) {
  const t = gunluk(k), iz = gunluk(k, (x) => x[5]), M = (ISTEK * k) / 1e6;
  yaz(D, `${k}x`, t.toFixed(0), (t / M).toFixed(1), ((t - iz) / M).toFixed(1),
    (iz / M).toFixed(1), `%${(100 * iz / t).toFixed(0)}`);
}

const ms = Number(process.hrtime.bigint() - t0) / 1e6;   // ham olcum basilmaz, bant denetlenir
console.log(`\ndort tablo ve olcek taramasi 2000 ms bandinda: ${ms < 2000 ? "evet" : "hayir"}`);
```

```
30 gun, 9 maliyet kalemi, gunluk 753 br (kurgu para birimi); fatura 3 gun gecikmeli

1. maliyet soru kumesi
soru                                    yanit   kapsanan         yanitlanamamanin nedeni
toplam ne kadar tutuyor                  evet       %100                               -
hangi servis ne kadar tutuyor           kismi        %70                etiketsiz kaynak
dunku artis nereden geldi               hayir         %0         gecikmeli fatura verisi
hangi kaynak bosta duruyor               evet       %100                               -
bir istek kaca mal oluyor                evet       %100                               -
bir servisin istegi kaca mal oluyor     hayir        %70 paylasilan kalem bolusturulemez
izleme verisi ne kadar tutuyor           evet       %100                               -
olcek iki katina ciksa fiyat ne olur    kismi       %100               faturadan okunmaz
  4/8 soru tam yanitlanir; 2 kismi, 2 yanitsiz

2. kalem dokumu ve izlemenin kendi payi
kalem                       gunluk br     pay     sahip         tur
servis ornekleri                  174     %23  etiketli     altyapi
bellek ve yerel disk               86     %11  etiketli     altyapi
blok depolama                      70      %9  etiketli     altyapi
gecelik toplu is kumesi            75     %10  etiketli     altyapi
paylasilan veri deposu            150     %20       yok     altyapi
bolgeler arasi aktarim             74     %10       yok     altyapi
zaman serisi deposu                54      %7  etiketli      izleme
gunluk deposu                      44      %6  etiketli      izleme
iz deposu                          26      %3  etiketli      izleme
toplam                            753    %100       %70         %16
  (son satir: etiketli pay, izleme payi) izleme 124 br/gun

3. hedef kullanim orani: bosta kaynak ile doyum yan yana
hedef       kapasite    donem br   bosta br    doyum    kesinti   bosta br/dk
%30             3.33       27785      19449     0/30       0 dk          51.5
%45             2.22       18523      10188     0/30       0 dk          25.7
%60             1.67       13892       5557     0/30       0 dk          12.9
%75             1.33       11114       2778     0/30       0 dk           5.1
%90             1.11        9262        926     8/30     360 dk             -
  talep tepesi 1.21; doyan gun 45 dk kesinti uretir

4. olcek buyurken birim maliyet
olcek     gunluk br   br/M istek    altyapi/M    izleme/M  izleme pay
1x              753        607.3        507.3       100.0         %16
2x             1356        546.7        418.5       128.2         %23
4x             2706        545.5        370.9       174.6         %32
8x             5832        587.9        344.3       243.6         %41

dort tablo ve olcek taramasi 2000 ms bandinda: evet
```

Sayılar **ölçüm** sınıfındadır; girdileri yukarıdaki varsayımlardır.

#### Faturanın Yüzde Otuzu Sahipsiz

Birinci tablo sekiz maliyet sorusunu kayda bağlar ve her sorunun faturanın hangi payı için
yanıtlandığını yazar: dördü tam, ikisi kısmi, ikisi yanıtsız.

Nedenler ayrı ayrı adlandırılır. **Etiketsiz kaynak:** paylaşılan veri deposu (%20) ile bölgeler
arası aktarım (%10) sahip etiketi taşımaz; "hangi servis ne kadar tutuyor" sorusu faturanın yalnız
**%70'i** için yanıtlanır. **Paylaşılan kalemin bölüştürülememesi:** aynı %30, "bir servisin isteği
kaça mal oluyor" sorusunu tümüyle kapatır — toplam birim maliyet hesaplanabilir, servis başına olan
hesaplanamaz. **Gecikmeli fatura verisi:** ayrıntı üç gün geriden geldiği için "dünkü artış nereden
geldi" **%0** kapsamla yanıtsızdır ve o üç günde aynı artış her gün yeniden ödenir.

#### İzleme Kendi Faturasını Taşıyor

İkinci tablo kalemleri döker. Günlük toplam 753 birimdir; bunun **124 birimi** (%16) izleme
verisinin kendi maliyetidir — zaman serisi deposu 54, günlük deposu 44, iz deposu 26. Üçü de ölçen
taraftır ve hiçbir isteği karşılamaz.

Ölçen tarafın ölçülmesi kursun kendi kuralının kendine uygulanmasıdır. İki sayı bunun yanında
okunur: hiçbir soru açmayan tek etiketin kaldırılması tam serinin %89'unu kazandırıyordu, hiçbir
soruya yanıt vermeyen paneller sorgu maliyetinin %95'ini tarıyordu. **Karşılıksız veri bu tabloda
bir kalem olarak görünür.**

#### Boşta Kaynak ile Doyum

Üçüncü tablo iki bedeli aynı satıra koyar. Hedef kullanım oranı yükseldikçe kapasite küçülür,
dönem maliyeti 27.785 birimden 9.262'ye, boşta duran kapasitenin bedeli 19.449'dan 926 birime iner.
Buna karşılık %90 hedefte otuz günün **sekizinde** talep kapasiteyi aşar ve 360 dakika kesinti
çıkar; talep tepesi 1,21, kapasite 1,11'dir.

Son sütun kararın kendisidir: doyumdan kaçınmanın dakika başına fiyatı. %75 hedefte doyum sıfırdır
ve fazladan boşta duran kapasite kaçınılan dakika başına **5,1 birim** tutar. Aynı sıfır doyum %60
hedefte 12,9, %45'te 25,7, %30'da 51,5 birime mal olur. **Boşta kaynak bir sigortadır ve aynı
korumanın fiyatı on kat değişir;** hedefi %75'in altına çekmek tek bir doyum dakikası kazandırmaz.

Bu tablonun bir yanı ölçülemeyendir: kesinti dakikasının kaç birime karşılık geldiği yazılı
değildir. Kaynak fiyatı faturadan okunur, kesintinin fiyatı okunmaz.

#### Ölçek Ekonomisinin Çalışmadığı Kalem

Dördüncü tablo ölçeği sekiz katına çıkarır. Altyapı beklendiği gibi davranır: milyon istek başına
507,3 birimden **344,3 birime** iner, çünkü sabit tabanlar amortize olur ve paylaşılan veri deposu
ile toplu iş kümesi ölçek üssü birin altındadır.

İzleme tersine gider. Milyon istek başına 100,0 birimden **243,6 birime** çıkar ve payı %16'dan
**%41'e** yükselir. Nedeni varsayımda açıkça yazılıdır: örnek sayısı `k` katına çıkarken etiket
kardinalitesi de büyür, seri sayısı ikisinin çarpımıdır ve ölçek üssü 1,5'e oturur. Ölçüt hattı
büyüyen sistemden **daha hızlı** büyür.

Toplam birim maliyet bu iki eğrinin toplamıdır ve dönüş noktası tablodadır: 607,3'ten 546,7'ye,
sonra 545,5'e iner ve sekiz katta **587,9'a geri çıkar**. Ölçek ekonomisi dört kat büyümede
tükenir; ondan sonra sistemi büyütmek birim maliyeti düşürmez, çünkü tasarrufu izleme kalemi geri
alır. **Ölçek ekonomisinin çalışmadığı kalem gözlemlenebilirliğin kendisidir.**

#### Özet

- Sekiz maliyet sorusundan dördü tam, ikisi kısmi yanıtlanır, ikisi yanıtsız kalır; üç neden
  adıyla yazılır — etiketsiz kaynak (%30), paylaşılan kalemin bölüştürülememesi, üç gün gecikmeli
  fatura verisi.
- Günlük 753 birimin 124'ü (%16) izleme verisinin kendi maliyetidir; ölçen taraf faturada ayrı bir
  kalemdir ve hiçbir isteği karşılamaz.
- %90 hedef kullanımda 30 günün 8'i doyar ve 360 dakika kesinti çıkar; %75'te doyum sıfırlanır ve
  kaçınılan dakika 5,1 birime, %30'da aynı koruma 51,5 birime mal olur.
- Ölçek sekiz katına çıkarken altyapı milyon istek başına 507,3'ten 344,3 birime iner, izleme
  100,0'dan 243,6'ya çıkar ve payı %41'e gider; toplam birim maliyet dört katta dibi bulur (545,5)
  ve sekiz katta 587,9'a döner.

#### Kurs Kapanışı

| Ders | Yanıtlanan soru | Yanıtlanamayan soru ve nedeni | Verinin bedeli |
|---|---|---|---|
| Ölçüt Toplama Modelleri | 9/12 (itme) | S12, taşınmayan işlem kimliği | 1,6 MB/soru |
| Zaman Serisi Verisi | 11/12 | S12, etiketle çözülmez | 634,82 GB karşılıksız etiket |
| Sorgu ve Toplulaştırma | 2/4 ölçü birebir | 729 istek, özet siler | 3,6M kayıt taraması |
| Günlük Toplama | 9/12 (1x yük) | 3 soru, kırpılan hata satırı | 75 MB/soru (2x yük) |
| Günlük Ayrıştırma | 4/6 doğru | 2 soru, bakımsız kural | 35.233 bayt/doğru yanıt |
| Saklama ve Maliyet | 11/12 | S12, hiçbir basamakta yok | 2,76 GB/soru |
| Dağıtık İzleme Altyapısı | 9/11 (iz) | 1 soru, enstrümantasyon derinliği | 43,7 MB/soru |
| Enstrümantasyon Standartları | 6/10 (sözleşme) | 4 soru, uyumsuz servis | 20 alan değişikliği |
| Gösterge Tablosu Tasarımı | 11/12 (düzenden sonra) | 1 soru, toplanmamış boyut | 814/859 karşılıksız seri |
| Uyarı Kuralları | 7/8 olay (üç kural) | 1 olay, ölçütün kendisi | 21 yanlış alarm |
| Uyarı Yorgunluğu | 13/20 olay | 7 olay, sıradaki gecikme | 191 bildirim, %93 boş |
| Sentetik İzleme | 10/10 (ikisi birlikte) | 3 arıza, sabit girdili yoklama | 480 yoklama/gün |
| Nöbet Düzeni | 5/8 | 3 soru, ölçülmeyen toparlanma | 118,7 toparlanma saati |
| Olay Sınıflandırma | 4/7 | 3 soru, olay kapanmadan | 11.040 etki-dakika |
| Çalışma Yordamları | 5/8 | 3 soru, yordamın geçerliliği | 384 dakika gecikme |
| Olay Sonrası İnceleme | 7/8 | 1 soru, karşı olgu | 10.971 bayt/soru |
| Hata Bütçesi Yönetimi | 5/6 | 1 soru, karşı olgu | 5.952 bayt/soru |
| Kapasite ve Maliyet İzleme | 4/8 tam | 2 soru, etiketsiz kaynak | 124 br/gün izleme |

Kursun kuralı on sekiz satırın hepsinde aynı biçimde okunur: **veri sorunun yanıtı kadar
değerlidir; hiçbir soruyu yanıtlamayan veri maliyet, yanıtsız kalan soru risktir.** Birinci sütun
hiçbir derste tam değildir, dördüncü sütun her derste bir sayı taşır.

Üçüncü sütunda dört neden tekrar eder. **Toplanmamış boyut** on satırda çıkar: alan hiç
yazılmamıştır ve ne saklamayı uzatmak ne etiket eklemek onu açar — işlem kimliği, abone grubu,
toparlanma penceresi, etiketsiz kaynak hep aynı boşluktur. **Silinmiş ayrıntı** üç satırdadır: veri
toplanmış, sonra bir katmanda kaybolmuştur — özetin sildiği eşik sorusu, kırpılan hata satırı,
bakımsız kuralın boş bıraktığı alan. **Geç gelen yanıt** üç satırdadır: veri vardır ama sorulduğu
anda orada değildir. **Karşı olgu** iki satırdadır ve hiçbir kayıtla açılmaz: kapanan maddenin
önlediği kesinti, durdurmanın önlediği olay. İlk üçü bir tasarım kararıyla kapatılabilir;
dördüncüsü kapatılamaz ve yerine önlenmeyenin sayılması geçer.

Sistem artık görünür ve olaylar yönetiliyor. Bir sonraki kurs, **M22/K07 Sunucu, Ağ ve
Sertleştirme**, görünen şeyin altına iner: bu on sekiz dersin ölçtüğü her şey bir makinenin ve bir
ağın üstünde koşuyordu ve ikisi de hâlâ varsayılan ayarlarıyla duruyor. Açık duran port, yazılmamış
kural, değiştirilmemiş öntanımlı hesap — oradaki yüzey ne kadar geniş?

