ltrace Komutu ile Süreçlerin Kütüphane Çağrılarını İzleme ve Analiz Etme

Bir sürecin neden yavaş çalıştığını, hangi kütüphane fonksiyonunu çağırdığını ya da neden beklenmedik bir davranış sergilediğini anlamaya çalışırken strace yetersiz kalıyorsa, muhtemelen olayın kullanıcı alanında geçtiğini düşünmeniz gerekiyor. İşte tam bu noktada ltrace devreye giriyor. Sistem çağrılarını değil, kütüphane çağrılarını izleyen bu araç, özellikle shared library sorunlarını debug ederken hayat kurtarıcı oluyor.

ltrace Nedir ve strace’den Farkı Nedir?

strace, bir sürecin kernel’a yaptığı sistem çağrılarını (open, read, write, mmap gibi) izler. ltrace ise bir adım geri çekilir ve sürecin kullanıcı alanında çağırdığı dinamik kütüphane fonksiyonlarını yakalar. Yani strace kernel sınırında durur, ltrace ise uygulama ile kütüphane arasındaki köprüde durur.

Pratik bir örnekle açıklayalım: Bir uygulama malloc() çağırıyor. strace bunu görmez çünkü malloc doğrudan bir sistem çağrısı değil, libc içindeki bir fonksiyon. ltrace ise tam olarak bu malloc çağrısını, argümanlarını ve dönüş değerini gösterir. Eğer malloc sonunda brk ya da mmap sistem çağrısına dönüşüyorsa, onu da görmek için strace‘e bakarsınız. İkisini birlikte kullanmak, tam resmi görmenizi sağlar.

ltrace, PLT (Procedure Linkage Table) mekanizmasını kullanarak dinamik olarak bağlanan kütüphane çağrılarını yakalar. Statik olarak derlenmiş binary’lerde çalışmaz ya da çok sınırlı çıktı verir.

Kurulum

Çoğu minimal kurulumda ltrace hazır gelmez, yüklemeniz gerekir:

# Debian/Ubuntu
sudo apt install ltrace

# RHEL/CentOS/AlmaLinux
sudo dnf install ltrace

# Arch Linux
sudo pacman -S ltrace

Kurulumdan sonra versiyon kontrolü yapın:

ltrace --version

Temel Kullanım

En basit haliyle bir komutu ltrace ile çalıştırmak:

ltrace ls /tmp

Çıktı biraz ürkütücü görünebilir ilk başta. Her satır bir kütüphane çağrısını temsil eder. Genel format şöyle: fonksiyon_adı(argümanlar) = dönüş_değeri

Çalışan bir sürece bağlanmak istiyorsanız -p parametresini kullanırsınız, tıpkı strace‘deki gibi:

ltrace -p 1234

Bu komutla PID 1234 olan süreci izlemeye başlarsınız. Ctrl+C ile izlemeyi durdurursunuz, süreç çalışmaya devam eder.

Önemli Parametreler

-p : Çalışan bir sürece attach olur.

-c: Çağrı sayısını ve harcanan zamanı özetler, her çağrıyı tek tek göstermez. Performans analizi için çok kullanışlı.

-e : Sadece belirli fonksiyonları izler. malloc,free gibi virgülle ayırarak birden fazla belirtebilirsiniz.

-l : Sadece belirli bir kütüphaneden gelen çağrıları filtreler.

-o : Çıktıyı bir dosyaya yazar.

-t: Her satıra zaman damgası ekler (saat:dakika:saniye formatında).

-tt: Mikrosaniye hassasiyetinde zaman damgası.

-T: Her çağrının ne kadar sürdüğünü gösterir. gibi.

-n : Çıktıyı girintili gösterir, iç içe çağrıları daha okunaklı yapar.

-f: Fork edilen alt süreçleri de takip eder.

-s : String argümanlar için maksimum karakter sayısını belirler. Varsayılan 32’dir, uzun stringleri kesmek istemiyorsanız artırın.

-S: Kütüphane çağrılarına ek olarak sistem çağrılarını da gösterir. strace ve ltrace‘i aynı anda kullanmak gibi düşünebilirsiniz.

Gerçek Dünya Senaryosu 1: Bellek Sızıntısı Şüphesi

Bir uygulama zamanla giderek daha fazla bellek yiyor ama neden olduğunu bilmiyorsunuz. malloc ve free çağrılarını saymak ilk ipucunu verebilir:

ltrace -e malloc,free,realloc,calloc -c ./uygulama

-c parametresi özet çıktı verir. Eğer malloc çağrı sayısı free çağrı sayısından çok fazlaysa, ortada bir bellek sızıntısı var demektir. Bu, Valgrind ile derinlemesine inceleme yapmanız gerektiğinin sinyalini verir. ltrace burada hızlı bir ön teşhis aracı olarak devreye giriyor.

Daha ayrıntılı izlemek için:

ltrace -e malloc,free -t -s 64 ./uygulama 2>&1 | grep -E "malloc|free" | head -50

Her malloc çağrısının ne kadar bayt ayırdığını ve free‘nin hangi adresi serbest bıraktığını görebilirsiniz.

Gerçek Dünya Senaryosu 2: Konfigürasyon Dosyası Neden Okunmuyor?

Bir daemon başlatıyorsunuz, konfigürasyon dosyasını doğru yere koydunuz ama uygulama sanki görmüyormuş gibi davranıyor. strace ile de bakabilirsiniz ama bazen uygulama kütüphane fonksiyonları aracılığıyla dosyaya erişiyor ve kütüphane içinde bir önbellekleme mekanizması var. ltrace ile fopen, open, getenv gibi çağrılara bakabilirsiniz:

ltrace -e fopen,fopen64,open,getenv,setenv ./daemon --config /etc/daemon/conf.yaml

Çıktıda hangi path’lere fopen yapıldığını göreceksiniz. Belki uygulama /etc/daemon/conf.yaml yerine /etc/daemon/daemon.conf arıyordur, belki $HOME/.config/daemon/ dizininde arıyordur. Bu çağrıları görmeden tahmin yürütmek zaman kaybıdır.

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

Bir servis geç yanıt veriyour. Her istek normalde 10ms sürmeli ama bazen 2-3 saniyeye çıkıyor. -T parametresiyle hangi çağrıların uzun sürdüğünü tespit edebilirsiniz:

ltrace -T -tt -p $(pgrep servis_adi) 2>&1 | awk -F'[<>]' '$2 > 0.1 {print}' 

Bu komut, 100ms’den uzun süren tüm kütüphane çağrılarını filtreler. Belki getaddrinfo çağrısı DNS resolving için bekliyor, belki bir mutex bekliyor ya da gethostbyname timeout’a giriyor. Bunu görmeden log’lara bakmak, ormanda iğne aramaya benziyor.

Gerçek Dünya Senaryosu 4: Kriptografik Kütüphane Debug

OpenSSL kullanan bir uygulama TLS bağlantısı kuramıyor. Hangi cipher suite’leri denediğini, hangi sertifika dosyalarını açmaya çalıştığını görmek istiyorsunuz:

ltrace -e SSL_CTX_new,SSL_new,SSL_connect,SSL_read,SSL_write,X509_load_cert_file 
       -s 128 ./uygulama 2>&1

OpenSSL fonksiyon çağrılarını bu şekilde filtreleyerek TLS el sıkışma sürecini takip edebilirsiniz. Özellikle sertifika yolu sorunlarında hangi dosyanın açılmaya çalışıldığını görmek çok değerli.

Çıktıyı Dosyaya Yazma ve Analiz

Uzun süren izlemelerde terminale bakmak yerine dosyaya yazmak ve sonra analiz etmek daha pratik:

ltrace -o /tmp/ltrace_output.log -tt -T ./uygulama

Sonra bu dosyayı analiz etmek için:

# En çok çağrılan fonksiyonlar
awk '{print $2}' /tmp/ltrace_output.log | cut -d'(' -f1 | sort | uniq -c | sort -rn | head -20

# En uzun süren çağrılar
grep -oP '<K[0-9.]+(?=>)' /tmp/ltrace_output.log | sort -rn | head -10

Özet istatistik almak için -c en hızlı yoldur:

ltrace -c ./uygulama

Bu komut şuna benzer bir çıktı verir:

% time     seconds  usecs/call     calls      function
------ ----------- ----------- --------- --------------------
 45.23    0.023451         234       100 malloc
 23.11    0.011987          45       265 strlen
 15.67    0.008123        8123         1 gethostbyname
  ...

gethostbyname çağrısının 8 saniye aldığını bu özetten hemen anlayabilirsiniz. DNS problemi açık.

Belirli Kütüphaneye Odaklanma

Bazen sorunun belirli bir kütüphaneden kaynaklandığını biliyorsunuzdur. -l parametresiyle sadece o kütüphanenin çağrılarını izleyebilirsiniz:

# Sadece libpthread çağrıları
ltrace -l libpthread.so.0 -p $(pgrep uygulama)

# Sadece libssl çağrıları
ltrace -l libssl.so* ./uygulama

Bu, çıktıyı önemli ölçüde azaltır ve işin içinden çıkmanızı kolaylaştırır.

Child Process’leri Takip Etmek

Fork eden bir uygulama izliyorsanız, parent process’te değil child’da bir sorun olabilir. -f ile tüm alt süreçleri de izleyebilirsiniz:

ltrace -f -o /tmp/all_traces.log ./ana_uygulama

Çıktıda her satırın başında PID numarası görünür, hangi sürecin ne yaptığını ayırt edebilirsiniz. Çok process’li uygulamalarda bu çıktı hızla kaotik bir hal alabilir, bu yüzden -e ile filtreleme yapmak akıllıca olur.

ltrace ve strace Birlikte Kullanımı

Gerçek hayatta sorunlar katmanlıdır. Hem kütüphane hem sistem çağrısı seviyesinde neler olduğunu aynı anda görmek istiyorsanız, ltrace‘in -S parametresini kullanın:

ltrace -S -e malloc,free ./uygulama 2>&1 | head -100

Bu çıktıda kütüphane çağrıları normal şekilde, sistem çağrıları ise SYS_ öneki ile gösterilir. malloc çağrısının arkasında SYS_mmap ya da SYS_brk olduğunu bu şekilde doğrulayabilirsiniz.

Pratik İpuçları ve Dikkat Edilmesi Gerekenler

String uzunluğu sorunu: ltrace varsayılan olarak stringleri 32 karakterde keser. Dosya yolu ya da URL gibi uzun değerleri görmek istiyorsanız -s parametresini artırın:

ltrace -s 256 -e fopen,popen ./uygulama

Üretim ortamında dikkat: ltrace izlediği süreci yavaşlatır. Ptrace mekanizmasını kullandığı için her fonksiyon çağrısında bir interrupt oluşur. Yüksek trafikli üretim sistemlerinde kullanmaktan kaçının ya da çok kısa süre tutun. Test ortamında veya düşük yük anında kullanmak daha güvenli.

Statik binary’ler çalışmaz: Eğer uygulama statik derlenmiş bir binary ise, ltrace anlamlı çıktı vermez. Bunu kontrol etmek için:

file /usr/bin/uygulama
ldd /usr/bin/uygulama

ldd çıktısında “not a dynamic executable” yazıyorsa, ltrace yerine strace kullanmanız gerekir.

Go uygulamaları: Go, kendi runtime’ını statik olarak derler ve libc’yi çok az kullanır. Go uygulamalarında ltrace genellikle işe yaramaz. strace daha anlamlı sonuçlar verir ya da Go’nun kendi profiling araçlarına başvurmanız gerekir.

Permission sorunları: Root olmayan kullanıcı olarak başka bir kullanıcının sürecine attach olamazsınız. Bunun için ya root olmanız ya da ptrace_scope ayarını değiştirmeniz gerekir:

# Geçici olarak (reboot'ta sıfırlanır)
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

Üretimde bunu kalıcı olarak açık bırakmak güvenlik açığı oluşturur, dikkat edin.

Gerçek Bir Debug Hikayesi

Birkaç yıl önce bir müşteride Java tabanlı değil, C ile yazılmış eski bir ERP bileşeni vardı. Belirli saatlerde CPU spike atıyor, sonra normale dönüyordu. Loglar hiçbir şey söylemiyordu. top ile PID’i aldık, ltrace -c -p ile 60 saniyelik bir pencerede izledik. Çıktı ilginçti: crypt fonksiyonu toplam sürenin yüzde kırk üçünü yiyordu ve binlerce kez çağrılıyordu.

Uygulamanın kaynak koduna bakıldığında, her kayıt okuma işleminde bir hash doğrulaması yaptığı ve bunu her defasında yeniden hesapladığı ortaya çıktı. Basit bir önbellekleme ile sorun çözüldü. ltrace olmasaydı muhtemelen saatlerce yanlış yerlere bakardık. Belki de bir donanım sorunu olduğunu düşünüp gereksiz yere disk değiştirirdik.

ltrace Alternatiflerine Kısa Bir Bakış

ltrace her durumda yeterli olmayabilir. Alternatif ya da tamamlayıcı araçlar:

  • strace: Sistem çağrısı seviyesinde izleme, ltrace ile tamamlayıcı kullanım
  • perf: Düşük overhead ile CPU profiling, üretim ortamı için daha uygun
  • eBPF/bpftrace: Kernel seviyesinde modern izleme, çok güçlü ama öğrenme eğrisi dik
  • Valgrind: Bellek sorunları için daha detaylı analiz, çok yavaşlatır
  • ldd: Hangi kütüphanelerin kullanıldığını görmek için hızlı kontrol
  • nm ve objdump: Binary içindeki semboller ve import tablosuna bakmak için

Sonuç

ltrace, sysadmin ve DevOps araç kutusunda nadir kullanılan ama ihtiyaç duyulduğunda alternatifi olmayan bir araç. Özellikle üçüncü parti uygulamaların kaynak kodu elinizde yokken, uygulama ile kütüphaneler arasındaki etkileşimi anlamak için biçilmiş kaftan.

Kullanım alışkanlığı edinmek için şunu tavsiye ederim: Önce -c ile özet bakın, hangi fonksiyon öne çıkıyor. Sonra o fonksiyona -e ile odaklanın ve -T ile süre bilgisini ekleyin. Gerekirse -s ile string limitini artırın. Bu döngü, çoğu sorunu makul sürede tespit etmenizi sağlar.

strace biliyorsanız ltrace öğrenmek çok az zaman alır. Ama iki aracı birlikte kullanabilmek, sistem davranışını hem kullanıcı alanında hem kernel’da anlayabilmek, debug süreçlerinizi bambaşka bir seviyeye taşıyor. Bir dahaki sefere “bu uygulama neden böyle davranıyor” diye sorduğunuzda, cevabı ltrace çıktısında bulma ihtimaliniz oldukça yüksek.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir