Hướng dẫn sử dụng strace để debug ứng dụng trên Linux: Theo dõi System Call và tìm nguyên nhân lỗi hiệu quả

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

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

  1. 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.
  2. Lọc syscall cụ thể dựa trên kết quả bước 1 — đừng xem raw output vì quá nhiều.
  3. Dùng -tt -T khi cần xem timing chính xác — tìm khoảng thời gian dài bất thường.
  4. 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.

Share: