Khi nào bạn thật sự cần strace?
Có những buổi chiều thứ Sáu, service bỗng nhiên chết mà không log gì ra. Restart thì lên, 5 phút sau lại chết. dmesg không thấy gì, journalctl cũng im thin thít. Đó là lúc mình bắt đầu mở strace ra.
Trên con server CentOS 7 cũ của công ty, mình đã phải dùng strace khá nhiều để tìm ra nguyên nhân các vấn đề mà log level bình thường không capture được — từ file permission bị sai sau khi deploy, đến socket bị block vì ulimit, đến cả việc một binary cứ cố đọc file config ở đường dẫn cũ dù đã symlink sang chỗ mới.
strace là công cụ cho phép bạn “nghe lén” mọi system call mà một process thực hiện — tức là mọi tương tác giữa ứng dụng và kernel: mở file, đọc/ghi, kết nối mạng, tạo process con, v.v. Không cần source code, không cần recompile — attach vào PID đang chạy là xong.
Khác với việc đọc log (chỉ thấy những gì developer cho phép in ra), strace cho bạn thấy tất cả những gì process thật sự làm ở tầng kernel.
Cài đặt strace
Hầu hết distro đều có sẵn strace trong repo chính thức:
# Ubuntu / Debian
sudo apt install strace
# CentOS / RHEL / AlmaLinux
sudo yum install strace
# hoặc dnf nếu dùng bản mới hơn
sudo dnf install strace
# Arch Linux
sudo pacman -S strace
# Kiểm tra version
strace --version
Không cần cấu hình gì thêm. strace hoạt động dựa trên ptrace() syscall của kernel — miễn là bạn có quyền đủ để attach vào process (thường cần root hoặc cùng user).
Các cách dùng strace thực tế
Chạy thẳng một lệnh qua strace
Cách đơn giản nhất — strace sẽ chạy lệnh và in ra mọi syscall:
strace ls /tmp
Output sẽ nhiều kinh khủng. Thực tế bạn sẽ muốn lọc hoặc ghi ra file:
# Ghi ra file để phân tích sau
strace -o /tmp/strace_ls.log ls /tmp
# Kèm timestamp (rất hữu ích)
strace -t -o /tmp/strace_ls.log ls /tmp
# Timestamp chính xác đến microsecond
strace -tt -o /tmp/strace_ls.log ls /tmp
Attach vào process đang chạy
Đây là case thực tế nhất — service đang chạy mà bị lỗi, không thể restart:
# Tìm PID trước
pgrep -a nginx
# hoặc
ps aux | grep myapp
# Attach vào process
sudo strace -p 12345
# Attach vào tất cả thread (quan trọng với multi-thread app)
sudo strace -p 12345 -f
Flag -f (follow forks) cực kỳ quan trọng với các app đa luồng hoặc spawn child process — nếu không có -f bạn có thể miss hết syscall của các thread con.
Lọc chỉ những syscall cần thiết
Dùng -e trace= để giảm noise — đây là thứ mình hay dùng nhất:
# Chỉ xem các syscall liên quan đến file
strace -e trace=file ls /tmp
# Chỉ xem network calls
strace -p 12345 -e trace=network
# Chỉ xem open, read, write
strace -e trace=open,read,write -p 12345
# Chỉ xem các lỗi (syscall trả về -1)
strace -e trace=all -e status=failed -p 12345
Option -e status=failed là cực kỳ mạnh — chỉ hiện những syscall bị lỗi, bỏ qua tất cả những cái thành công. Dùng cái này để tìm permission error hoặc file not found cực nhanh.
Đo thời gian từng syscall
# -T: hiện thời gian mỗi syscall tốn bao lâu
strace -T -p 12345 -e trace=file
# -c: tổng hợp thống kê (rất hữu ích phân tích bottleneck)
strace -c ls /tmp
Output của -c trông như này:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
52.13 0.000423 42 10 mmap
23.41 0.000190 19 10 read
12.50 0.000102 12 8 1 openat
5.10 0.000041 5 8 fstat
...
Cột errors cho biết syscall nào đang fail. Cột % time cho biết cái gì đang chiếm CPU nhất.
Debug các vấn đề thực tế
Case 1: Ứng dụng không tìm thấy file config
Tình huống điển hình: app bị lỗi nhưng log chỉ nói chung chung “config not found”.
# Lọc syscall liên quan file, chỉ lấy lỗi
strace -e trace=openat,open -e status=failed ./myapp 2>&1 | grep ENOENT
Output sẽ chỉ thẳng những file app đang cố đọc mà không tìm thấy:
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)
Vậy là biết ngay app đang tìm config ở đâu, dù trong code không document rõ.
Case 2: Permission denied bí ẩn
strace -e trace=file -e status=failed sudo -u appuser ./myapp 2>&1 | grep EACCES
Trên server CentOS 7 của công ty mình, từng gặp trường hợp service fail với “Permission denied” nhưng ls -la thấy file permission rõ ràng là OK. Sau khi strace mới phát hiện ra là SELinux đang block — syscall trả về EACCES nhưng error message lại không mention SELinux gì cả.
Case 3: Service bị treo, không biết đang chờ gì
sudo strace -p $(pgrep myservice) -e trace=network,ipc
Nếu thấy process đang kẹt ở:
epoll_wait(5, [], 1, 30000) = 0 # chờ network, timeout 30s
# hoặc
futex(0x7f..., FUTEX_WAIT, ...) # đang chờ lock
Là biết ngay: cái đầu là đang chờ network connection (có thể backend timeout), cái sau là đang chờ mutex lock (có thể deadlock).
Case 4: Tìm bottleneck I/O
# Đo tổng hợp trong 30 giây
sudo timeout 30 strace -c -f -p $(pgrep myapp) 2>&1
Nếu thấy read hoặc write chiếm >50% time với usecs/call cao — đó là dấu hiệu I/O chậm, cần kiểm tra disk hoặc NFS mount.
Kiểm tra và monitoring với strace
Workflow debug thực tế của mình
- Chạy lần đầu với
-cđể có cái nhìn tổng quan: syscall nào gọi nhiều nhất, cái nào fail. - Lọc syscall cụ thể dựa trên kết quả bước 1 — đừng xem raw output vì quá nhiều.
- Dùng
-tt -Tkhi cần xem timing chính xác — tìm khoảng thời gian dài bất thường. - Grep theo error code:
ENOENT(file not found),EACCES(permission),ECONNREFUSED(network),ETIMEDOUT(timeout).
Một số lệnh grep hữu ích khi phân tích log strace
# Xem tất cả file đã được mở thành công
grep 'openat.*O_RDONLY' strace.log | grep -v '= -1'
# Tìm các network connection
grep 'connect(' strace.log
# Tìm write ra stderr (fd=2)
grep 'write(2,' strace.log
Lưu ý về overhead
strace dùng ptrace() — mỗi syscall phải dừng process lại để kernel report. Overhead có thể từ 2x đến 10x tùy workload. Không dùng trên production dưới tải cao — chỉ dùng khi đang debug, hoặc dùng -c thống kê tổng hợp thay vì xem real-time output.
Nếu cần tracing production mà ít overhead hơn, perf trace hoặc bpftrace là lựa chọn tốt hơn — nhưng strace vẫn là công cụ đầu tiên mình mở ra vì đơn giản và không cần chuẩn bị gì.
Tổng kết
strace không phải tool để dùng hàng ngày, nhưng khi cần debug những vấn đề mà log không giải thích được — đặc biệt là permission error, file not found, network timeout, hay deadlock — thì nó tiết kiệm rất nhiều thời gian so với việc đọc source code hoặc thêm print statement rồi redeploy.
Thứ tự ưu tiên khi debug với strace: -e status=failed trước để thấy lỗi, rồi -c để thấy bottleneck, rồi mới xem chi tiết nếu cần. Đừng xem raw output ngay từ đầu — sẽ bị overwhelm.

