Node.js 26.7.0: трассировка через Perfetto

Релиз Node.js 26.7.0 вышел 5 августа 2026 года, и в списке Notable Changes затерялась строка из трёх слов: add perfetto support (#64565). Выглядит как сноска. На деле это перестройка одной из самых старых и наименее любимых подсистем платформы — слоя трассировки.

Проблема: формат трейсов из другой эпохи

Годами встроенная трассировка в Node.js работала так:

bash
node --trace-event-categories v8,node,node.async_hooks server.js

На выходе — файл node_trace.1.log. Несмотря на расширение, внутри лежит JSON в устаревшем Trace Event Format, пришедшем из Chrome. Формат полностью текстовый, поэтому файлы разбухают под любой реальной нагрузкой, а традиционный просмотрщик chrome://tracing давно превратился в заброшенный инструмент.

Но главное уже не в удобстве. В обсуждении nodejs/diagnostics#654 было зафиксировано: V8 — источник значительной части трейс-данных, которые отдаёт Node (GC, компиляция, исполнение), — переходит исключительно на Perfetto и отказывается от старого механизма трассировки. Поскольку V8 находится в самом ядре Node.js, вариантов было два: двигаться следом или постепенно потерять самый содержательный источник данных в рантайме.

Что изменилось

В 26.7.0 появился новый бэкенд трассировки на базе Perfetto SDK, включаемый на этапе сборки:

bash
./configure --with-perfetto
make -j"$(nproc)"

Дальше всё остаётся прежним — те же флаги, те же категории:

bash
node --trace-event-categories node.perf,node.async_hooks,v8 \
     --trace-event-file-pattern '${pid}-${rotation}.pftrace' \
     server.js

Разница — в результате. Вместо JSON Node пишет protobuf-файл node_trace.1.pftrace, который открывается напрямую в ui.perfetto.dev. И это не просто таймлайн: Perfetto даёт SQL-слой поверх трейса, так что данные можно спрашивать, а не пролистывать.

Программный API тоже не тронут:

js
import { createTracing } from 'node:trace_events';

const tracing = createTracing({
  categories: ['node.perf', 'v8'],
});

tracing.enable();

// измеряемая работа
await handleRequest(req);

tracing.disable();

Это осознанное решение: замена происходит внизу, а привычная поверхность остаётся на месте. Категории тоже прежние — node.perf для измерений Performance API, node.async_hooks для асинхронных операций, node.fs.sync и node.fs.async для файловых вызовов, v8 для данных движка. Изменилось то, куда эти события попадают и в каком виде записываются, а не то, как они собираются.

Оговорки, о которых стоит сказать прямо

  • В официальных сборках не включено. --with-perfetto — опция этапа configure, то есть текущие официальные бинарники её не содержат. На практике это означает собственную сборку либо ожидание решения включить её по умолчанию.
  • JSON-вывода в этом режиме нет. Исключение сделано намеренно. Любая внутренняя тулза, которая читает node_trace.*.log и парсит его как JSON, потребует другого пути.
  • Трассировка через inspector отключается. При активном Perfetto домен NodeTracing поверх inspector выключен: протоколу здесь нужны сырые байты, а не объекты протокола.
  • Бэкпорта не будет. Изменение ограничено веткой 26.x и не попадёт в 22.x или 24.x, а 26.x — это Current, не LTS.

Вывод

Наблюдаемость продолжает переезжать из категории «прикрутили сбоку» в категорию того, чем владеет сам рантайм. Запрашиваемый protobuf-трейс — не просто формат опрятнее JSON: это данные, которые понимают инструменты, и которые понимают агенты, всё чаще участвующие в разборе проблем производительности. Разница между пролистыванием JSON-файла на несколько сотен мегабайт и SQL-запросом к тем же данным — это разница между медленным ручным чтением и структурированным расследованием.

Пока шаг остаётся опцией сборки, но направление читается однозначно: путь трассировки в Node.js пересобирают так, чтобы он говорил на одном языке с остальной инструментальной экосистемой. Кто следил за тем, что приехало в Node.js 26.6, заметит: линейка 26.x несёт структурные изменения, а не косметику.

Первоисточник: release notes Node.js 26.7.0, детали реализации — в PR #64565.