Skip to content

Commit 69c6874

Browse files
authored
feat(core): Add new transports to base backend (#4752)
Adds new transports to base backend in core. For now, they are gated behind `options._experiments.newTransport = true`. The reason this is gated is because client reports does not work with the new transports. The next step is to add new transports for fetch, xhr (browser) as well as http, https (node). We can do this in any order!
1 parent 5f6335d commit 69c6874

File tree

4 files changed

+79
-18
lines changed

4 files changed

+79
-18
lines changed

packages/core/src/basebackend.ts

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { Event, EventHint, Options, Session, Severity, Transport } from '@sentry/types';
22
import { isDebugBuild, logger, SentryError } from '@sentry/utils';
33

4+
import { initAPIDetails } from './api';
5+
import { createEventEnvelope, createSessionEnvelope } from './request';
6+
import { NewTransport } from './transports/base';
47
import { NoopTransport } from './transports/noop';
58

69
/**
@@ -63,6 +66,9 @@ export abstract class BaseBackend<O extends Options> implements Backend {
6366
/** Cached transport used internally. */
6467
protected _transport: Transport;
6568

69+
/** New v7 Transport that is initialized alongside the old one */
70+
protected _newTransport?: NewTransport;
71+
6672
/** Creates a new backend instance. */
6773
public constructor(options: O) {
6874
this._options = options;
@@ -91,9 +97,23 @@ export abstract class BaseBackend<O extends Options> implements Backend {
9197
* @inheritDoc
9298
*/
9399
public sendEvent(event: Event): void {
94-
void this._transport.sendEvent(event).then(null, reason => {
95-
isDebugBuild() && logger.error('Error while sending event:', reason);
96-
});
100+
// TODO(v7): Remove the if-else
101+
if (
102+
this._newTransport &&
103+
this._options.dsn &&
104+
this._options._experiments &&
105+
this._options._experiments.newTransport
106+
) {
107+
const api = initAPIDetails(this._options.dsn, this._options._metadata, this._options.tunnel);
108+
const env = createEventEnvelope(event, api);
109+
void this._newTransport.send(env).then(null, reason => {
110+
isDebugBuild() && logger.error('Error while sending event:', reason);
111+
});
112+
} else {
113+
void this._transport.sendEvent(event).then(null, reason => {
114+
isDebugBuild() && logger.error('Error while sending event:', reason);
115+
});
116+
}
97117
}
98118

99119
/**
@@ -105,9 +125,23 @@ export abstract class BaseBackend<O extends Options> implements Backend {
105125
return;
106126
}
107127

108-
void this._transport.sendSession(session).then(null, reason => {
109-
isDebugBuild() && logger.error('Error while sending session:', reason);
110-
});
128+
// TODO(v7): Remove the if-else
129+
if (
130+
this._newTransport &&
131+
this._options.dsn &&
132+
this._options._experiments &&
133+
this._options._experiments.newTransport
134+
) {
135+
const api = initAPIDetails(this._options.dsn, this._options._metadata, this._options.tunnel);
136+
const [env] = createSessionEnvelope(session, api);
137+
void this._newTransport.send(env).then(null, reason => {
138+
isDebugBuild() && logger.error('Error while sending session:', reason);
139+
});
140+
} else {
141+
void this._transport.sendSession(session).then(null, reason => {
142+
isDebugBuild() && logger.error('Error while sending session:', reason);
143+
});
144+
}
111145
}
112146

113147
/**

packages/core/src/request.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ function enhanceEventWithSdkInfo(event: Event, sdkInfo?: SdkInfo): Event {
3939
return event;
4040
}
4141

42-
/** Creates a SentryRequest from a Session. */
43-
export function sessionToSentryRequest(session: Session | SessionAggregates, api: APIDetails): SentryRequest {
42+
/** Creates an envelope from a Session */
43+
export function createSessionEnvelope(
44+
session: Session | SessionAggregates,
45+
api: APIDetails,
46+
): [SessionEnvelope, SentryRequestType] {
4447
const sdkInfo = getSdkMetadataForEnvelopeHeader(api);
4548
const envelopeHeaders = {
4649
sent_at: new Date().toISOString(),
@@ -54,13 +57,47 @@ export function sessionToSentryRequest(session: Session | SessionAggregates, api
5457
// TODO (v7) Have to cast type because envelope items do not accept a `SentryRequestType`
5558
const envelopeItem = [{ type } as { type: 'session' | 'sessions' }, session] as SessionItem;
5659
const envelope = createEnvelope<SessionEnvelope>(envelopeHeaders, [envelopeItem]);
60+
61+
return [envelope, type];
62+
}
63+
64+
/** Creates a SentryRequest from a Session. */
65+
export function sessionToSentryRequest(session: Session | SessionAggregates, api: APIDetails): SentryRequest {
66+
const [envelope, type] = createSessionEnvelope(session, api);
5767
return {
5868
body: serializeEnvelope(envelope),
5969
type,
6070
url: getEnvelopeEndpointWithUrlEncodedAuth(api.dsn, api.tunnel),
6171
};
6272
}
6373

74+
/**
75+
* Create an Envelope from an event. Note that this is duplicated from below,
76+
* but on purpose as this will be refactored in v7.
77+
*/
78+
export function createEventEnvelope(event: Event, api: APIDetails): EventEnvelope {
79+
const sdkInfo = getSdkMetadataForEnvelopeHeader(api);
80+
const eventType = event.type || 'event';
81+
82+
const { transactionSampling } = event.sdkProcessingMetadata || {};
83+
const { method: samplingMethod, rate: sampleRate } = transactionSampling || {};
84+
85+
const envelopeHeaders = {
86+
event_id: event.event_id as string,
87+
sent_at: new Date().toISOString(),
88+
...(sdkInfo && { sdk: sdkInfo }),
89+
...(!!api.tunnel && { dsn: dsnToString(api.dsn) }),
90+
};
91+
const eventItem: EventItem = [
92+
{
93+
type: eventType,
94+
sample_rates: [{ id: samplingMethod, rate: sampleRate }],
95+
},
96+
event,
97+
];
98+
return createEnvelope<EventEnvelope>(envelopeHeaders, [eventItem]);
99+
}
100+
64101
/** Creates a SentryRequest from an event. */
65102
export function eventToSentryRequest(event: Event, api: APIDetails): SentryRequest {
66103
const sdkInfo = getSdkMetadataForEnvelopeHeader(api);

packages/core/src/transports/base.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,6 @@ export interface NodeTransportOptions extends BaseTransportOptions {
7979
}
8080

8181
export interface NewTransport {
82-
// If `$` is set, we know that this is a new transport.
83-
// TODO(v7): Remove this as we will no longer have split between
84-
// old and new transports.
85-
$: boolean;
8682
send(request: Envelope): PromiseLike<TransportResponse>;
8783
flush(timeout?: number): PromiseLike<boolean>;
8884
}
@@ -144,7 +140,6 @@ export function createTransport(
144140
}
145141

146142
return {
147-
$: true,
148143
send,
149144
flush,
150145
};

packages/core/test/lib/transports/base.test.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ const TRANSACTION_ENVELOPE = createEnvelope<EventEnvelope>(
2020
);
2121

2222
describe('createTransport', () => {
23-
it('has $ property', () => {
24-
const transport = createTransport({}, _ => resolvedSyncPromise({ statusCode: 200 }));
25-
expect(transport.$).toBeDefined();
26-
});
27-
2823
it('flushes the buffer', async () => {
2924
const mockBuffer: PromiseBuffer<TransportResponse> = {
3025
$: [],

0 commit comments

Comments
 (0)