---
title: İzleme
source: 'https://academia.sh/tr/kurslar/go-uretim/izleme'
course: 'Üretim Go: Test, Araçlar ve Başarım'
language: tr
updated: '2026-09-13T05:08:46+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'İki kurulumun (sıralı, üç işçili havuz) ürettiği yürütme izi olay sayılarını filtreleyerek karşılaştırır'
    - 'Aynı toplam işin farklı sayıda eşzamanlı birimle yapılmasının hangi olay sayısını değiştirdiğini, hangisini değiştirmediğini ayırt eder'
    - 'İz toplamanın programın davranışını değiştirdiğini, sayıların bu sınırla birlikte okunması gerektiğini gösterir'
---

# İzleme

Yürütme izi bir koşum bilgisidir ve burada olay sayısıyla okunuyor: aynı altı kaydı işleyen iki kurulum, biri sıralı biri üç işçiyle dağıtık, aynı sayıda kayıt işleme olayı üretiyor ama farklı sayıda işçi başlangıç olayı üretiyor. Sınırlayıcı ölçüm: iz toplamak programın davranışını değiştiriyor, bu yüzden sayılar buna göre okunuyor.

Önceki ders bir programın **kaç değer** ayırdığını sayarken durdu — bir programın yalnız
bellek yönü. Ama bir programın çalışma zamanı bundan fazlasını içeriyor: hangi goroutine
ne zaman başladı, kaç tanesi eşzamanlı çalıştı. Bu ders bu daha geniş kayda bakıyor: dilin
kendi yürütme izi, bir programın koşumu sırasında olan olayları kaydediyor ve bu ders o
kaydı **olay sayısıyla** okuyor.

Bu kursun dört dersi de aynı biçimde ilerledi: önce bir bilginin nereden geldiğini
sınıflandır (kaynak, araç, koşum), sonra o sınıfa özgü bir sınırı ölç. Profil ve kaçış
kararı iki ayrı sınıftaydı — biri koşum, biri araç. Ayırma sayısı yine koşumdu, ama
tek bir sayıya değil dört karşılaştırmaya bakıyordu. Bu son ders koşuma dönüyor, ama
sorduğu şey daha önce hiç sorulmayan bir tür: **kaç ayrı yürütme biriminin** gerçekten
çalıştığı.

Yürütme izi de bu kursun ilk dersinden beri süren ayrımın bir örneği — koşum bilgisi: kaynağa
bakan biri kaç goroutine'in gerçekten çalıştığını göremez, yalnız çalıştırıp sorabilir. Ama bu
derste okunan sayı, profil ya da ayırma sayısından farklı bir şeyi yakalıyor: bellek değil,
**eşzamanlılığın kendisi**. Bu kursun dört ölçü ekseni (M09/K03) burada kullanılmıyor; bu ders
yalnız iki kurulumun ürettiği olay sayısını karşılaştırıyor.

"İzleme" sözcüğü burada dar bir anlamda kullanılıyor: dilin kendi yürütme izi mekanizması,
bir profil ya da bir günlük kaydı değil. Profil "kaç değer ayrıldı" diye soruyordu; günlük
kaydı (bu kursta ayrıca ele alınmayan bir başka mekanizma) uygulamanın kendi yazdığı
iletileri tutuyor. Yürütme izi ikisinden de farklı: çalışma zamanının kendisinin,
programın hangi anlarda hangi yürütme birimini çalıştırdığını kaydeden bir mekanizma. Bu
ders o mekanizmanın yalnız uygulamaya özgü işaretleri kullanılan kısmını ölçüyor.

## Neden Ham Sayı Değil, Etiketli Sayı

Bir yürütme izi yalnız programın yazdığı işleri kaydetmiyor; çalışma zamanının kendi
arka plan işlerini de kaydediyor — zamanlayıcının bir iş parçacığını nasıl dağıttığı,
çöp toplayıcının ne zaman bir tarama başlattığı gibi. Bu arka plan etkinliği makinenin o
anki yüküne, işletim sisteminin zamanlamasına bağlı ve **koşumdan koşuma değişiyor**. Bu
yüzden bir izin **toplam** olay sayısı — programın kendi yazdığı her şey dahil arka plan
etkinliği de sayılırsa — aynı kaynak kodla bile iki ayrı koşumda farklı çıkabiliyor.

Bu ders bu değişkenliği ölçmüyor, ondan **kaçınıyor**: toplam sayı yerine, kendi seçtiği
iki etiketin (`kayitBS-isle`, `iscibasBS`) kaç kez geçtiğini sayıyor. Bu etiketler
yalnız bu programın kendi kodunda geçiyor, arka plan etkinliğinde hiç görünmüyor — bu
yüzden bu iki sayı, toplam olay sayısından farklı olarak koşumdan koşuma **sabit**
kalıyor. Kursun kararlılık kalıbı burada da geçerli: ölçülen sayı önce belirlenimci
olduğu kanıtlanmadan tabloya girmiyor.

Bu seçim, önceki üç dersteki tekrarlanabilirlik arayışının doğrudan devamı: profil sayısı beş
koşumda tek değer verdiği için kullanılabilir sayıldı, ayırma sayısı da aynı sınavdan geçti.
Yürütme izi kendi başına bu sınavı geçemiyor — ham hâliyle koşumdan koşuma değişiyor — ama izin
**bir bölümü**, kendi etiketlediği bölüm, geçiyor. Bu ders bu yüzden izin tamamını değil, kararlı
çıkan bölümünü ölçüyor.

## İzi Etiketlerle Okumak

Bir yürütme izinin ham içeriği, bu kursta basılması yasak olan her şeyi taşıyor: goroutine
numaraları, zaman damgaları, yığıt izleri. Bu ders bu içeriği hiç yazdırmıyor; onun yerine
izin içinde **kendi seçtiği** iki etiketi arıyor ve yalnız bu etiketlerin kaç kez geçtiğini
sayıyor.

```go
// iz.go — iz dosyasini olusturuyor ve icindeki bir etiketin kac kez gectigini sayiyor
package main

import (
	"context"
	"os"
	"os/exec"
	"runtime/trace"
	"strings"
)

const kayitEtiketi = "kayitBS-isle"
const iscibasEtiketi = "iscibasBS"

// izKaydet, verilen isi bir iz dosyasina kaydedip yolunu donduruyor; yol
// hicbir yerde basilmiyor, yalniz bu islevin icinde kullaniliyor.
func izKaydet(f func(ctx context.Context)) string {
	dizin, _ := os.MkdirTemp("", "iz")
	yol := dizin + "/trace.out"
	dosya, _ := os.Create(yol)
	trace.Start(dosya)
	f(context.Background())
	trace.Stop()
	dosya.Close()
	return yol
}

// olaySayisi, iz dosyasini iz aracina veriyor ve yalniz istenen etiketin kac
// kez gectigini sayiyor. Aracin urettigi metin hicbir zaman basilmiyor.
func olaySayisi(izYolu, etiket string) int {
	cmd := exec.Command("go", "tool", "trace", "-d=parsed", izYolu)
	cmd.Env = append(os.Environ(), "GOTOOLCHAIN=local")
	cikti, _ := cmd.CombinedOutput()
	return strings.Count(string(cikti), etiket)
}
```

**BS7.** `olaySayisi`, iz aracının ürettiği metni okuyor ama hiçbir zaman ekrana yazmıyor —
yalnız `strings.Count` ile bir alt dizginin kaç kez geçtiğini sayıyor ve bu sayıyı
döndürüyor. İz aracının kendi çıktısı goroutine numarası, zaman damgası ve tam dosya yolu
taşıyor; bunların hiçbiri programın herhangi bir noktasında bir değişkene bile atanmıyor,
doğrudan sayma işleminin içinde tüketilip atılıyor.

`izKaydet` de benzer bir disiplin taşıyor: iz dosyasının yolu `os.MkdirTemp` ile kurulan
geçici bir dizinde duruyor ve bu yol yalnız `olaySayisi`ye geçirilmek için kullanılıyor —
hiçbir `fmt.Println` çağrısına girmiyor. İşlev imzası da bilinçli: `f func(ctx
context.Context)` alarak, izlenecek işi çağırana bırakıyor. Bu sayede aynı `izKaydet`
işlevi hem sıralı hem havuzlu kurulumu izlemek için kullanılabiliyor — yalnız hangi
işlevin çağrıldığı değişiyor, izleme mekaniği aynı kalıyor.

## İşçi Sayısı Neden Üç

Havuzlu kurulum üç işçi açıyor, altı kayıt işliyor — işçi sayısı kayıt sayısını tam
bölmüyor bilerek: her işçi ortalama iki kayıt işlemek zorunda kalıyor ama kanaldan
okuma sırası önceden belli değil, bu yüzden hangi işçinin kaç kayıt aldığı koşumdan
koşuma değişebiliyor. Bu ders o dağılımı hiç ölçmüyor — yalnız üç işçinin **başladığını**
sayıyor, kaçının kaç kayıt aldığını değil. Bu, kursun M09/K03'te kurduğu ve burada
kullanılmayan bir eksenle (bir goroutine'in nasıl duracağı) karışmaması için bilinçli bir
sınır: bu ders yalnız kaç yürütme biriminin **var olduğunu** ölçüyor, aralarındaki
paylaşımı değil.

## İki Kurulum: Sıralı ve Havuzlu

Aşağıdaki ölçüm aynı altı kaydı iki ayrı yoldan işliyor. Sıralı kurulum her kaydı çağıran
goroutine'in kendisinde, sırayla işliyor. Havuzlu kurulum aynı altı kaydı üç işçi
goroutine'e dağıtıyor; her işçi başladığında bir kez etiketli bir kayıt bırakıyor, sonra
kanaldan gelen kayıtları işliyor. Her iki kurulumda da her kayıt, `trace.WithRegion` ile
aynı etiketle işaretleniyor.

```go
// olcum.go — ayni is, iki kurulum: sirali ve uc iscili havuz
package main

import (
	"context"
	"fmt"
	"os"
	"runtime/trace"
	"strconv"
	"sync"
)

type Kayit struct {
	Ad     string
	Miktar int
}

var kayitlar = []Kayit{
	{"vida", 1}, {"somun", 2}, {"pul", 3}, {"civi", 4}, {"civata", 5}, {"rondela", 6},
}

func isle(ctx context.Context, k Kayit) int {
	sonuc := 0
	trace.WithRegion(ctx, kayitEtiketi, func() {
		sonuc = k.Miktar * 2
	})
	return sonuc
}

func sirayla(ctx context.Context) int {
	toplam := 0
	for _, k := range kayitlar {
		toplam += isle(ctx, k)
	}
	return toplam
}

func havuzla(ctx context.Context, iscisi int) int {
	is := make(chan Kayit)
	var mu sync.Mutex
	toplam := 0
	var wg sync.WaitGroup
	for id := 0; id < iscisi; id++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			trace.Log(ctx, iscibasEtiketi, strconv.Itoa(id))
			for k := range is {
				v := isle(ctx, k)
				mu.Lock()
				toplam += v
				mu.Unlock()
			}
		}(id)
	}
	for _, k := range kayitlar {
		is <- k
	}
	close(is)
	wg.Wait()
	return toplam
}

func main() {
	sYol := izKaydet(func(ctx context.Context) { sirayla(ctx) })
	defer os.RemoveAll(sYol)
	hYol := izKaydet(func(ctx context.Context) { havuzla(ctx, 3) })
	defer os.RemoveAll(hYol)

	fmt.Println("-- iki kurulumda uretilen olay sayisi --")
	fmt.Printf("%-10s %-22s %4d\n", "sirali", "kayit isleme olayi", olaySayisi(sYol, kayitEtiketi))
	fmt.Printf("%-10s %-22s %4d\n", "sirali", "isci baslangic olayi", olaySayisi(sYol, iscibasEtiketi))
	fmt.Printf("%-10s %-22s %4d\n", "havuzlu", "kayit isleme olayi", olaySayisi(hYol, kayitEtiketi))
	fmt.Printf("%-10s %-22s %4d\n", "havuzlu", "isci baslangic olayi", olaySayisi(hYol, iscibasEtiketi))
}
```

```
-- iki kurulumda uretilen olay sayisi --
sirali     kayit isleme olayi       12
sirali     isci baslangic olayi      0
havuzlu    kayit isleme olayi       12
havuzlu    isci baslangic olayi      3
```

**BS8.** `isle`, her iki kurulumda da aynı işlevle çağrılıyor ve her çağrı bir
`trace.WithRegion` bloğuna sarılıyor — bu, izin `kayitEtiketi` ile işaretlenmiş bir
başlangıç ve bir bitiş olayı üretmesine yol açıyor. Altı kayıt işlendiğinde bu on iki
olaya karşılık geliyor (altı başlangıç, altı bitiş) — kurulum ne olursa olsun, çünkü her
iki kurulumda da toplam altı kayıt işleniyor.

`havuzla` işlevinde her işçi, kanaldan okumaya başlamadan **önce** `trace.Log` çağrısını
yapıyor — döngünün içinde değil, döngüden hemen önce, bir kez. Bu sıralama bilinçli: eğer
etiket her kayıt için tekrar bırakılsaydı, işçi başlangıç sayısı da işlenen kayıt sayısına
bağlı çıkardı ve iki farklı bilgi (kaç işçi var, kaç kayıt işlendi) birbirine karışırdı.
Etiketi yalnız bir kez, işçi hayata geçtiğinde bırakmak, bu iki sayıyı **birbirinden
bağımsız** tutuyor.

## Sayıların Okunması

Tablo iki farklı davranış gösteriyor. `kayit isleme olayi` her iki kurulumda da **on iki** —
sıralı ya da havuzlu, işlenen kayıt sayısı aynı olduğu için üretilen olay sayısı da aynı.
Bu satır, izin **neyi değiştirmediğini** gösteriyor: iş dağıtımının kendisi, yapılan işin
toplam miktarını değiştirmiyor.

`isci baslangic olayi` ise sıralı kurulumda **sıfır**, havuzlu kurulumda **üç**. Sıralı
kurulum hiç ek goroutine açmıyor, bu yüzden hiç işçi başlangıç olayı üretmiyor; havuzlu
kurulum üç işçi açıyor ve her biri başladığında bir kez bu etiketi bırakıyor. Bu satır,
izin **neyi gösterdiğini** açıklıyor: kaç ayrı yürütme biriminin gerçekten çalıştığı —
kaynaktaki `for id := 0; id < iscisi; id++` döngüsünün üç kez döndüğü bir insan tarafından
da sayılabilir, ama iz bunu **çalışan** programdan doğrudan okuyor, kaynağı ayrıca
incelemeye gerek kalmadan.

Bu iki satırın bir arada okunması, tek başına hiçbirinin veremeyeceği bir bilgi veriyor.
Yalnız `kayit isleme olayi` okunsaydı iki kurulumun aynı işi yaptığı görülür ama nasıl
yaptığı bilinmezdi. Yalnız `isci baslangic olayi` okunsaydı havuzlu kurulumun üç işçi
açtığı görülür ama bu üç işçinin gerçekten iş yapıp yapmadığı bilinmezdi — üçü de boşta
kalıp hiçbir kayıt işlememiş olabilirdi. İkisi birlikte üçüncü bir soruyu yanıtlıyor: üç
işçi açıldı **ve** altı kaydın tamamı gerçekten işlendi, hiçbiri kaybolmadı, hiçbiri iki
kez işlenmedi. Bu, kanaldan okuma düzeneğinin doğru çalıştığının bir kanıtı — testin
verdiği "geçti" kararından farklı bir yoldan, ama aynı türden bir güvence.

Kursun açılışı on bir bilgiyi kaynak, araç ve koşum diye ayırmıştı; bu ders o üç sınıftan
yalnız koşumu kullanıyor — hem etiketli bölgeler hem işçi başlangıçları ancak program
gerçekten çalıştırılıp izlendiğinde ortaya çıkıyor.

## Sınırlayıcı Ölçüm: İz Toplamak Davranışı Değiştirir

Bu ders, kursun süre yasağını başka bir açıdan tekrar karşılıyor. `trace.Start` çağrısı
programın her goroutine geçişini, her kilitlenmeyi kaydetmeye başlıyor — bu kaydın kendisi
bedava değil, her olay işlenip yazılırken programın normal akışına ek bir iş biniyor. Bu
yüzden bir programı izlerken görülen davranış, izlenmeyen hâlinden **her zaman biraz
farklı**: iz toplamak programın davranışını değiştiriyor.

Bu iddia burada ölçülmüyor — ölçülmesi süreye bakmayı gerektirirdi ve süre bu kursun
hiçbir dersinde yazılmıyor. Bunun yerine bir cümleyle yazılıp gerekçelendiriliyor, tıpkı
karşılaştırmalı ölçüm dersinin süre yasağını gerekçelendirdiği gibi: iz toplamanın kendisi
bir iş ve bu iş sıfır değil. Bu yüzden yukarıdaki tablo, izlenmeyen bir programın kaç
olay ürettiğini değil, **izlenen** bir programın kaç olay ürettiğini gösteriyor — sayılar
bu çerçevede okunmalı, izleme kapalıyken de aynı davranışın süreceği varsayılmadan.

Bu sınır, önceki üç dersin sınırlarıyla aynı aileden. Profil yalnız koşan yolu görüyordu;
kaçış çözümlemesi yalnız bu derleyicinin kararını gösteriyordu; ayırma sayısı bir sayının
düşmesinin otomatik bir iyileştirme olmadığını öğretmişti. Bu ders de aynı örüntüyü
sürdürüyor: bir ölçüm aracı, ölçtüğü şeyi **ölçme eyleminin kendisiyle** birlikte
sunuyor ve okuyan taraf bu birlikteliği unutursa yanlış bir kesinlik hissine kapılıyor.
İz toplamanın davranışı değiştirmesi, iz aracının bir kusuru değil — herhangi bir gözlem
aracının, gözlemlediği sistemin bir parçası hâline gelmesinin kaçınılmaz bir sonucu.

## Bu Ölçümün Kapsamı

Gerçek bir üretim izinin okuduğu şey bu dersteki iki etiketten çok daha geniş: bir
zamanlayıcının bir goroutine'i ne zaman durdurup başka birini çalıştırdığı, bir
goroutine'in ne kadar süre bir kilidi beklediği, bir çöp toplama turunun ne zaman
başladığı — bunların hepsi aynı izin içinde duruyor ve bir iz görüntüleyicisiyle zaman
çizelgesi olarak incelenebiliyor. Bu tür bir inceleme genelde belirli bir soruna
yanıt arıyor: neden bu istek beklenenden uzun sürdü, hangi goroutine hangi kaynağı
tıkadı. Bu sorular süre içeriyor, bu yüzden bu kursta hiç sorulmuyor.

Bu derste kurulan yöntem bunun yerine dar bir soruya cevap veriyor: belirli bir olay **kaç
kez** oldu. Bu, gerçek bir izin sunduğu bilginin küçük bir dilimi — zaman çizelgesindeki
sıralamayı, çakışmayı, bekleme süresini hiç görmüyor. Ama bu dar soru bile kaynağa
bakılarak yanıtlanamıyor: `havuzla` işlevini okuyan biri üç goroutine açıldığını görebilir,
ama bu üçünün gerçekten çalışıp çalışmadığını, gerçekten iş alıp almadığını yalnız
çalıştırıp izleyerek öğrenebilir.

## Özet

- Yürütme izi bir koşum bilgisidir ve bu derste olay sayısıyla okundu; goroutine numarası,
  zaman damgası ve yığıt izi hiçbir yerde basılmadı.
- Aynı altı kaydı işleyen sıralı ve havuzlu iki kurulum, aynı sayıda (on iki) kayıt işleme
  olayı üretti — iş dağıtımı toplam işin miktarını değiştirmedi.
- İki kurulum farklı sayıda (sıfır, üç) işçi başlangıç olayı üretti — bu fark, kaç ayrı
  yürütme biriminin gerçekten çalıştığını izin doğrudan göstermesinden geliyor.
- İz aracının ürettiği metin hiçbir zaman basılmadı; yalnız seçilen iki etiketin kaç kez
  geçtiği sayıldı.
- İz toplamak programın davranışını değiştiriyor; bu ders bunu ölçmedi, bir cümleyle
  yazıp sayıları bu sınırla birlikte sundu.
- Yürütme izinin ham içeriği koşumdan koşuma değişiyor; bu ders bu yüzden izin tamamını
  değil, kendi etiketlediği ve kararlı çıkan bölümünü ölçtü.

## Sonraki Adım

Bu kursun dört dersi de bir programı **koşturarak** bir şey öğrendi — profil, kaçış kararı,
ayırma sayısı, olay sayısı; hepsi ancak çalışan bir programdan okunabildi ve her biri
kendi ölçüm eyleminin programı biraz değiştirdiğini kabul etmek zorunda kaldı. Sıradaki
konu bu zeminin tamamından çıkıyor: hangi dosyanın derlemeye gireceğini, hangi platforma
çıkılacağını ve ikiliye ne gömüleceğini araç, programı hiç çalıştırmadan söylüyor —
koşumun kendisi artık gerekmiyor.
