strace i ltrace — diagnostyka procesów na serwerze Linux
Opublikowano: 10 kwietnia 2026 · Kategoria: VPS
Aplikacja odmawia startu bez żadnego komunikatu o błędzie. Daemon zawiesza się co kilka
godzin. Serwis web zwraca 500 ale logi milczą. W takich sytuacjach strace i ltrace
pozwalają dosłownie podsłuchać co proces rozmawia z jądrem i bibliotekami — bez dostępu do kodu
źródłowego, bez debuggera, bez rekompilacji. Ten artykuł pokazuje jak efektywnie korzystać z tych
narzędzi na serwerach produkcyjnych i deweloperskich.
Instalacja i podstawowe użycie strace
# Ubuntu/Debian sudo apt install strace ltrace -y # Uruchom program ze śledzeniem od startu strace ls /etc # Dołącz do działającego procesu (PID) strace -p $(pgrep nginx | head -1) # Śledź z zapisem do pliku (nie blokuje terminala) strace -p 1234 -o /tmp/nginx-trace.log # Pokaż tylko błędy (wywołania zwracające -1) strace -p 1234 2>&1 | grep -i "ENOENT\|EACCES\|EPERM"
Filtrowanie wywołań — flaga -e
Surowe wyjście strace jest ogromne i trudne do analizy. Flaga -e pozwala filtrować
tylko interesujące nas kategorie syscalli. Najczęściej używane filtry:
# Tylko operacje na plikach (open, read, write, close, stat) strace -e trace=file python3 app.py # Tylko połączenia sieciowe strace -e trace=network curl https://example.com # Procesy i sygnały strace -e trace=process,signal nginx -t # Zarządzanie pamięcią (mmap, brk, mprotect) strace -e trace=memory ./myapp # Konkretne syscalle po nazwie strace -e trace=openat,read,write,close,connect ls /proc # Wszystko POZA określonymi (odejmowanie) strace -e trace=!futex,epoll_wait ./myapp
Timing i statystyki — flagi -T i -c
Flaga -T pokazuje czas spędzony w każdym wywołaniu — nieoceniona przy diagnozowaniu
wolnych operacji I/O. Flaga -c generuje podsumowanie statystyk po zakończeniu procesu.
# Czas każdego wywołania w nawiasach kwadratowych
strace -T -e trace=file php artisan migrate
# openat("config/database.php", ...) = 3 <0.000234>
# read(3, "...", 4096) = 512 <0.000018>
# Podsumowanie statystyk (-c) — kto zjada czas?
strace -c python3 -c "import numpy"
# % time seconds usecs/call calls errors syscall
# ------- --------- ----------- ------- ------- --------
# 45.32 0.234512 1234 190 mmap
# 23.18 0.119872 234 512 12 openat
# 15.44 0.079821 45 1782 read
# ...
# Połącz -T i zapis do pliku — do późniejszej analizy
strace -T -o /tmp/trace-$(date +%s).log -p $(pgrep php-fpm | head -1) Śledzenie procesów potomnych — flaga -f
Wiele serwerów (Nginx, PHP-FPM, Apache) działa jako master + worker processes. Flaga
-f (follow forks) śledzi cały drzewo procesów — niezbędna przy debugowaniu problemów
w workerach. Flaga -ff zapisuje każdy proces do osobnego pliku.
# Śledź master + wszystkie forki strace -f nginx -g "daemon off;" # Każdy PID do osobnego pliku (php-fpm.log.1234, php-fpm.log.5678...) strace -ff -o /tmp/php-fpm.log -p $(pgrep -x php-fpm8.2 | head -1) # Potem analizuj każdy worker osobno ls /tmp/php-fpm.log.* strace -e trace=file /tmp/php-fpm.log.5678 | grep ENOENT
Debugowanie "hung" procesów — co blokuje aplikację?
Gdy proces jest zawieszony (100% CPU lub 0% CPU bez postępu), strace natychmiast pokazuje na czym czeka. Typowe przyczyny:
# Dołącz do zawieszonego procesu
strace -p <PID>
# Typowe wyniki i ich znaczenie:
# futex(0x7f..., FUTEX_WAIT, ...) = ? ERESTARTSYS
# → czeka na mutex/lock — może deadlock lub wolna synchronizacja
# select(5, [3 4], NULL, NULL, NULL) = ? ERESTARTNOHAND
# → czeka na dane z pliku/socketu — może połączenie do DB wisi
# epoll_wait(4, ..., 128, -1) = ?
# → event loop czeka na zdarzenia — normalny stan idle dla Nginx/Node
# nanosleep({tv_sec=60, tv_nsec=0}, ...)
# → śpi — może zawieszony w pętli retry z za długim sleep
# read(5, ...) blocking on socket
# → czeka na odpowiedź z DB lub upstream — timeout problem?
# Sprawdź otwarte deskryptory plików
ls -la /proc/<PID>/fd
# Sprawdź połączenia sieciowe procesu
ss -tulpn | grep <PID> ltrace — śledzenie wywołań bibliotek
ltrace działa na wyższym poziomie niż strace — pokazuje wywołania funkcji z bibliotek współdzielonych. Przydatne gdy problem leży w logice biblioteki, nie w systemie.
# Podstawowe użycie ltrace
ltrace ls /etc
# Śledź tylko wybrane funkcje (wyrażenie regularne)
ltrace -e malloc,free,realloc ./myapp
# Śledź wywołania libssl
ltrace -l libssl.so.3 curl https://example.com
# Czas wywołania biblioteki
ltrace -T ./myapp 2>&1 | head -50
# Statystyki wywołań bibliotek
ltrace -c ./myapp
# Przykładowy output:
# malloc(4096) = 0x55a1b2c3d000
# fopen("/etc/hosts", "r") = 0x55a1b2c3e020
# fgets(0x55a1b2c3e0a0, 256, 0x55a1b2...) = "127.0.0.1 localhost\n"
# strcmp("example.com", "localhost") = 1
# fclose(0x55a1b2c3e020) = 0 Porównanie narzędzi diagnostycznych
| Narzędzie | Poziom | Narzut wydajnościowy | Najlepsze do |
|---|---|---|---|
| strace | Syscalls (kernel) | Wysoki (5-100x) | Debugowanie dev/test, brakujące pliki, uprawnienia |
| ltrace | Library calls (user) | Wysoki (3-50x) | Analiza zachowania bibliotek, malloc/free, libssl |
| perf trace | Syscalls (eBPF) | Niski (1-5%) | Krótkie sesje na produkcji, statystyki syscall |
| bpftrace | Kernel+user (eBPF) | Minimalny (<1%) | Produkcja, własne skrypty, tracing bez restartu |
| gdb | Source-level debugger | Bardzo wysoki | Crash analysis, core dumps, step debugging |
| SystemTap | Kernel probes | Niski | Zaawansowane kernel instrumentation |
Praktyczne przepisy diagnostyczne
# 1. Znajdź jakie pliki otwiera program (szukaj ENOENT)
strace -e trace=openat 2>&1 myapp | grep -E "ENOENT|No such file"
# 2. Debuguj błąd "Permission denied" — co jest blokowane?
strace -e trace=file,network 2>&1 myapp | grep EACCES
# 3. Sprawdź z jakim serwerem DNS łączy się aplikacja
strace -e trace=network -p <PID> 2>&1 | grep -A2 "connect"
# 4. Monitoruj nowe procesy tworzone przez daemon
strace -f -e trace=clone,fork,execve -p <PID> 2>&1
# 5. Znajdź "busy loop" — co zjada CPU?
strace -c -p <PID> &
sleep 5
kill %1
# Sprawdź która syscall ma najwięcej calls
# 6. Debuguj wolne uruchamianie PHP
strace -T -e trace=openat,stat php -v 2>&1 | \
awk '{if($NF ~ /^<[0-9]/) print}' | sort -t'<' -k2 -rn | head -20