Современные приложения в Linux часто представляют собой сложные системы, взаимодействующие с ядром через сотни системных вызовов. Когда возникает проблема — от непонятного зависания до неожиданных ошибок ввода-вывода — strace становится настоящим швейцарским ножом в руках разработчика. Этот инструмент трассировки системных вызовов позволяет заглянуть под капот любого процесса, не требуя перезапуска или перекомпиляции кода.
Базовое использование: наблюдаем за системной активностью
Установка strace в Arch Linux тривиальна:
sudo pacman -S strace
Для начала исследуем простейший случай — выполнение команды ls
с трассировкой:
strace -ff -o ls_trace.log ls /nonexistent
Флаг -ff
обеспечивает запись в отдельные файлы для каждого порожденного потока, а -o
направляет вывод в указанный файл. В полученном журнале сразу видим попытку доступа к несуществующему файлу:
openat(AT_FDCWD, "/nonexistent", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
write(2, "ls: cannot access '/nonexistent'"..., 35) = 35
Здесь важно не просто увидеть ошибку, а понять последовательность вызовов: openat
пытается открыть директорию, получает ENOENT, после чего следует запись сообщения об ошибке в stderr (дескриптор 2).
Динамическая трассировка работающих процессов
Для анализа уже запущенных приложений используем флаг -p
:
sudo strace -p $(pgrep -f my_daemon) -e trace=file -o daemon_files.log
Комбинация -e trace=file
фильтрует только файловые операции, что критично для анализа проблем с конфигурационными файлами или блоками данных. В типичном сценарии отладки веб-сервера такой подход быстро выявляет попытки чтения из неправильных путей или отсутствующих TLS-сертификатов.
Расширенный анализ вызовов: за пределами базовых фильтров
Продвинутые сценарии требуют комбинации фильтров и анализа временных характеристик. Рассмотрим команду:
strace -ttT -e trace=network,process -o service_calls.log -yy my_service
Опции:
-ttT
добавляет временные метки с микросекундной точностью и длительность каждого вызова-yy
декодирует структуры sockaddr для читаемого отображения адресов- Фильтр
network
иprocess
отслеживает сетевые операции и управление процессами
В выводе наблюдаем детализацию сетевых подключений:
16:23:01.451678 socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 3 <0.000143>
16:23:01.452914 connect(3, {sa_family=AF_INET6, sin6_port=htons(443), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "2606:4700::6810:135e", &sin6_addr), sin6_scope_id=0}, 28) = -1 EINPROGRESS <0.012345>
Здесь видно не только параметры сокета, но и время, затраченное ядром на обработку каждого вызова — ключевой метрики для диагностики задержек.
Реальный кейс: диагностика блокирующих операций
Представим ситуацию: приложение периодически зависает на 30 секунд. Запускаем трассировку с фокусом на вызовах, связанных с синхронизацией:
strace -e trace=futex,epoll_wait,poll -tt -p $(pgrep -f problematic_app)
В выводе обнаруживаем повторяющийся паттерн:
17:05:23.112345 futex(0x7f8e741ef9d0, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, 0xffffffff) = 0 <30.000456>
17:05:53.112801 futex(0x7f8e741ef9d0, FUTEX_WAKE_PRIVATE, 1) = 1 <0.000012>
Явная 30-секундная блокировка на futex указывает на проблему с мьютексами в коде приложения. Далее остается исследовать соответствующий участок кода, связанный с адресом 0x7f8e741ef9d0, используя отладочную информацию (debug symbols).
Производительность и оптимизация трассировки
stce может вносить значительные накладные расходы, особенно при трассировке высоконагруженных приложений. Для минимизации влияния:
-
Избирательная фильтрация:
bashstrace -e 'trace=!mmap,mprotect,read' -o filtered.log app
Исключаем нерелевантные вызовы типа mmap
-
Статистический анализ:
bashstrace -c -S calls app
Флаг
-c
собирает сводную статистику по времени и количеству вызовов -
Буферизированный вывод:
bashstrace -ff -o buffered.log -q -b execve app
Опция
-b execve
прерывает трассировку при определенных вызовах
Для высокопроизводительных сценариев рассматривайте альтернативы вроде BPF-based инструментов (bpftrace), но помните, что strace остается незаменимым для быстрого прототипирования диагностики.
Интерпретация результатов: от сырых данных к инсайтам
Ключевые паттерны для анализа:
- Повторяющиеся EINTR: Прерывания системных вызовов сигналами могут указывать на конфликты обработчиков
- Неожиданные EACCES/EPERM: Проблемы с правами доступа, часто возникающие после обновлений SELinux/policykit
- Циклы stat/open: Признаки некорректного поиска конфигурационных файлов в нескольких путях
- Неявные зависимости через LD_PRELOAD: Вызовы dlopen в неожиданных местах
Пример диагностики TLS-ошибки:
openat(AT_FDCWD, "/etc/ssl/certs/ca-certificates.crt", O_RDONLY) = -1 ENOENT
Указывает на отсутствие цепочки сертификатов в нестандартном расположении, что характерно для контейнеров с минимальным набором пакетов.
Когда strace недостаточно
Хотя strace охватывает большинство сценариев, сложные случаи требуют комбинации инструментов:
- ltrace для отслеживания библиотечных вызовов
- gdb с командами
catch syscall
для интерактивной отладки - perf trace для низкоуровневой трассировки с минимальными накладными расходами
Для анализа взаимодействия между процессами добавляем фильтрацию по PID:
strace -e trace=all -o comms.log -s 128 -P /var/run/app.sock
Заключение: стратегия эффективной отладки
- Начинайте с широкой трассировки (
strace -f -tt -o full.log
), затем сужайте фокус через-e trace=
- Сочетайте временные метки (
-ttt
) с внешними журналами приложения для корреляции событий - Автоматизируйте анализ через awk/grep для поиска аномалий в больших логах
- Для критичных к производительности систем используйте
-y -yy
для декодирования дескрипторов и сокетов
stce не просто показывает, что происходит — он раскрывает, как приложение взаимодействует с ядром, превращая черный ящик в прозрачную систему. Главное — задавать правильные вопросы через фильтры и уметь читать между строк системных вызовов.