Skip to content

Commit 5961a96

Browse files
authored
fix(replay): Send dsn in envelope header if tunneling is active (#6568)
As outlined in #6539, we were previosuly not sending the `dsn` key in the replay event [envelope header](https://develop.sentry.dev/sdk/envelopes/#envelope-headers), thereby not including the necessary information to forward the event to Sentry. This patch fixes that by extracting the `createEventEnvelopeHeaders` function to utils so that we can use it in Replay (analogously to #6514), as well as using this function to create all headers. We tested the change with NextJS' `tunnelRoute` as well as with the conventional `tunnel` option and everything seems to work now.
1 parent 0463cc5 commit 5961a96

File tree

5 files changed

+113
-59
lines changed

5 files changed

+113
-59
lines changed

packages/core/src/envelope.ts

+6-22
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {
22
DsnComponents,
33
Event,
44
EventEnvelope,
5-
EventEnvelopeHeaders,
65
EventItem,
76
SdkInfo,
87
SdkMetadata,
@@ -11,7 +10,12 @@ import {
1110
SessionEnvelope,
1211
SessionItem,
1312
} from '@sentry/types';
14-
import { createEnvelope, dropUndefinedKeys, dsnToString, getSdkMetadataForEnvelopeHeader } from '@sentry/utils';
13+
import {
14+
createEnvelope,
15+
createEventEnvelopeHeaders,
16+
dsnToString,
17+
getSdkMetadataForEnvelopeHeader,
18+
} from '@sentry/utils';
1519

1620
/**
1721
* Apply SdkInfo (name, version, packages, integrations) to the corresponding event key.
@@ -74,23 +78,3 @@ export function createEventEnvelope(
7478
const eventItem: EventItem = [{ type: eventType }, event];
7579
return createEnvelope<EventEnvelope>(envelopeHeaders, [eventItem]);
7680
}
77-
78-
function createEventEnvelopeHeaders(
79-
event: Event,
80-
sdkInfo: SdkInfo | undefined,
81-
tunnel: string | undefined,
82-
dsn: DsnComponents,
83-
): EventEnvelopeHeaders {
84-
const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext;
85-
86-
return {
87-
event_id: event.event_id as string,
88-
sent_at: new Date().toISOString(),
89-
...(sdkInfo && { sdk: sdkInfo }),
90-
...(!!tunnel && { dsn: dsnToString(dsn) }),
91-
...(event.type === 'transaction' &&
92-
dynamicSamplingContext && {
93-
trace: dropUndefinedKeys({ ...dynamicSamplingContext }),
94-
}),
95-
};
96-
}

packages/replay/src/replay.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -921,8 +921,9 @@ export class ReplayContainer implements ReplayContainerInterface {
921921
const client = hub.getClient();
922922
const scope = hub.getScope();
923923
const transport = client && client.getTransport();
924+
const dsn = client?.getDsn();
924925

925-
if (!client || !scope || !transport) {
926+
if (!client || !scope || !transport || !dsn) {
926927
return;
927928
}
928929

@@ -982,7 +983,7 @@ export class ReplayContainer implements ReplayContainerInterface {
982983
}
983984
*/
984985

985-
const envelope = createReplayEnvelope(replayId, replayEvent, payloadWithSequence);
986+
const envelope = createReplayEnvelope(replayEvent, payloadWithSequence, dsn, client.getOptions().tunnel);
986987

987988
try {
988989
return transport.send(envelope);

packages/replay/src/util/createReplayEnvelope.ts

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
import { Envelope, Event } from '@sentry/types';
2-
import { createEnvelope, getSdkMetadataForEnvelopeHeader } from '@sentry/utils';
1+
import { DsnComponents, Envelope, Event } from '@sentry/types';
2+
import { createEnvelope, createEventEnvelopeHeaders, getSdkMetadataForEnvelopeHeader } from '@sentry/utils';
33

44
export function createReplayEnvelope(
5-
replayId: string,
65
replayEvent: Event,
76
payloadWithSequence: string | Uint8Array,
7+
dsn: DsnComponents,
8+
tunnel?: string,
89
): Envelope {
910
return createEnvelope(
10-
{
11-
event_id: replayId,
12-
sent_at: new Date().toISOString(),
13-
sdk: getSdkMetadataForEnvelopeHeader(replayEvent),
14-
},
11+
createEventEnvelopeHeaders(replayEvent, getSdkMetadataForEnvelopeHeader(replayEvent), tunnel, dsn),
1512
[
1613
// @ts-ignore New types
1714
[{ type: 'replay_event' }, replayEvent],

packages/replay/test/unit/util/createReplayEnvelope.test.ts

+72-27
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,96 @@
11
import { Event } from '@sentry/types';
2+
import { makeDsn } from '@sentry/utils';
23

34
import { createReplayEnvelope } from '../../../src/util/createReplayEnvelope';
45

56
describe('createReplayEnvelope', () => {
7+
const REPLAY_ID = 'MY_REPLAY_ID';
8+
9+
const replayEvent = {
10+
type: 'replay_event',
11+
timestamp: 1670837008.634,
12+
error_ids: ['errorId'],
13+
trace_ids: ['traceId'],
14+
urls: ['https://example.com'],
15+
replay_id: REPLAY_ID,
16+
segment_id: 3,
17+
platform: 'javascript',
18+
event_id: REPLAY_ID,
19+
environment: 'production',
20+
sdk: {
21+
integrations: ['BrowserTracing', 'Replay'],
22+
name: 'sentry.javascript.browser',
23+
version: '7.25.0',
24+
},
25+
tags: {
26+
sessionSampleRate: 1,
27+
errorSampleRate: 0,
28+
replayType: 'error',
29+
},
30+
};
31+
32+
const payloadWithSequence = 'payload';
33+
34+
const dsn = makeDsn({
35+
host: 'sentry.io',
36+
pass: 'xyz',
37+
port: '1234',
38+
projectId: '123',
39+
protocol: 'https',
40+
publicKey: 'abc',
41+
});
42+
643
it('creates an envelope for a given Replay event', () => {
7-
const replayId = '1234';
8-
const replayEvent = {
9-
type: 'replay_event',
10-
timestamp: 1670837008.634,
11-
error_ids: ['errorId'],
12-
trace_ids: ['traceId'],
13-
urls: ['https://example.com'],
14-
replay_id: 'eventId',
15-
segment_id: 3,
16-
platform: 'javascript',
17-
event_id: 'eventId',
18-
environment: 'production',
19-
sdk: {
20-
integrations: ['BrowserTracing', 'Replay'],
21-
name: 'sentry.javascript.browser',
22-
version: '7.25.0',
23-
},
24-
tags: {
25-
sessionSampleRate: 1,
26-
errorSampleRate: 0,
27-
replayType: 'error',
44+
const envelope = createReplayEnvelope(replayEvent as Event, payloadWithSequence, dsn);
45+
46+
expect(envelope).toEqual([
47+
{
48+
event_id: REPLAY_ID,
49+
sdk: { name: 'sentry.javascript.browser', version: '7.25.0' },
50+
sent_at: expect.any(String),
2851
},
29-
};
30-
const payloadWithSequence = 'payload';
52+
[
53+
[
54+
{ type: 'replay_event' },
55+
{
56+
environment: 'production',
57+
error_ids: ['errorId'],
58+
event_id: REPLAY_ID,
59+
platform: 'javascript',
60+
replay_id: REPLAY_ID,
61+
sdk: { integrations: ['BrowserTracing', 'Replay'], name: 'sentry.javascript.browser', version: '7.25.0' },
62+
segment_id: 3,
63+
tags: { errorSampleRate: 0, replayType: 'error', sessionSampleRate: 1 },
64+
timestamp: 1670837008.634,
65+
trace_ids: ['traceId'],
66+
type: 'replay_event',
67+
urls: ['https://example.com'],
68+
},
69+
],
70+
[{ length: 7, type: 'replay_recording' }, 'payload'],
71+
],
72+
]);
73+
});
3174

32-
const envelope = createReplayEnvelope(replayId, replayEvent as Event, payloadWithSequence);
75+
it('creates an envelope with the `dsn` key in the header if `tunnel` is specified', () => {
76+
const envelope = createReplayEnvelope(replayEvent as Event, payloadWithSequence, dsn, '/my-tunnel-endpoint');
3377

3478
expect(envelope).toEqual([
3579
{
36-
event_id: '1234',
80+
event_id: REPLAY_ID,
3781
sdk: { name: 'sentry.javascript.browser', version: '7.25.0' },
3882
sent_at: expect.any(String),
83+
dsn: 'https://[email protected]:1234/123',
3984
},
4085
[
4186
[
4287
{ type: 'replay_event' },
4388
{
4489
environment: 'production',
4590
error_ids: ['errorId'],
46-
event_id: 'eventId',
91+
event_id: REPLAY_ID,
4792
platform: 'javascript',
48-
replay_id: 'eventId',
93+
replay_id: REPLAY_ID,
4994
sdk: { integrations: ['BrowserTracing', 'Replay'], name: 'sentry.javascript.browser', version: '7.25.0' },
5095
segment_id: 3,
5196
tags: { errorSampleRate: 0, replayType: 'error', sessionSampleRate: 1 },

packages/utils/src/envelope.ts

+27
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@ import {
22
Attachment,
33
AttachmentItem,
44
DataCategory,
5+
DsnComponents,
56
Envelope,
67
EnvelopeItem,
78
EnvelopeItemType,
89
Event,
10+
EventEnvelopeHeaders,
911
SdkInfo,
1012
SdkMetadata,
1113
TextEncoderInternal,
1214
} from '@sentry/types';
1315

16+
import { dsnToString } from './dsn';
1417
import { normalize } from './normalize';
1518
import { dropUndefinedKeys } from './object';
1619

@@ -154,3 +157,27 @@ export function getSdkMetadataForEnvelopeHeader(metadataOrEvent?: SdkMetadata |
154157
const { name, version } = metadataOrEvent.sdk;
155158
return { name, version };
156159
}
160+
161+
/**
162+
* Creates event envelope headers, based on event, sdk info and tunnel
163+
* Note: This function was extracted from the core package to make it available in Replay
164+
*/
165+
export function createEventEnvelopeHeaders(
166+
event: Event,
167+
sdkInfo: SdkInfo | undefined,
168+
tunnel: string | undefined,
169+
dsn: DsnComponents,
170+
): EventEnvelopeHeaders {
171+
const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext;
172+
173+
return {
174+
event_id: event.event_id as string,
175+
sent_at: new Date().toISOString(),
176+
...(sdkInfo && { sdk: sdkInfo }),
177+
...(!!tunnel && { dsn: dsnToString(dsn) }),
178+
...(event.type === 'transaction' &&
179+
dynamicSamplingContext && {
180+
trace: dropUndefinedKeys({ ...dynamicSamplingContext }),
181+
}),
182+
};
183+
}

0 commit comments

Comments
 (0)