Skip to content

fix(replay): Send dsn in envelope header if tunneling is enabled #6568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 6 additions & 22 deletions packages/core/src/envelope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
DsnComponents,
Event,
EventEnvelope,
EventEnvelopeHeaders,
EventItem,
SdkInfo,
SdkMetadata,
Expand All @@ -11,7 +10,12 @@ import {
SessionEnvelope,
SessionItem,
} from '@sentry/types';
import { createEnvelope, dropUndefinedKeys, dsnToString, getSdkMetadataForEnvelopeHeader } from '@sentry/utils';
import {
createEnvelope,
createEventEnvelopeHeaders,
dsnToString,
getSdkMetadataForEnvelopeHeader,
} from '@sentry/utils';

/**
* Apply SdkInfo (name, version, packages, integrations) to the corresponding event key.
Expand Down Expand Up @@ -74,23 +78,3 @@ export function createEventEnvelope(
const eventItem: EventItem = [{ type: eventType }, event];
return createEnvelope<EventEnvelope>(envelopeHeaders, [eventItem]);
}

function createEventEnvelopeHeaders(
event: Event,
sdkInfo: SdkInfo | undefined,
tunnel: string | undefined,
dsn: DsnComponents,
): EventEnvelopeHeaders {
const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext;

return {
event_id: event.event_id as string,
sent_at: new Date().toISOString(),
...(sdkInfo && { sdk: sdkInfo }),
...(!!tunnel && { dsn: dsnToString(dsn) }),
...(event.type === 'transaction' &&
dynamicSamplingContext && {
trace: dropUndefinedKeys({ ...dynamicSamplingContext }),
}),
};
}
5 changes: 3 additions & 2 deletions packages/replay/src/replay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -921,8 +921,9 @@ export class ReplayContainer implements ReplayContainerInterface {
const client = hub.getClient();
const scope = hub.getScope();
const transport = client && client.getTransport();
const dsn = client?.getDsn();

if (!client || !scope || !transport) {
if (!client || !scope || !transport || !dsn) {
Comment on lines +924 to +926
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just adding this here so we can be certain, dsn isn't undefined further below. In case we don't have a dsn, we can't send anything anyway.

return;
}

Expand Down Expand Up @@ -982,7 +983,7 @@ export class ReplayContainer implements ReplayContainerInterface {
}
*/

const envelope = createReplayEnvelope(replayId, replayEvent, payloadWithSequence);
const envelope = createReplayEnvelope(replayEvent, payloadWithSequence, dsn, client.getOptions().tunnel);

try {
return transport.send(envelope);
Expand Down
13 changes: 5 additions & 8 deletions packages/replay/src/util/createReplayEnvelope.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { Envelope, Event } from '@sentry/types';
import { createEnvelope, getSdkMetadataForEnvelopeHeader } from '@sentry/utils';
import { DsnComponents, Envelope, Event } from '@sentry/types';
import { createEnvelope, createEventEnvelopeHeaders, getSdkMetadataForEnvelopeHeader } from '@sentry/utils';

export function createReplayEnvelope(
replayId: string,
replayEvent: Event,
payloadWithSequence: string | Uint8Array,
dsn: DsnComponents,
tunnel?: string,
): Envelope {
return createEnvelope(
{
event_id: replayId,
sent_at: new Date().toISOString(),
sdk: getSdkMetadataForEnvelopeHeader(replayEvent),
},
createEventEnvelopeHeaders(replayEvent, getSdkMetadataForEnvelopeHeader(replayEvent), tunnel, dsn),
[
// @ts-ignore New types
[{ type: 'replay_event' }, replayEvent],
Expand Down
99 changes: 72 additions & 27 deletions packages/replay/test/unit/util/createReplayEnvelope.test.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,96 @@
import { Event } from '@sentry/types';
import { makeDsn } from '@sentry/utils';

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

describe('createReplayEnvelope', () => {
const REPLAY_ID = 'MY_REPLAY_ID';

const replayEvent = {
type: 'replay_event',
timestamp: 1670837008.634,
error_ids: ['errorId'],
trace_ids: ['traceId'],
urls: ['https://example.com'],
replay_id: REPLAY_ID,
segment_id: 3,
platform: 'javascript',
event_id: REPLAY_ID,
environment: 'production',
sdk: {
integrations: ['BrowserTracing', 'Replay'],
name: 'sentry.javascript.browser',
version: '7.25.0',
},
tags: {
sessionSampleRate: 1,
errorSampleRate: 0,
replayType: 'error',
},
};

const payloadWithSequence = 'payload';

const dsn = makeDsn({
host: 'sentry.io',
pass: 'xyz',
port: '1234',
projectId: '123',
protocol: 'https',
publicKey: 'abc',
});

it('creates an envelope for a given Replay event', () => {
const replayId = '1234';
const replayEvent = {
type: 'replay_event',
timestamp: 1670837008.634,
error_ids: ['errorId'],
trace_ids: ['traceId'],
urls: ['https://example.com'],
replay_id: 'eventId',
segment_id: 3,
platform: 'javascript',
event_id: 'eventId',
environment: 'production',
sdk: {
integrations: ['BrowserTracing', 'Replay'],
name: 'sentry.javascript.browser',
version: '7.25.0',
},
tags: {
sessionSampleRate: 1,
errorSampleRate: 0,
replayType: 'error',
const envelope = createReplayEnvelope(replayEvent as Event, payloadWithSequence, dsn);

expect(envelope).toEqual([
{
event_id: REPLAY_ID,
sdk: { name: 'sentry.javascript.browser', version: '7.25.0' },
sent_at: expect.any(String),
},
};
const payloadWithSequence = 'payload';
[
[
{ type: 'replay_event' },
{
environment: 'production',
error_ids: ['errorId'],
event_id: REPLAY_ID,
platform: 'javascript',
replay_id: REPLAY_ID,
sdk: { integrations: ['BrowserTracing', 'Replay'], name: 'sentry.javascript.browser', version: '7.25.0' },
segment_id: 3,
tags: { errorSampleRate: 0, replayType: 'error', sessionSampleRate: 1 },
timestamp: 1670837008.634,
trace_ids: ['traceId'],
type: 'replay_event',
urls: ['https://example.com'],
},
],
[{ length: 7, type: 'replay_recording' }, 'payload'],
],
]);
});

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

expect(envelope).toEqual([
{
event_id: '1234',
event_id: REPLAY_ID,
sdk: { name: 'sentry.javascript.browser', version: '7.25.0' },
sent_at: expect.any(String),
dsn: 'https://[email protected]:1234/123',
},
[
[
{ type: 'replay_event' },
{
environment: 'production',
error_ids: ['errorId'],
event_id: 'eventId',
event_id: REPLAY_ID,
platform: 'javascript',
replay_id: 'eventId',
replay_id: REPLAY_ID,
sdk: { integrations: ['BrowserTracing', 'Replay'], name: 'sentry.javascript.browser', version: '7.25.0' },
segment_id: 3,
tags: { errorSampleRate: 0, replayType: 'error', sessionSampleRate: 1 },
Expand Down
27 changes: 27 additions & 0 deletions packages/utils/src/envelope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import {
Attachment,
AttachmentItem,
DataCategory,
DsnComponents,
Envelope,
EnvelopeItem,
EnvelopeItemType,
Event,
EventEnvelopeHeaders,
SdkInfo,
SdkMetadata,
TextEncoderInternal,
} from '@sentry/types';

import { dsnToString } from './dsn';
import { normalize } from './normalize';
import { dropUndefinedKeys } from './object';

Expand Down Expand Up @@ -154,3 +157,27 @@ export function getSdkMetadataForEnvelopeHeader(metadataOrEvent?: SdkMetadata |
const { name, version } = metadataOrEvent.sdk;
return { name, version };
}

/**
* Creates event envelope headers, based on event, sdk info and tunnel
* Note: This function was extracted from the core package to make it available in Replay
*/
export function createEventEnvelopeHeaders(
event: Event,
sdkInfo: SdkInfo | undefined,
tunnel: string | undefined,
dsn: DsnComponents,
): EventEnvelopeHeaders {
const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext;

return {
event_id: event.event_id as string,
sent_at: new Date().toISOString(),
...(sdkInfo && { sdk: sdkInfo }),
...(!!tunnel && { dsn: dsnToString(dsn) }),
...(event.type === 'transaction' &&
dynamicSamplingContext && {
trace: dropUndefinedKeys({ ...dynamicSamplingContext }),
}),
};
}