strace Basics - Tracing System Calls for Troubleshooting
What is strace?
strace is a debugging tool that records and displays the system calls (kernel requests) and signals issued by a process in real time. It exposes raw interactions such as opening files, establishing network connections, and forking child processes — all of which are visible even without source code.
When to use strace
- No useful log output, or error messages that reveal nothing
- Unsure which config file the application is actually reading
- "Permission denied" occurs but you don't know which path is being rejected
- Network connections fail for unclear reasons
Why does strace help with troubleshooting?
Every application, no matter how complex, accesses hardware and OS resources through kernel system calls. strace monitors that exact interface — so even without source code, you can see precisely what a process tried to do and why it failed.
Kernel-level errors such as errno: ENOENT (file not found), errno: EACCES (permission denied), and errno: ECONNREFUSED (connection refused) appear directly in strace output. Even when an app only logs "An error occurred," strace leads you to the root cause.
How do you install strace?
Most distributions include strace by default. Install it with your package manager if it is missing.
# Ubuntu / Debian sudo apt install strace # RHEL / CentOS / Fedora sudo dnf install strace
Verify the installation:
strace --version
strace -- version 6.x ...
Basic Usage
Trace a command directly
strace ls /tmp
A stream of output appears. The last few lines show the exit status.
execve("/bin/ls", ["ls", "/tmp"], 0x7fff... /* 20 vars */) = 0
brk(NULL) = 0x55d3e...
...
openat(AT_FDCWD, "/tmp", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
...
+++ exited with 0 +++
Attach to a running process
sudo strace -p PID
Find the PID with ps aux or pgrep:
# Find PID by process name pgrep nginx # Attach sudo strace -p 12345
Attaching with -p usually requires root privileges (not needed for your own processes). Attaching to a production service can affect its performance.
Trace child processes too
For multi-process services, -f is essential:
strace -f -p PID
How do you filter to specific system calls?
The default output is overwhelming. Use -e trace= to narrow the focus:
strace -e trace=openat ls /tmp
Common filters:
| Filter | Traces |
|---|---|
openat |
File opens |
read,write |
Reads and writes |
connect |
Network connections |
execve |
Process launches |
file |
All file-related calls |
network |
All network-related calls |
# Trace only file access strace -e trace=file command # Trace only network connections strace -e trace=network command
How do you read strace output?
The basic format is:
syscall_name(args...) = return_value
Success:
openat(AT_FDCWD, "/etc/hosts", O_RDONLY) = 3
Failure — ENOENT (file not found):
openat(AT_FDCWD, "/etc/myapp.conf", O_RDONLY) = -1 ENOENT (No such file or directory)
Failure — EACCES (permission denied):
openat(AT_FDCWD, "/root/secret", O_RDONLY) = -1 EACCES (Permission denied)
Reading the return value
= 0or higher: success (file descriptor number, bytes processed, etc.)= -1: failure. The errno token that follows names the specific reason.
Common Troubleshooting Patterns
Pattern 1: App not reading its config file
strace -e trace=openat myapp 2>&1 | grep "ENOENT"
openat(AT_FDCWD, "/etc/myapp/config.yaml", O_RDONLY) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/home/user/.myapp/config.yaml", O_RDONLY) = -1 ENOENT (No such file or directory)
You can see exactly which paths the application tries.
Pattern 2: Pinpointing the cause of Permission denied
strace -e trace=openat myapp 2>&1 | grep "EACCES"
openat(AT_FDCWD, "/var/run/myapp.pid", O_WRONLY|O_CREAT) = -1 EACCES (Permission denied)
The exact path being rejected becomes visible.
Pattern 3: Diagnosing a connection failure
strace -e trace=network myapp 2>&1 | grep -E "connect|ECONNREFUSED"
connect(3, {sa_family=AF_INET, sin_port=htons(5432), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ECONNREFUSED (Connection refused)
Confirm whether the address and port match your expectations.
Pattern 4: Save output for later analysis
strace -o /tmp/trace.log -f myapp grep ENOENT /tmp/trace.log
-o redirects output to a file, keeping stderr clean and making it easy to grep or less through later.
Practical Options Reference
| Option | Effect |
|---|---|
-p PID |
Attach to a running process |
-f |
Trace child processes created by fork/clone |
-e trace= |
Filter to specific system calls |
-o file |
Write output to a file instead of stderr |
-t |
Prefix each line with wall-clock time |
-tt |
Microsecond-precision timestamps |
-T |
Show time spent in each system call |
-c |
Print a summary of call counts, times, and errors |
-s 256 |
Set maximum string display length (default: 32) |
-q |
Suppress "Attaching..." messages |
Checking statistics with -c
strace -c ls /tmp
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 35.14 0.000147 14 10 mmap 18.42 0.000077 11 7 openat ... ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000418 48 2 total
Get a quick picture of which calls are consuming the most time.