diff --git a/packages/core/src/basebackend.ts b/packages/core/src/basebackend.ts index 4ba8cce63bd7..f770c5aa0d8c 100644 --- a/packages/core/src/basebackend.ts +++ b/packages/core/src/basebackend.ts @@ -1,6 +1,9 @@ import { Event, EventHint, Options, Session, Severity, Transport } from '@sentry/types'; import { isDebugBuild, logger, SentryError } from '@sentry/utils'; +import { initAPIDetails } from './api'; +import { createEventEnvelope, createSessionEnvelope } from './request'; +import { NewTransport } from './transports/base'; import { NoopTransport } from './transports/noop'; /** @@ -63,6 +66,9 @@ export abstract class BaseBackend implements Backend { /** Cached transport used internally. */ protected _transport: Transport; + /** New v7 Transport that is initialized alongside the old one */ + protected _newTransport?: NewTransport; + /** Creates a new backend instance. */ public constructor(options: O) { this._options = options; @@ -91,9 +97,23 @@ export abstract class BaseBackend implements Backend { * @inheritDoc */ public sendEvent(event: Event): void { - void this._transport.sendEvent(event).then(null, reason => { - isDebugBuild() && logger.error('Error while sending event:', reason); - }); + // TODO(v7): Remove the if-else + if ( + this._newTransport && + this._options.dsn && + this._options._experiments && + this._options._experiments.newTransport + ) { + const api = initAPIDetails(this._options.dsn, this._options._metadata, this._options.tunnel); + const env = createEventEnvelope(event, api); + void this._newTransport.send(env).then(null, reason => { + isDebugBuild() && logger.error('Error while sending event:', reason); + }); + } else { + void this._transport.sendEvent(event).then(null, reason => { + isDebugBuild() && logger.error('Error while sending event:', reason); + }); + } } /** @@ -105,9 +125,23 @@ export abstract class BaseBackend implements Backend { return; } - void this._transport.sendSession(session).then(null, reason => { - isDebugBuild() && logger.error('Error while sending session:', reason); - }); + // TODO(v7): Remove the if-else + if ( + this._newTransport && + this._options.dsn && + this._options._experiments && + this._options._experiments.newTransport + ) { + const api = initAPIDetails(this._options.dsn, this._options._metadata, this._options.tunnel); + const [env] = createSessionEnvelope(session, api); + void this._newTransport.send(env).then(null, reason => { + isDebugBuild() && logger.error('Error while sending session:', reason); + }); + } else { + void this._transport.sendSession(session).then(null, reason => { + isDebugBuild() && logger.error('Error while sending session:', reason); + }); + } } /** diff --git a/packages/core/src/request.ts b/packages/core/src/request.ts index 01cdd4a3035f..db53a0a367e6 100644 --- a/packages/core/src/request.ts +++ b/packages/core/src/request.ts @@ -39,8 +39,11 @@ function enhanceEventWithSdkInfo(event: Event, sdkInfo?: SdkInfo): Event { return event; } -/** Creates a SentryRequest from a Session. */ -export function sessionToSentryRequest(session: Session | SessionAggregates, api: APIDetails): SentryRequest { +/** Creates an envelope from a Session */ +export function createSessionEnvelope( + session: Session | SessionAggregates, + api: APIDetails, +): [SessionEnvelope, SentryRequestType] { const sdkInfo = getSdkMetadataForEnvelopeHeader(api); const envelopeHeaders = { sent_at: new Date().toISOString(), @@ -54,6 +57,13 @@ export function sessionToSentryRequest(session: Session | SessionAggregates, api // TODO (v7) Have to cast type because envelope items do not accept a `SentryRequestType` const envelopeItem = [{ type } as { type: 'session' | 'sessions' }, session] as SessionItem; const envelope = createEnvelope(envelopeHeaders, [envelopeItem]); + + return [envelope, type]; +} + +/** Creates a SentryRequest from a Session. */ +export function sessionToSentryRequest(session: Session | SessionAggregates, api: APIDetails): SentryRequest { + const [envelope, type] = createSessionEnvelope(session, api); return { body: serializeEnvelope(envelope), type, @@ -61,6 +71,33 @@ export function sessionToSentryRequest(session: Session | SessionAggregates, api }; } +/** + * Create an Envelope from an event. Note that this is duplicated from below, + * but on purpose as this will be refactored in v7. + */ +export function createEventEnvelope(event: Event, api: APIDetails): EventEnvelope { + const sdkInfo = getSdkMetadataForEnvelopeHeader(api); + const eventType = event.type || 'event'; + + const { transactionSampling } = event.sdkProcessingMetadata || {}; + const { method: samplingMethod, rate: sampleRate } = transactionSampling || {}; + + const envelopeHeaders = { + event_id: event.event_id as string, + sent_at: new Date().toISOString(), + ...(sdkInfo && { sdk: sdkInfo }), + ...(!!api.tunnel && { dsn: dsnToString(api.dsn) }), + }; + const eventItem: EventItem = [ + { + type: eventType, + sample_rates: [{ id: samplingMethod, rate: sampleRate }], + }, + event, + ]; + return createEnvelope(envelopeHeaders, [eventItem]); +} + /** Creates a SentryRequest from an event. */ export function eventToSentryRequest(event: Event, api: APIDetails): SentryRequest { const sdkInfo = getSdkMetadataForEnvelopeHeader(api); diff --git a/packages/core/src/transports/base.ts b/packages/core/src/transports/base.ts index d5e7218cd87d..6290fbfec36e 100644 --- a/packages/core/src/transports/base.ts +++ b/packages/core/src/transports/base.ts @@ -79,10 +79,6 @@ export interface NodeTransportOptions extends BaseTransportOptions { } export interface NewTransport { - // If `$` is set, we know that this is a new transport. - // TODO(v7): Remove this as we will no longer have split between - // old and new transports. - $: boolean; send(request: Envelope): PromiseLike; flush(timeout?: number): PromiseLike; } @@ -144,7 +140,6 @@ export function createTransport( } return { - $: true, send, flush, }; diff --git a/packages/core/test/lib/transports/base.test.ts b/packages/core/test/lib/transports/base.test.ts index cb32bb44bd73..2257a67165b1 100644 --- a/packages/core/test/lib/transports/base.test.ts +++ b/packages/core/test/lib/transports/base.test.ts @@ -20,11 +20,6 @@ const TRANSACTION_ENVELOPE = createEnvelope( ); describe('createTransport', () => { - it('has $ property', () => { - const transport = createTransport({}, _ => resolvedSyncPromise({ statusCode: 200 })); - expect(transport.$).toBeDefined(); - }); - it('flushes the buffer', async () => { const mockBuffer: PromiseBuffer = { $: [],