TL;DR
smapped-traces — это open-source решение для резолва source maps в OpenTelemetry трассировках, использующее debug ID вместо хрупких path-based подходов. Поддерживает Next.js 15+, работает с Turbopack и webpack, предлагает multiple storage backends (SQLite, S3, HTTP).
Введение: проблема source maps в production
Когда мы переходим с Sentry на OpenTelemetry, одна из ключевых проблем — потеря читаемости stack traces в production. Вместо понятных:
Error: Cannot read properties of undefined (reading 'id')
at DashboardComponent (./src/components/Dashboard.tsx:42:15)
Мы видим минифицированный ад:
Error: Cannot read properties of undefined (reading 'id')
at t (/_next/static/chunks/pages/dashboard-abc123.js:1:23847)
Традиционные подходы к резолву source maps через path matching хрупки и требуют:
- Точного соответствия путей
- Доступа к .map файлам в production
- Сложной инфраструктуры для хранения source maps
smapped-traces предлагает альтернативу через стандартизированные debug ID.
Как работают debug ID
Концепция основана на TC39 proposal и реализована в Turbopack нативно, для webpack требуется plugin.
Build-time:
- Каждому бандлу присваивается UUID (debug ID)
- Этот же ID записывается в соответствующий .map файл
- Создается mapping вида
{ "file.js": "debug-id" }
Runtime:
- При ошибке в коде мы получаем stack trace с путями файлов
- Специальный exporter ищет debug ID для каждого файла
- По ID загружается соответствующий source map
Архитектура smapped-traces
Решение состоит из трех ключевых компонентов:
1. Build Plugin (Next.js)
// next.config.js
const { withSmappedTraces } = require('@smapped-traces/nextjs');
module.exports = withSmappedTraces({
// Конфигурация хранилища
storage: {
type: 's3',
bucket: 'my-sourcemaps-bucket'
},
// Дополнительные опции
purgeSourceMaps: true // удаляем .map файлы из output
});
Плагин выполняет:
- Индексацию source maps по debug ID
- Удаление .map файлов из production build (опционально)
- Загрузку маппингов в выбранное хранилище
2. SourceMappedSpanExporter
import { SourceMappedSpanExporter } from 'smapped-traces';
import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base';
const exporter = new SourceMappedSpanExporter({
// Делегируем экспорт основному экспортеру
delegate: new ConsoleSpanExporter(),
// Конфигурация хранилища
storage: {
type: 'http',
endpoint: 'https://sourcemaps.internal'
}
});
Экспортер:
- Перехватывает exception events
- Резолвит stack traces через debug ID
- Применяет source maps
- Передает обогащенные данные дальше по цепочке
3. Traces Handler (для OTLP)
import { createTracesHandler } from 'smapped-traces';
export default createTracesHandler({
storage: { type: 'sqlite', path: '/data/sourcemaps.db' },
collector: {
url: 'https://otel-collector.internal'
}
});
Обработчик:
- Принимает OTLP трассировки
- Резолвит source maps
- Пересылает данные в ваш collector
Практическое применение
Интеграция с OpenTelemetry SDK
import { NodeSDK } from '@opentelemetry/sdk-node';
import { SourceMappedSpanExporter } from 'smapped-traces';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
const sdk = new NodeSDK({
traceExporter: new SourceMappedSpanExporter({
delegate: new OTLPTraceExporter(),
storage: { type: 's3' }
}),
instrumentations: [getNodeAutoInstrumentations()]
});
sdk.start();
Поддерживаемые storage backends
- SQLite (для standalone приложений):
{
type: 'sqlite',
path: '/path/to/database.db'
}
- S3-совместимые (AWS, Cloudflare R2, Google Cloud Storage):
{
type: 's3',
bucket: 'my-sourcemaps',
region: 'us-east-1'
}
- HTTP endpoint (для собственных решений):
{
type: 'http',
endpoint: 'https://sourcemaps-api.internal'
}
Кастомизация через интерфейсы
Вы можете реализовать собственное хранилище:
interface SourceMapStore {
getSourceMap(debugId: string): Promise<RawSourceMap | null>;
getDebugId(sourceUrl: string): Promise<string | null>;
}
class MyCustomStore implements SourceMapStore {
// ... ваша реализация
}
Ограничения и roadmap
- Поддержка bundlers: Turbopack (нативно), webpack (через plugin), Vite/esbuild (пока нет)
- Runtime: любой Web-совместимый (браузер, Edge, Cloudflare Workers)
- Требования: Next.js 15+, OpenTelemetry SDK v2+
Планируемые фичи:
- Поддержка Vite после реализации debug ID в их бандлере
- Интеграция с CDN для edge-резолва source maps
- Расширенная статистика по успешности резолва
Заключение
smapped-traces предлагает production-ready решение для source map резолва в OpenTelemetry, устраняя главные боли:
- Нет зависимости от путей файлов
- Не требуем доступа к .map файлам в production
- Поддерживаем multiple storage backends
- Полная интеграция с OTel ecosystem
Для проектов на Next.js с Turbopack/webpack — это наиболее надежный способ получить читаемые stack traces в production без головной боли с path mapping.
Ресурсы: