Привет, Хабр!
Процесс висит — и непонятно, что он делает. Потребляет CPU, но не пишет в лог. Или наоборот — не потребляет ничего, но и не отвечает. top показывает состояние D или S, но это мало что говорит. Логов нет, дебаггер подключать нельзя (прод), исходников нет (чужой бинарник).
Есть strace. Утилита, которая перехватывает системные вызовы процесса и показывает их в реальном времени. Процесс пытается открыть файл? Вы увидите openat(). Ждёт данные из сокета? recvfrom(). Спит? nanosleep().
Первый запуск: что происходит внутри
strace ls /tmp
Выводом получаем стену текста. Каждая строка как один системный вызов:
execve("/usr/bin/ls", ["ls", "/tmp"], 0x7fff...) = 0 brk(NULL) = 0x55a8c2d3e000 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 read(3, "\x7fELF..."..., 832) = 832 ... openat(AT_FDCWD, "/tmp", O_RDONLY|O_NONBLOCK|O_DIRECTORY) = 3 getdents64(3, /* 15 entries */, 32768) = 488 write(1, "file1.txt\nfile2.log\n...", 87) = 87 close(3) = 0 exit_group(0) = ?
Первым делом — execve (запуск). Потом загрузка динамических библиотек (openat + read для .so файлов). Потом собственно работа: открыть директорию, прочитать записи, вывести в stdout, закрыть, выйти.
Формат строки: имя_вызова(аргументы) = результат. Результат -1 — ошибка, и strace покажет код ошибки: ENOENT (файл не найден), EACCES (нет прав), ECONNREFUSED (соединение отклонено).
Подключиться к работающему процессу
# По PID strace -p 12345 # Найти PID и подключиться strace -p $(pidof nginx)
Не нужно перезапускать процесс и не нужен дебаггер. Подключились к проду, посмотрели что происходит, отключились. Для отключения — Ctrl+C, процесс продолжит работать.
Фильтрация
По умолчанию strace показывает всё. Для типичного процесса сотни вызовов в секунду. Есть фильтры:
# Только файловые операции strace -e trace=file -p 12345 # openat, stat, access, unlink, rename... # Только сетевые strace -e trace=network -p 12345 # socket, connect, bind, listen, accept, send, recv... # Только чтение/запись strace -e trace=read,write -p 12345 # Конкретные вызовы strace -e trace=openat,connect -p 12345
Категории: file (файловый ввод-вывод), network (сеть), process (fork, exec, exit), signal (сигналы), memory (mmap, brk), ipc (межпроцессное взаимодействие).
Кейс: «приложение не стартует»
Сервис не запускается. В логах пусто. Systemd говорит exit code 1.
strace -f -e trace=file ./myapp 2>&1 | grep -i "no such\|permission"
openat(AT_FDCWD, "/etc/myapp/config.yaml", O_RDONLY) = -1 ENOENT (No such file or directory)
Готово. Приложение ищет конфиг по пути /etc/myapp/config.yaml, файла нет. Без strace можно было бы часами гадать.
Ещё вариант — проблемы с правами:
openat(AT_FDCWD, "/var/lib/myapp/data.db", O_RDWR) = -1 EACCES (Permission denied)
Или динамическая библиотека не найдена:
openat(AT_FDCWD, "/usr/lib/libcustom.so", O_RDONLY) = -1 ENOENT
Кейс: «приложение тормозит»
Сервер отвечает медленно. CPU не загружен. Диск не загружен. Что-то ждёт.
strace -T -p 12345
Флаг -T добавляет время выполнения каждого вызова:
recvfrom(5, "HTTP/1.1 200 OK\r\n...", 8192, 0, NULL, NULL) = 347 <2.103452> write(1, "Processing response...\n", 23) = 23 <0.000041> connect(6, {sa_family=AF_INET, sin_addr=10.0.0.50, sin_port=3306}, 16) = 0 <0.503221>
<2.103452> — два секунды на получение HTTP-ответа. <0.503221> — полсекунды на коннект к MySQL. Узкое место найдено.
Или посчитать суммарно:
strace -c -p 12345 # Ctrl+C через 10 секунд # % time seconds usecs/call calls errors syscall # ------ ----------- ----------- --------- --------- ---------------- # 89.12 4.523100 150770 30 poll # 5.23 0.265400 8846 30 recvfrom # 3.01 0.152800 5093 30 sendto # ...
-c — статистика. 89% времени процесс проводит в poll — ждёт данных. Не CPU-bound, а I/O-bound. Смотрите, кого он ждёт.
Кейс: «куда пишет логи?»
Достался чужой бинарник. Документации нет. Куда он пишет?
strace -e trace=write,openat -p 12345 2>&1 | grep -E "open.*O_WRONLY|open.*O_RDWR|write\("
openat(AT_FDCWD, "/var/log/mystery/app.log", O_WRONLY|O_APPEND|O_CREAT, 0644) = 4 write(4, "2026-03-23 10:15:02 INFO Start...", 52) = 52
Файловый дескриптор 4 — это /var/log/mystery/app.log. Теперь знаете.
Кейс: «DNS-резолвинг тормозит»
Приложение медленно подключается к внешним сервисам. Подозрение на DNS.
strace -e trace=network -T -p 12345 2>&1 | grep connect
connect(3, {sa_family=AF_INET, sin_addr=8.8.8.8, sin_port=53}, 16) = 0 <0.000045> ... recvfrom(3, ...) = 52 <3.001234>
Три секунды на ответ от DNS-сервера. Проблема не в приложении — DNS тормозит.
Многопоточные приложения: -f
По умолчанию strace трассирует только основной поток. Для многопоточных приложений:
strace -f -p 12345
-f — следить за всеми потоками и дочерними процессами. Каждая строка будет префиксирована PID:
[pid 12345] poll([{fd=5, events=POLLIN}], 1, 5000) = 1 [pid 12346] read(7, "data...", 4096) = 128 [pid 12347] write(3, "log entry\n", 10) = 10
Вывод в файл
Для анализа позже:
# Всё в файл strace -o trace.log -f -T -p 12345 # Каждый поток/процесс в отдельный файл strace -ff -o trace -p 12345 # Создаст trace.12345, trace.12346, trace.12347...
-ff с -o — по файлу на каждый PID. Удобно для многопоточных: каждый поток — свой файл, нет перемешивания.
Строки: больше контекста
По умолчанию strace обрезает строки до 32 символов. Для отладки часто мало:
# Показывать до 1024 символов в строковых аргументах strace -s 1024 -p 12345 # Показывать пути полностью strace -y -p 12345 # write(4</var/log/app.log>, "data", 4) = 4
-y — рядом с файловым дескриптором показывает путь. Не нужно вручную сопоставлять fd 4 с файлом.
Timestamps
# Абсолютное время strace -t -p 12345 # 10:15:02 openat(...) = 3 # С микросекундами strace -tt -p 12345 # 10:15:02.345678 openat(...) = 3 # Относительное (от предыдущего вызова) strace -r -p 12345 # 0.000123 openat(...) = 3 # 2.103456 read(...) = 128 ← 2 секунды между вызовами
-r — самый полезный для поиска задержек. Видите большое число — между этими двумя вызовами процесс ждал.
Краткая шпаргалка
strace -p PID # Подключиться к процессу strace -f -p PID # + потоки и дочерние strace -e trace=file # Только файловые операции strace -e trace=network # Только сетевые strace -T # Время каждого вызова strace -c # Статистика по вызовам strace -r # Время между вызовами strace -y # Показать пути для fd strace -s 1024 # Длинные строки strace -o file.log # В файл
Десять флагов, c ними вы точно покроете 95% случаев.

Если в какой-то момент вам стало тесно на уровне «посмотреть вывод утилиты и починить симптом», значит дальше уже нужен разбор того, как система устроена изнутри. На курсе по разработке ядра Linux как раз идут в эту глубину: архитектура ядра, модули, память, прерывания, синхронизация и отладка — то есть те вещи, которые помогают не просто диагностировать поведение системы, а понимать его причины.
Немного практики в тему — пройдите вступительный тест и узнаете, есть ли пробелы в знаниях. ➦ Пройти тест.
А чтобы узнать больше о формате обучения и задать вопросы экспертам, приходите на бесплатные уроки:
9 апреля в 20:00. «Платформенные драйверы. Как управлять периферией систем на кристалле». Записаться
21 апреля в 20:00. «Связанные списки в ядре Linux: от базовых средств до реального кода». Записаться
