Skip to content

Commit 35b0399

Browse files
committed
feat(core): Add new transports to base backend
Adds new transports to base backend in core. For now, they are gated behind `options._experiments.newTransport = true`. The next step is to add new transports for fetch, xhr (browser) as well as http, https (node).
1 parent 5f0b1d0 commit 35b0399

File tree

4 files changed

+81
-18
lines changed

4 files changed

+81
-18
lines changed

packages/core/src/basebackend.ts

Lines changed: 42 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
/**
@@ -123,4 +157,6 @@ export abstract class BaseBackend<O extends Options> implements Backend {
123157
protected _setupTransport(): Transport {
124158
return new NoopTransport();
125159
}
160+
161+
protected abstract _setupNewTransport(): NewTransport;
126162
}

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
}
@@ -143,7 +139,6 @@ export function createTransport(
143139
}
144140

145141
return {
146-
$: true,
147142
send,
148143
flush,
149144
};

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)