Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c07e1ef
feat(core): Add span v2 and envelope type definitions (#19100)
Lms24 Feb 2, 2026
7bee95d
feat(core): Add `traceLifecycle` option and `beforeSendSpan` compatib…
Lms24 Feb 4, 2026
106f651
feat(core): Add `StreamedSpanEnvelope` creation function (#19153)
Lms24 Feb 4, 2026
6ad9e01
feat(core): Add span serialization utilities (#19140)
Lms24 Feb 4, 2026
21fadd4
feat(core): Add `captureSpan` pipeline and helpers (#19197)
Lms24 Feb 6, 2026
a958488
feat(core): Add `SpanBuffer` implementation (#19204)
Lms24 Feb 9, 2026
eba6140
feat(browser): Add `spanStreamingIntegration` (#19218)
Lms24 Feb 19, 2026
7c0ab66
feat(core): Add weight-based flushing to span buffer (#19579)
Lms24 Mar 2, 2026
13fac6a
test(browser): Add span streaming integration tests (#19581)
Lms24 Mar 6, 2026
ac8c702
fix(browser): Apply Http timing attributes to streamed `http.client` …
Lms24 Mar 9, 2026
3ab6fcb
fix(core): Replace global interval with trace-specific interval based…
Lms24 Mar 9, 2026
a29564e
feat(node-core): Add POtel server-side span streaming implementation …
Lms24 Mar 12, 2026
2aa1c63
test(node,node-core): Add span streaming integration tests (#19806)
Lms24 Mar 18, 2026
e360c3b
feat(core): Apply `ignoreSpans` to streamed spans (#19934)
Lms24 Apr 2, 2026
54b2d66
feat(browser-utils): Add FCP instrumentation handler and export INP_E…
logaretm Mar 16, 2026
728f0ec
feat(browser): Emit web vitals as streamed spans when span streaming …
logaretm Mar 16, 2026
65b22b0
test(browser): Add integration tests for streamed web vital spans
logaretm Mar 16, 2026
6f0add9
fix(browser): Only emit LCP, CLS, INP as streamed spans; disable stan…
logaretm Mar 23, 2026
9a11f1d
fix(browser): Add MAX_PLAUSIBLE_INP_DURATION check to streamed INP sp…
logaretm Mar 23, 2026
41d2d5a
fix(browser): Prevent duplicate INP spans when span streaming is enabled
logaretm Mar 23, 2026
1ad9e35
fix(browser-utils): Remove dead FCP instrumentation code
logaretm Mar 23, 2026
949df64
fix(browser-utils): Add fallback for browserPerformanceTimeOrigin in …
logaretm Mar 23, 2026
211790f
fix(browser-utils): Cache browserPerformanceTimeOrigin call in _sendL…
logaretm Mar 23, 2026
739fcf4
fix(browser): Skip INP interaction listeners when span streaming is e…
logaretm Mar 24, 2026
6d2401f
fix(browser): Skip CLS/LCP measurements on pageload span when streaming
logaretm Mar 24, 2026
7729456
refactor(browser-utils): Share MAX_PLAUSIBLE_INP_DURATION between INP…
logaretm Mar 24, 2026
8e5fa78
fix(browser): Fix ReferenceError for spanStreamingEnabled in afterAll…
logaretm Mar 24, 2026
b94c3b3
fix(browser): Skip redundant CLS/LCP handlers when span streaming is …
logaretm Mar 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions .size-limit.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = [
path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init'),
gzip: true,
limit: '24.5 KB',
limit: '25 KB',
modifyWebpackConfig: function (config) {
const webpack = require('webpack');

Expand Down Expand Up @@ -103,7 +103,7 @@ module.exports = [
path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'sendFeedback'),
gzip: true,
limit: '31 KB',
limit: '32 KB',
},
{
name: '@sentry/browser (incl. FeedbackAsync)',
Expand All @@ -117,7 +117,7 @@ module.exports = [
path: 'packages/browser/build/npm/esm/prod/index.js',
import: createImport('init', 'metrics'),
gzip: true,
limit: '27 KB',
limit: '28 KB',
},
{
name: '@sentry/browser (incl. Logs)',
Expand Down Expand Up @@ -148,7 +148,7 @@ module.exports = [
import: createImport('init', 'ErrorBoundary', 'reactRouterV6BrowserTracingIntegration'),
ignore: ['react/jsx-runtime'],
gzip: true,
limit: '45.1 KB',
limit: '46 KB',
},
// Vue SDK (ESM)
{
Expand Down Expand Up @@ -220,13 +220,13 @@ module.exports = [
name: 'CDN Bundle (incl. Tracing, Replay, Feedback)',
path: createCDNPath('bundle.tracing.replay.feedback.min.js'),
gzip: true,
limit: '86 KB',
limit: '87 KB',
},
{
name: 'CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)',
path: createCDNPath('bundle.tracing.replay.feedback.logs.metrics.min.js'),
gzip: true,
limit: '87 KB',
limit: '88 KB',
},
// browser CDN bundles (non-gzipped)
{
Expand All @@ -241,7 +241,7 @@ module.exports = [
path: createCDNPath('bundle.tracing.min.js'),
gzip: false,
brotli: false,
limit: '129 KB',
limit: '130 KB',
},
{
name: 'CDN Bundle (incl. Logs, Metrics) - uncompressed',
Expand All @@ -255,7 +255,7 @@ module.exports = [
path: createCDNPath('bundle.tracing.logs.metrics.min.js'),
gzip: false,
brotli: false,
limit: '132 KB',
limit: '134 KB',
},
{
name: 'CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed',
Expand All @@ -269,7 +269,7 @@ module.exports = [
path: createCDNPath('bundle.tracing.replay.min.js'),
gzip: false,
brotli: false,
limit: '246 KB',
limit: '247 KB',
},
{
name: 'CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed',
Expand Down Expand Up @@ -317,7 +317,7 @@ module.exports = [
import: createImport('init'),
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
gzip: true,
limit: '57 KB',
limit: '59 KB',
},
// Node SDK (ESM)
{
Expand All @@ -326,14 +326,14 @@ module.exports = [
import: createImport('init'),
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
gzip: true,
limit: '176 KB',
limit: '177 KB',
},
{
name: '@sentry/node - without tracing',
path: 'packages/node/build/esm/index.js',
import: createImport('initWithoutDefaultIntegrations', 'getDefaultIntegrationsWithoutPerformance'),
gzip: true,
limit: '98 KB',
limit: '100 KB',
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
modifyWebpackConfig: function (config) {
const webpack = require('webpack');
Expand All @@ -356,7 +356,7 @@ module.exports = [
import: createImport('init'),
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
gzip: true,
limit: '114 KB',
limit: '117 KB',
},
];

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as Sentry from '@sentry/browser';

window.Sentry = Sentry;

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
integrations: [Sentry.spanStreamingIntegration()],
tracesSampleRate: 1.0,
debug: true,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Sentry.startSpan({ name: 'test-span', op: 'test' }, () => {
Sentry.startSpan({ name: 'test-child-span', op: 'test-child' }, () => {
// noop
});

const inactiveSpan = Sentry.startInactiveSpan({ name: 'test-inactive-span' });
inactiveSpan.end();

Sentry.startSpanManual({ name: 'test-manual-span' }, span => {
// noop
span.end();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import { expect } from '@playwright/test';
import {
SDK_VERSION,
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE,
SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME,
SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION,
SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID,
SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME,
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
} from '@sentry/core';
import { sentryTest } from '../../../../utils/fixtures';
import { shouldSkipTracingTest, testingCdnBundle } from '../../../../utils/helpers';
import { waitForStreamedSpanEnvelope } from '../../../../utils/spanUtils';

sentryTest(
'sends a streamed span envelope if spanStreamingIntegration is enabled',
async ({ getLocalTestUrl, page }) => {
sentryTest.skip(shouldSkipTracingTest() || testingCdnBundle());

const spanEnvelopePromise = waitForStreamedSpanEnvelope(page);

const url = await getLocalTestUrl({ testDir: __dirname });
await page.goto(url);

const spanEnvelope = await spanEnvelopePromise;

const envelopeHeader = spanEnvelope[0];
const envelopeItem = spanEnvelope[1];
const spans = envelopeItem[0][1].items;

expect(envelopeHeader).toEqual({
sdk: {
name: 'sentry.javascript.browser',
version: SDK_VERSION,
},
sent_at: expect.any(String),
trace: {
environment: 'production',
public_key: 'public',
sample_rand: expect.any(String),
sample_rate: '1',
sampled: 'true',
trace_id: expect.stringMatching(/^[\da-f]{32}$/),
transaction: 'test-span',
},
});

const numericSampleRand = parseFloat(envelopeHeader.trace!.sample_rand!);
const traceId = envelopeHeader.trace!.trace_id;

expect(Number.isNaN(numericSampleRand)).toBe(false);

expect(envelopeItem).toEqual([
[
{ content_type: 'application/vnd.sentry.items.span.v2+json', item_count: 4, type: 'span' },
{
items: expect.any(Array),
},
],
]);

const segmentSpanId = spans.find(s => !!s.is_segment)?.span_id;
expect(segmentSpanId).toBeDefined();

expect(spans).toEqual([
{
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: {
type: 'string',
value: 'test-child',
},
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: {
type: 'string',
value: 'manual',
},
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME]: {
type: 'string',
value: 'sentry.javascript.browser',
},
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION]: {
type: 'string',
value: SDK_VERSION,
},
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: {
type: 'string',
value: segmentSpanId,
},
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: {
type: 'string',
value: 'test-span',
},
},
end_timestamp: expect.any(Number),
is_segment: false,
name: 'test-child-span',
parent_span_id: segmentSpanId,
span_id: expect.stringMatching(/^[\da-f]{16}$/),
start_timestamp: expect.any(Number),
status: 'ok',
trace_id: traceId,
},
{
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: {
type: 'string',
value: 'manual',
},
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME]: {
type: 'string',
value: 'sentry.javascript.browser',
},
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION]: {
type: 'string',
value: SDK_VERSION,
},
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: {
type: 'string',
value: segmentSpanId,
},
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: {
type: 'string',
value: 'test-span',
},
},
end_timestamp: expect.any(Number),
is_segment: false,
name: 'test-inactive-span',
parent_span_id: segmentSpanId,
span_id: expect.stringMatching(/^[\da-f]{16}$/),
start_timestamp: expect.any(Number),
status: 'ok',
trace_id: traceId,
},
{
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: {
type: 'string',
value: 'manual',
},
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME]: {
type: 'string',
value: 'sentry.javascript.browser',
},
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION]: {
type: 'string',
value: SDK_VERSION,
},
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: {
type: 'string',
value: segmentSpanId,
},
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: {
type: 'string',
value: 'test-span',
},
},
end_timestamp: expect.any(Number),
is_segment: false,
name: 'test-manual-span',
parent_span_id: segmentSpanId,
span_id: expect.stringMatching(/^[\da-f]{16}$/),
start_timestamp: expect.any(Number),
status: 'ok',
trace_id: traceId,
},
{
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: {
type: 'string',
value: 'test',
},
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: {
type: 'string',
value: 'manual',
},
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: {
type: 'integer',
value: 1,
},
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_NAME]: {
type: 'string',
value: 'sentry.javascript.browser',
},
[SEMANTIC_ATTRIBUTE_SENTRY_SDK_VERSION]: {
type: 'string',
value: SDK_VERSION,
},
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_ID]: {
type: 'string',
value: segmentSpanId,
},
[SEMANTIC_ATTRIBUTE_SENTRY_SEGMENT_NAME]: {
type: 'string',
value: 'test-span',
},
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: {
type: 'string',
value: 'custom',
},
'sentry.span.source': {
type: 'string',
value: 'custom',
},
},
end_timestamp: expect.any(Number),
is_segment: true,
name: 'test-span',
span_id: segmentSpanId,
start_timestamp: expect.any(Number),
status: 'ok',
trace_id: traceId,
},
]);
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as Sentry from '@sentry/browser';

window.Sentry = Sentry;

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
integrations: [Sentry.browserTracingIntegration(), Sentry.spanStreamingIntegration()],
tracesSampleRate: 1,
debug: true,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
document.getElementById('go-background').addEventListener('click', () => {
setTimeout(() => {
Object.defineProperty(document, 'hidden', { value: true, writable: true });
const ev = document.createEvent('Event');
ev.initEvent('visibilitychange');
document.dispatchEvent(ev);
}, 250);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<button id="go-background">New Tab</button>
</body>
</html>
Loading
Loading