What is strace?

In the world of Linux, most operations a program performs – from opening a file, to connecting to a network, to reading the time – are done through system calls. These are special kernel functions that programs “ask” to perform low-level tasks.

strace (short for “system call trace”) is a powerful diagnostic tool that allows you to “eavesdrop” on and display all of these system calls that a given process makes in real time. This lets us see exactly what a program is doing “under the hood.”

Why is strace so useful?

strace is indispensable in situations where a program isn’t behaving as it should, and its own logs tell us nothing. It helps answer questions like:

  • Why can’t this program open a file? (Is it looking in the wrong path? Does it lack permissions?)
  • Why is this program running so slowly? (Is it constantly trying to connect to an unavailable network address?)
  • What configuration files is this process accessing?

How to use strace? Basic uses

1. Running a program with strace

The simplest way to use strace is to run any program with it. strace will display every system call made by that program.

# Let's see what the simple 'ls' command does
strace ls

The output will be very detailed, but at a glance, we’ll see calls like openat() (opening files), read() (reading), write() (writing to standard output), and close() (closing files).

2. Attaching to a running process

This is the most common and useful scenario. If you already have a running process (e.g., a web server, a database) that is causing problems, you can attach strace to it by providing its process ID (PID).

# First, find the PID of the process (e.g., an nginx server)
pidof nginx

# Let's assume the PID is 1234. We attach to it:
sudo strace -p 1234

From this moment, every system call made by the process with PID 1234 will be displayed in your terminal. To exit, press Ctrl+C.

Practical examples and useful options

Example: Program can’t find a file

Imagine a program my-program reports an error on startup “cannot open config file,” but it doesn’t say where it’s looking. Let’s use strace to find out. We’ll filter for only the file opening calls (openat).

strace -e trace=openat my-program

You’ll see something like this in the output:

openat(AT_FDCWD, "/etc/my-program.conf", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/user/.config/my-program.conf", O_RDONLY) = -1 ENOENT (No such file or directory)

Now you know exactly where the program was looking for its configuration file and why it couldn’t find it.

Other useful strace options

  • -o <file>: Writes the output to a file instead of the screen.
    sudo strace -p 1234 -o /tmp/strace.log
    
  • -f: Also traces all child processes (forks/clones). Very important when analyzing complex applications like web servers.
  • -t: Shows the execution time of each call.
  • -s <size>: Specifies the maximum length of strings to display (they are shortened by default).
  • -e trace=<set>: Filters calls to a specific set. Examples:
    • trace=file: Only file-related calls (open, read, write, close).
    • trace=network: Only network calls.
    • trace=process: Only process management calls.

Summary

strace is a powerful tool that gives you X-ray vision into the workings of any program. While its output may seem overwhelming at first, learning to filter and interpret the most important system calls is one of the most worthwhile investments in your Linux debugging skills. It’s a tool that will save you in difficult situations time and time again.