strace

strace shows you every system call a process makes — every file it opens, every network connection, every memory allocation request. It's the first tool to reach for when a program fails mysteriously, is unexpectedly slow, or you want to understand what it actually does at the OS level.

Basic Usage

# Trace a command from start: strace ls /tmp # execve("/usr/bin/ls", ["ls", "/tmp"], envp) = 0 # brk(NULL) = 0x55c... (heap start) # openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 # mmap(NULL, 12345, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f... # close(3) = 0 # openat(AT_FDCWD, "/tmp", O_RDONLY|O_DIRECTORY) = 3 # getdents64(3, /* 5 entries */, 32768) = 168 # write(1, "file1.txt file2.log\n", 21) = 21 # exit_group(0) = ? # Attach to running process: strace -p PID # Trace with timestamps: strace -t ls # clock time strace -T ls # time spent in each syscall # Count syscalls (summary, not each call): strace -c ls # % time seconds usecs/call calls syscall # 45.00 0.000450 90 5 read # 30.00 0.000300 60 5 openat # ...

Useful Flags

# Follow child processes (fork/exec): strace -f nginx # Filter to specific syscalls: strace -e trace=open,read,write ls # Filter by category: strace -e trace=file ls # all file-related syscalls strace -e trace=network curl # network syscalls only strace -e trace=process bash # process management # Output to file (useful for long traces): strace -o /tmp/trace.txt myapp # Trace forked children to separate files: strace -ff -o /tmp/trace myapp # Creates: /tmp/trace.PID1, /tmp/trace.PID2, etc. # Combine: full trace with timestamps, children, to file: strace -ff -tt -o /tmp/trace myapp

Diagnosing Slowness

How do you find which syscall is making a program slow? Use -T to show time spent in each call, combined with -e to filter relevant categories. Sort the output to find the slowest calls. A program spending 2 seconds in read() on a network socket is waiting for data. One spending 2 seconds in stat() is doing excessive filesystem metadata lookups.
# Find slow syscalls — sort by time spent: strace -T myapp 2>&1 | grep " <" | sort -t'<' -k2 -n | tail -20 # write(1, "...", 1024) = 1024 <0.000010> # read(3, "...", 4096) = 4096 <2.034567> ← 2 seconds in read! # Profile just disk I/O: strace -T -e trace=read,write,pread64,pwrite64 myapp 2>&1 | \ awk '/ <[0-9]/ {match($0, /<([0-9.]+)>/, a); sum+=a[1]} END {print sum}' # Find "open" calls that fail (ENOENT = file not found): strace -e trace=openat myapp 2>&1 | grep ENOENT # openat(AT_FDCWD, "/etc/myapp.conf", O_RDONLY) = -1 ENOENT (No such file) # openat(AT_FDCWD, "/usr/local/etc/myapp.conf", O_RDONLY) = -1 ENOENT # openat(AT_FDCWD, "/home/user/.myapp.conf", O_RDONLY) = 3 ← found it here

strace Overhead Warning

Is strace safe to use on production systems? strace has significant overhead — typically 5-50x slowdown. It works by injecting ptrace into the target process, which intercepts every syscall via a trap. For debugging a slow startup or diagnosing an error, it's fine. For profiling a production service under load, use perf or eBPF instead — much lower overhead. Never attach strace to a high-throughput production process without understanding the impact.