strace ile Linux’ta Sistem Çağrılarını İzleme

Bir uygulamanın neden bu kadar yavaş çalıştığını, bir servisin neden belirli bir dosyaya erişemediğini ya da bir programın arka planda ne yaptığını hiç merak ettiniz mi? İşte tam bu noktada strace devreye girer. Linux dünyasının en güçlü hata ayıklama araçlarından biri olan strace, bir sürecin çekirdeğe yaptığı tüm sistem çağrılarını gerçek zamanlı olarak izlemenizi sağlar. Kaynak koduna ihtiyaç duymadan, debug sembolü olmadan, sadece süreci çalıştırarak ne yaptığını görebilirsiniz. Bu yazıda strace‘i gerçek dünya senaryolarıyla ele alacağız.

strace Nedir ve Nasıl Çalışır?

strace, Linux çekirdeğinin ptrace sistem çağrısını kullanarak bir süreci izleyen bir araçtır. Program çalışırken yaptığı her sistem çağrısını (open, read, write, fork, execve vb.) ve bu çağrıların dönüş değerlerini ekrana basar. Sinyal bildirimlerini de yakalayabilir.

Temel mantığı şöyle düşünebilirsiniz: Uygulamanız kullanıcı uzayında (user space) çalışır. Dosya okumak, ağ bağlantısı kurmak, bellek ayırmak gibi işlemler için çekirdeğe (kernel space) geçmesi gerekir. İşte bu geçiş noktaları sistem çağrılarıdır ve strace tam olarak bu geçişleri dinler.

Dikkat: strace izlediği süreci yavaşlatır. Production ortamında dikkatli kullanılmalıdır. Bazı durumlarda %10-100 arasında performans kaybı yaşanabilir.

Kurulum

Çoğu dağıtımda varsayılan olarak gelmez ama paket depolarında mevcuttur:

# Debian/Ubuntu
sudo apt install strace

# RHEL/CentOS/Fedora
sudo yum install strace
# veya
sudo dnf install strace

# Arch Linux
sudo pacman -S strace

Temel Kullanım

En basit kullanım şekli bir komutun önüne strace eklemektir:

strace ls /tmp

Bu komutu çalıştırdığınızda ekrana akan onlarca satır sizi şaşırtabilir. Basit bir ls komutu bile onlarca sistem çağrısı yapar. Çıktının bir kısmı şöyle görünür:

execve("/usr/bin/ls", ["ls", "/tmp"], 0x7ffd... /* 23 vars */) = 0
brk(NULL)                               = 0x55a8b2e45000
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF2113>1"..., 832) = 832
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3

Her satır bir sistem çağrısıdır. Format şöyledir: sistem_cagri_adi(parametreler) = donus_degeri

Önemli Parametreler

strace‘in asıl gücü parametrelerinden gelir:

  • -e trace=: Belirli sistem çağrılarını filtreler, örneğin -e trace=open,read
  • -p PID: Halihazırda çalışan bir sürece bağlanır
  • -f: Fork edilen alt süreçleri de izler
  • -o dosya: Çıktıyı bir dosyaya yazar
  • -t: Her satıra zaman damgası ekler (saat:dakika:saniye)
  • -T: Her sistem çağrısının ne kadar sürdüğünü gösterir
  • -c: İstatistik özeti verir, hangi çağrı kaç kez yapılmış
  • -s: String çıktı uzunluğunu ayarlar, varsayılan 32 karakterdir
  • -v: Yapıları tam detayıyla gösterir
  • -x: String olmayan argümanları hexadecimal gösterir
  • -y: File descriptor’ları dosya yollarıyla gösterir
  • -yy: Soket bilgilerini de ekler

Gerçek Dünya Senaryosu 1: Uygulama Hangi Dosyaları Açıyor?

En sık karşılaştığım senaryolardan biri şudur: Bir uygulama başlarken hata veriyor ama hangi config dosyasını okumaya çalıştığını bilmiyorsunuz. Belgelendirme yok, kaynak kodu yok ya da bakmaya zamanınız yok.

strace -e trace=openat,open -o /tmp/dosya_izleme.txt uygulama_adi
cat /tmp/dosya_izleme.txt | grep -i "config|conf|.ini|.yaml"

Daha da pratik bir yaklaşım:

strace -e trace=openat 2>&1 python3 myapp.py | grep "ENOENT"

ENOENT (No such file or directory) hatası alan satırları filtreleyerek uygulamanın aradığı ama bulamadığı dosyaları hemen görürsünüz. Bu tek satır bana sayısız kez saatlerce debug sürecini birkaç dakikaya indirdi.

Örnek çıktı:

openat(AT_FDCWD, "/etc/myapp/config.yaml", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/local/etc/myapp.conf", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/user/.myapp/config", O_RDONLY) = 5

İşte bu çıktı size şunu söyler: Uygulama önce iki yerde aradı, bulamadı, üçüncüde buldu. Artık hangi config dosyasının kullanıldığını kesin olarak biliyorsunuz.

Gerçek Dünya Senaryosu 2: Çalışan Bir Sürece Bağlanma

Bazen sorun zaten çalışan bir süreçte oluşur. Servisi yeniden başlatmak istemiyorsunuz ya da sorun sadece belirli koşullarda ortaya çıkıyor. -p parametresiyle mevcut bir sürece bağlanabilirsiniz:

# Önce PID'i bulun
pgrep nginx
# veya
pidof nginx

# Sürece bağlanın
sudo strace -p 1234

Nginx’in birden fazla worker süreci varsa hepsini aynı anda izleyebilirsiniz:

sudo strace -p 1234 -p 1235 -p 1236 -o /tmp/nginx_strace.log

Ya da tüm nginx süreçlerine otomatik bağlanmak için:

sudo strace $(pgrep nginx | sed 's/^/-p /' | tr 'n' ' ') -o /tmp/nginx_debug.log

Gerçek Dünya Senaryosu 3: Performans Darboğazı Tespiti

Bir serviste periyodik yavaşlama var. Kodda herhangi bir sorun göremiyorsunuz. -c ve -T parametreleri burada hayat kurtarır.

-c ile istatistik özeti alın:

strace -c -p $(pgrep myservice) &
sleep 30
kill %1

Çıktı şöyle görünür:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 78.23    2.342100        2342      1000           fsync
 12.45    0.373200          37     10000           write
  5.32    0.159600          16     10000           read
  ...

Eğer fsync çağrısı zamanın %78’ini alıyorsa, uygulama her yazma işleminde diski senkronize ediyordur. Bu ciddi bir performans problemidir. Diskinizin yavaş olması ya da SSD yerine HDD kullanılıyor olması bu sorunu katmerlendirir.

-T parametresiyle hangi çağrıların uzun sürdüğünü tek tek görebilirsiniz:

strace -T -e trace=read,write,fsync -p 1234 2>&1 | awk '$NF ~ /.[0-9]+/ && $NF+0 > 0.1'

Bu komut 100ms’den uzun süren sistem çağrılarını filtreler. Çıktıda gördüğünüz gibi değerler saniye cinsindendir.

Gerçek Dünya Senaryosu 4: Ağ Bağlantılarını İzleme

Bir uygulama nereye bağlanıyor? Hangi IP’lere, hangi portlara istek atıyor? Bunu firewall logları olmadan da anlayabilirsiniz:

strace -e trace=network -p $(pgrep myapp) 2>&1 | grep -E "connect|bind|listen"

Daha detaylı soket bilgisi için:

strace -e trace=connect,bind,socket -yy -p 1234

-yy parametresi soket bilgilerini insan okunabilir formatta gösterir:

connect(5<TCP:[local_ip:port]>, {sa_family=AF_INET, sin_port=htons(5432), sin_addr=inet_addr("192.168.1.100")}, 16) = 0

Artık uygulamanın 192.168.1.100:5432 adresine (muhtemelen PostgreSQL) bağlandığını görebiliyorsunuz. Herhangi bir network monitoring aracı kurmadan, sadece strace ile.

Gerçek Dünya Senaryosu 5: Permission Denied Hatalarını Analiz Etme

“Permission denied” hatası alıyorsunuz ama hangi dosya ya da kaynak için olduğunu bilmiyorsunuz. Uygulama sadece genel bir hata mesajı verip çıkıyor.

strace -e trace=openat,stat,access 2>&1 myapp | grep "EACCES|EPERM"

Çıktı:

openat(AT_FDCWD, "/var/log/myapp/app.log", O_WRONLY|O_CREAT|O_APPEND, 0644) = -1 EACCES (Permission denied)

Hemen anladınız: /var/log/myapp/app.log dosyasına yazma izni yok. Çözüm basit:

sudo chown myappuser:myappuser /var/log/myapp/
# veya
sudo chmod 755 /var/log/myapp/

Bu yöntemi kullanarak özellikle systemd servisleri ve containerized uygulamalarda çok sık izin sorunlarını çözdüm. Kaynak kodu olmayan third-party araçlarda bu yaklaşım gerçekten paha biçilemez.

Gerçek Dünya Senaryosu 6: Sonsuz Döngü ve Yüksek CPU Tespiti

Bir process %100 CPU kullanıyor ama neden bilmiyorsunuz. strace burada da yardımcı olur:

sudo strace -p $(pgrep -f "sorunlu_uygulama") -c -e trace=all

Eğer çıktıda aynı sistem çağrısının milyonlarca kez tekrarlandığını görüyorsanız (örneğin gettimeofday, clock_gettime), uygulama muhtemelen sonsuz bir döngüde zaman kontrolü yapıyor ya da busy-waiting durumundadır.

Gerçek zamanlı olarak görmek isterseniz:

sudo strace -p 1234 2>&1 | head -50

Çıktı akışına bakın: Eğer aynı satırlar sürekli tekrar ediyorsa, sonsuz döngü olduğu açıktır.

Çıktıyı Anlamlandırma: Hata Kodları

strace çıktısında bazı hata kodlarına çok sık rastlarsınız. Bunları ezberlemek debug sürecini hızlandırır:

  • ENOENT: Dosya veya dizin bulunamadı
  • EACCES: Erişim reddedildi
  • EPERM: İşlem izni yok (genellikle root gerektiren işlemler için)
  • ENOBUFS / ENOMEM: Bellek veya buffer yetersiz
  • EINTR: Sistem çağrısı sinyal tarafından kesildi
  • EAGAIN / EWOULDBLOCK: Kaynak geçici olarak kullanılamıyor (non-blocking I/O)
  • ECONNREFUSED: Bağlantı reddedildi
  • ETIMEDOUT: Bağlantı zaman aşımına uğradı
  • EEXIST: Dosya veya dizin zaten var
  • EBADF: Geçersiz file descriptor

Bu kodlar çıktıda her zaman parantez içinde açıklamasıyla birlikte gelir, bu da strace‘i gerçekten kullanıcı dostu kılar.

Alt Süreçleri İzleme: -f Parametresi

Bir süreç başka süreçler başlatıyorsa (örneğin bir shell scripti, systemd servisi ya da multiprocess uygulama), -f parametresi ile fork edilen tüm alt süreçleri de izleyebilirsiniz:

strace -f -o /tmp/full_trace.log bash deploy.sh

Bu özellikle CI/CD pipeline’larında veya karmaşık başlangıç scriptlerinde sorun giderirken çok işe yarar. Çıktıda her süreç kendi PID’iyle belirtilir:

[pid 12345] execve("/usr/bin/git", ["git", "pull"], ...) = 0
[pid 12346] openat(AT_FDCWD, ".git/config", O_RDONLY) = 3

String Uzunluğunu Artırma: -s Parametresi

Varsayılan olarak strace stringleri 32 karakterde keser. Bu bazen kritik bilgileri gizler. Özellikle HTTP isteklerini, veritabanı sorgularını veya uzun dosya yollarını izlerken string uzunluğunu artırın:

strace -s 1024 -e trace=write -p $(pgrep myapp)

Eğer bir uygulamanın tam olarak hangi SQL sorgusunu gönderdiğini görmek istiyorsanız:

strace -s 4096 -e trace=write,sendto -p $(pgrep myapp) 2>&1 | grep -A2 "SELECT|INSERT|UPDATE"

Bu yöntem, ORM kullanan uygulamalarda gerçekte hangi sorguların üretildiğini görmek için harika çalışır.

Pratik Tek Satırlık Komutlar

Sysadmin günlük hayatında işe yarayan hazır tarifler:

# Bir sürecin açık tuttuğu tüm dosyaları bul
strace -e trace=openat -p 1234 2>&1 | grep -v "= -1"

# En çok hangi sistem çağrısı yapılıyor?
strace -c myprogram 2>&1 | sort -k4 -rn | head -10

# Ağ trafiğini izle ve IP adresi göster
strace -e trace=connect -yy myprogram 2>&1 | grep "sin_addr"

# Gerçek zamanlı yazma işlemlerini izle
strace -e trace=write -s 2048 -p 1234 2>&1 | grep -v "^write.*= [0-9]$"

# Belirli bir dosyaya yapılan tüm erişimleri izle
strace -e trace=openat -p 1234 2>&1 | grep "dosya_adi"

ltrace ile Karşılaştırma

strace sistem çağrılarını izlerken, ltrace kütüphane çağrılarını (libc fonksiyonları gibi) izler. İkisi birbirini tamamlar:

# Sistem çağrıları
strace -e trace=read,write myapp

# Kütüphane çağrıları (strcmp, malloc vb.)
ltrace myapp

Hangi katmanda sorun olduğunu anlamak için ikisini birlikte kullanmak iyi bir yaklaşımdır. Eğer ltrace‘de sorun görüyorsanız uygulama mantığında, strace‘de görüyorsanız işletim sistemi etkileşimindedir.

Güvenlik ve Production Dikkat Notları

strace güçlü bir araçtır ama dikkatli kullanılmalıdır:

  • Performans etkisi: İzlenen süreç ciddi ölçüde yavaşlar. Production’da kısa süreli kullanın.
  • Güvenlik: strace çıktısında şifreler, API anahtarları, session token’lar görünebilir. Çıktı dosyalarını güvenli tutun.
  • Root yetkisi: Başka bir kullanıcının sürecine bağlanmak için root gerekir.
  • Seccomp: Bazı containerized ortamlar ptrace sistem çağrısını kısıtlar. Docker’da --cap-add=SYS_PTRACE gerekebilir.
  • SELinux: SELinux politikaları strace kullanımını engelleyebilir, geçici olarak permissive moda alınabilir.

Docker container içinde kullanmak için:

docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined myimage strace myapp

Alternatif: perf ve bpftrace

strace harika bir araç ama production’da daha hafif alternatiflere ihtiyaç duyabilirsiniz:

  • perf trace: strace‘e benzer ama çok daha düşük overhead ile çalışır. eBPF tabanlı sistemlerde tercih edilir.
  • bpftrace: Modern Linux çekirdeklerinde eBPF ile sistem çağrılarını neredeyse sıfır overhead ile izler.
# perf trace ile aynı işlev
sudo perf trace -p 1234

# bpftrace ile openat çağrılarını izle
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %sn", comm, str(args->filename)); }'

Ancak hata ayıklama ve öğrenme aşamasında strace‘in okunabilirliği ve kullanım kolaylığı hala rakipsizdir.

Sonuç

strace, Linux sistem yönetiminin ve hata ayıklamanın vazgeçilmez araçlarından biridir. Belgelendirmesi olmayan bir uygulamanın hangi dosyaları okuduğunu bulmak, gizli bir permission hatasını yakalamak, performans darboğazını tespit etmek ya da ağ bağlantılarını izlemek için kaynak koda ihtiyaç duymadan çalışabilirsiniz. Bu özelliği onu özellikle binary uygulamalar, legacy sistemler ve third-party araçlarla uğraşırken paha biçilmez kılar.

Temel kullanımı öğrendikten sonra -e, -f, -c, -T gibi parametreleri günlük iş akışınıza entegre edin. Zamanla strace çıktısını okumak size ikinci bir dil gibi gelmeye başlar. Bir süreci “şeffaflaştırmak” ve arka planda ne yaptığını görmek hem hata ayıklamayı hem de sistemi anlama sürecini kökten değiştirir.

Son bir tavsiye: Bir sonraki “neden çalışmıyor?” probleminizde direkt Google’a atlamadan önce strace -e trace=openat,connect -o /tmp/debug.log problemli_komut deneyin. Çoğu zaman cevap orada gizlidir.

Yorum yapın