"App khởi động rồi chết ngay, log không in gì cả." "Nó nói 'không tìm thấy file' nhưng file nào?" "Chương trình treo, chẳng biết nó kẹt ở đâu." Những tình huống này khiến việc debug tưởng như đoán mò — trừ khi bạn dùng một công cụ cho thấy chính xác chương trình đang làm gì ở mức thấp nhất: strace. Mọi việc "thật" một chương trình làm — đọc file, gửi mạng, cấp bộ nhớ — cuối cùng đều là một system call (lời gọi hệ thống) tới kernel. strace chen vào giữa và ghi lại từng cái. Bài này (phần 1 loạt "Debug và hiệu năng Linux") chạy thật để thấy strace biến hộp đen thành trong suốt.
Mọi việc thật đều là syscall
Chương trình của bạn không tự đọc đĩa hay gửi gói mạng — nó nhờ kernel làm qua syscall: openat (mở file), read/write (đọc/ghi), connect (kết nối mạng), mmap (cấp bộ nhớ)... strace bám vào tiến trình và in mỗi syscall cùng tham số và kết quả trả về.
strace cat data.txt
# openat(AT_FDCWD, "data.txt", O_RDONLY) = 3 <- mở file, được fd 3
# read(3, "noi dung file\n", 131072) = 14 <- đọc 14 byte
# write(1, "noi dung file\n", 14) = 14 <- ghi 14 byte ra stdout (fd 1)
Chỉ ba dòng đã kể toàn bộ câu chuyện: cat mở data.txt thành fd 3, đọc 14 byte, ghi 14 byte ra stdout (fd 1). Bạn thấy đúng file nó mở, đúng số byte, không phải suy đoán.

Hình 1: Mọi thao tác thật là syscall; strace ghi lại từng cái cùng kết quả. Bắt lỗi qua mã trả về (ENOENT, EACCES), lọc bằng -e trace=, gắn vào tiến trình đang chạy bằng -p, tóm tắt bằng -c.
Đo thật: bắt lỗi mà log giấu

Hình 2: Chạy thật — strace cat phơi bày openat→fd 3, read=14, write=14; mở file thiếu cho -1 ENOENT (No such file); -e trace=network chỉ hiện socket/connect; -c tóm tắt tổng 43 syscall.
- Bắt file thiếu: một app cố đọc
/etc/config-khong-ton-tai. Log app có thể im lặng, nhưng strace cho:openat(..., "/etc/config-khong-ton-tai", O_RDONLY) = -1 ENOENT (No such file or directory). Bạn biết chính xác đường dẫn nó tìm và vì sao thất bại. Kết quả-1 EACCESthì là thiếu quyền,-1 ENOENTlà không có file — hai lỗi khác nhau mà strace phân biệt rõ. - Lọc theo nhóm:
strace -e trace=networkchỉ hiện syscall mạng (socket,connect) — thấy app thử kết nối tới đâu và thành/bại. Trong demo, nó thử socket/var/run/nscd/socket(cache DNS) và nhậnENOENT. - Gắn vào tiến trình đang chạy:
strace -p <PID>bám vào một tiến trình đã chạy mà không cần khởi động lại — vô giá khi debug một service đang treo trên production (thấy nó kẹt ở syscall nào). - Tóm tắt:
strace -ckhông in từng dòng mà đếm — tổng 43 syscall cho lệnhcat. Đây là nền cho việc tìm nghẽn hiệu năng (bài sau).
Đánh đổi cần cân nhắc
strace làm chương trình chậm đi đáng kể — không dùng trên hot path production. Mỗi syscall bị dừng lại để ghi, nên một chương trình strace có thể chậm hàng chục lần. Dùng nó để chẩn đoán trên một lần chạy hoặc thời gian ngắn (timeout, -p rồi tách sớm), đừng để nó chạy dài trên service đang phục vụ tải. Với môi trường production nhạy cảm, cân nhắc các công cụ eBPF nhẹ hơn (bpftrace) chỉ lấy mẫu.
Output rất dài — luôn lọc. Một chương trình thực tế gọi hàng nghìn syscall (nạp thư viện, mmap...). In hết là ngập màn hình. Dùng -e trace= để lọc nhóm quan tâm (file, network, openat), -o file để ghi ra file rồi grep, hoặc -c để xem tổng quan trước khi soi chi tiết. Phần lớn "nhiễu" đầu output là nạp libc và động — thứ bạn cần thường nằm sau đó.
strace cho thấy cái gì, không cho thấy tại sao trong code. Nó là công cụ ranh giới kernel: thấy app mở file X và thất bại, nhưng không thấy dòng code nào gọi. Với lỗi logic trong chương trình của bạn, debugger (gdb/dlv) hoặc log ứng dụng hợp hơn. strace toả sáng khi vấn đề nằm ở tương tác với hệ thống (file, mạng, quyền) hoặc khi bạn không có mã nguồn (debug một binary lạ).
Ba ý mang về
- strace phơi bày mọi syscall chương trình gọi: đo thật
strace catcho thấyopenat→fd,read=14 byte,write=14 byte — bạn thấy chính xác file nào được mở, bao nhiêu byte, ghi đi đâu, thay vì đoán. - Bắt lỗi mà log giấu qua mã trả về: đo thật
openatfile thiếu →-1 ENOENT; strace phân biệtENOENT(không có file) vớiEACCES(thiếu quyền), và-e trace=networkthấy app kết nối tới đâu. - Dùng đúng chỗ:
-pgắn vào tiến trình đang treo,-ctóm tắt để tìm nghẽn — nhưng strace làm chậm chương trình nên chỉ để chẩn đoán ngắn, và nó cho biết cái gì ở ranh giới kernel chứ không phải dòng code nào.
Nguồn
- man7.org — strace(1): https://man7.org/linux/man-pages/man1/strace.1.html
- strace.io — trang chính thức: https://strace.io/
- man7.org — syscalls(2): https://man7.org/linux/man-pages/man2/syscalls.2.html
Phần sau ta dùng strace để đo hiệu năng: -c đếm và -T đo thời gian mỗi syscall, tìm chính xác lời gọi nào khiến chương trình chậm — I/O, mạng, hay chờ khoá.