From 0b291e8f83102fffd20fda2a22685a3c547018eb Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 27 Mar 2024 19:11:58 +0100 Subject: [PATCH] fix(deprecations): Removes all trivial/drop-in-replacement deprecations --- src/js/client.ts | 12 ++++++------ src/js/profiling/integration.ts | 4 ++-- src/js/sdk.tsx | 23 ++++++++++++----------- src/js/touchevents.tsx | 8 ++++---- src/js/tracing/addTracingExtensions.ts | 7 +++---- src/js/tracing/nativeframes.ts | 22 ++++++++++++++++------ src/js/tracing/reactnativeprofiler.tsx | 16 ++++++++-------- src/js/tracing/reactnativetracing.ts | 14 +++++++------- src/js/tracing/stalltracking.ts | 13 +++++++------ src/js/tracing/transaction.ts | 12 ++++++------ src/js/tracing/utils.ts | 5 ++++- 11 files changed, 75 insertions(+), 61 deletions(-) diff --git a/src/js/client.ts b/src/js/client.ts index f351a75f67..bd2cf44f89 100644 --- a/src/js/client.ts +++ b/src/js/client.ts @@ -16,7 +16,7 @@ import { Alert } from 'react-native'; import { createIntegration } from './integrations/factory'; import { defaultSdkInfo } from './integrations/sdkinfo'; import type { ReactNativeClientOptions } from './options'; -import { ReactNativeTracing } from './tracing'; +import type { ReactNativeTracing } from './tracing'; import { createUserFeedbackEnvelope, items } from './utils/envelope'; import { ignoreRequireCycleLogs } from './utils/ignorerequirecyclelogs'; import { mergeOutcomes } from './utils/outcome'; @@ -90,12 +90,12 @@ export class ReactNativeClient extends BaseClient { } /** - * Sets up the integrations + * @inheritdoc */ - public setupIntegrations(): void { - super.setupIntegrations(); - const tracing = this.getIntegration(ReactNativeTracing); - const routingName = tracing?.options.routingInstrumentation?.name; + protected _setupIntegrations(): void { + super._setupIntegrations(); + const tracing = this.getIntegrationByName('ReactNativeTracing') as ReactNativeTracing; + const routingName = tracing?.options?.routingInstrumentation?.name; if (routingName) { this.addIntegration(createIntegration(routingName)); } diff --git a/src/js/profiling/integration.ts b/src/js/profiling/integration.ts index b82ecfad58..b5b7efa440 100644 --- a/src/js/profiling/integration.ts +++ b/src/js/profiling/integration.ts @@ -1,6 +1,6 @@ /* eslint-disable complexity */ import type { Hub } from '@sentry/core'; -import { getActiveTransaction } from '@sentry/core'; +import { getActiveTransaction, spanIsSampled } from '@sentry/core'; import type { Envelope, Event, EventProcessor, Integration, ThreadCpuProfile, Transaction } from '@sentry/types'; import { logger, uuid4 } from '@sentry/utils'; import { Platform } from 'react-native'; @@ -112,7 +112,7 @@ export class HermesProfiling implements Integration { }; private _shouldStartProfiling = (transaction: Transaction): boolean => { - if (!transaction.sampled) { + if (!spanIsSampled(transaction)) { logger.log('[Profiling] Transaction is not sampled, skipping profiling'); return false; } diff --git a/src/js/sdk.tsx b/src/js/sdk.tsx index 4a753d1dad..6eb942bd82 100644 --- a/src/js/sdk.tsx +++ b/src/js/sdk.tsx @@ -1,6 +1,6 @@ /* eslint-disable complexity */ import type { Scope } from '@sentry/core'; -import { getIntegrationsToSetup, Hub, initAndBind, makeMain, setExtra } from '@sentry/core'; +import { getClient, getIntegrationsToSetup, Hub, initAndBind, makeMain, setExtra, withScope as coreWithScope } from '@sentry/core'; import { defaultStackParser, getCurrentHub, @@ -16,7 +16,8 @@ import type { ReactNativeClientOptions, ReactNativeOptions, ReactNativeWrapperOp import { shouldEnableNativeNagger } from './options'; import { ReactNativeScope } from './scope'; import { TouchEventBoundary } from './touchevents'; -import { ReactNativeProfiler, ReactNativeTracing } from './tracing'; +import type { ReactNativeTracing } from './tracing'; +import { ReactNativeProfiler } from './tracing'; import { DEFAULT_BUFFER_SIZE, makeNativeTransportFactory } from './transports/native'; import { makeUtf8TextEncoder } from './transports/TextEncoder'; import { getDefaultEnvironment, isExpoGo } from './utils/environment'; @@ -108,7 +109,7 @@ export function wrap

>( RootComponent: React.ComponentType

, options?: ReactNativeWrapperOptions ): React.ComponentType

{ - const tracingIntegration = getCurrentHub().getIntegration(ReactNativeTracing); + const tracingIntegration = getClient()?.getIntegrationByName?.('ReactNativeTracing') as ReactNativeTracing | undefined; if (tracingIntegration) { tracingIntegration.useAppStartWithProfiler = true; } @@ -154,10 +155,7 @@ export function setDist(dist: string): void { * Use this only for testing purposes. */ export function nativeCrash(): void { - const client = getCurrentHub().getClient(); - if (client) { - client.nativeCrash(); - } + NATIVE.nativeCrash(); } /** @@ -166,7 +164,7 @@ export function nativeCrash(): void { */ export async function flush(): Promise { try { - const client = getCurrentHub().getClient(); + const client = getClient(); if (client) { const result = await client.flush(); @@ -186,7 +184,7 @@ export async function flush(): Promise { */ export async function close(): Promise { try { - const client = getCurrentHub().getClient(); + const client = getClient(); if (client) { await client.close(); @@ -200,7 +198,7 @@ export async function close(): Promise { * Captures user feedback and sends it to Sentry. */ export function captureUserFeedback(feedback: UserFeedback): void { - getCurrentHub().getClient()?.captureUserFeedback(feedback); + getClient()?.captureUserFeedback(feedback); } /** @@ -225,12 +223,14 @@ export function withScope(callback: (scope: Scope) => T): T | undefined { return undefined; } }; - return getCurrentHub().withScope(safeCallback); + return coreWithScope(safeCallback); } /** * Callback to set context information onto the scope. * @param callback Callback function that receives Scope. + * + * @deprecated Use `getScope()` directly. */ export function configureScope(callback: (scope: Scope) => void): ReturnType { const safeCallback = (scope: Scope): void => { @@ -240,5 +240,6 @@ export function configureScope(callback: (scope: Scope) => void): ReturnType { * Registers the TouchEventBoundary as a Sentry Integration. */ public componentDidMount(): void { - const client = getCurrentHub().getClient(); + const client = getClient(); client?.addIntegration?.(createIntegration(this.name)); if (!this._tracingIntegration && client) { - this._tracingIntegration = client.getIntegration(ReactNativeTracing); + this._tracingIntegration = client.getIntegrationByName?.('ReactNativeTracing') as ReactNativeTracing|| null; } } diff --git a/src/js/tracing/addTracingExtensions.ts b/src/js/tracing/addTracingExtensions.ts index b3ce2c527b..c6567b0942 100644 --- a/src/js/tracing/addTracingExtensions.ts +++ b/src/js/tracing/addTracingExtensions.ts @@ -67,15 +67,14 @@ const _patchStartTransaction = (originalStartTransaction: StartTransactionFuncti if (reactNativeTracing) { reactNativeTracing.onTransactionStart(transaction); - // eslint-disable-next-line @typescript-eslint/unbound-method - const originalFinish = transaction.finish; + const originalFinish = transaction.end.bind(transaction); - transaction.finish = (endTimestamp: number | undefined) => { + transaction.end = (endTimestamp: number | undefined) => { if (reactNativeTracing) { reactNativeTracing.onTransactionFinish(transaction); } - return originalFinish.apply(transaction, [endTimestamp]); + return originalFinish(endTimestamp); }; } diff --git a/src/js/tracing/nativeframes.ts b/src/js/tracing/nativeframes.ts index 80fac1428c..7edbb8944e 100644 --- a/src/js/tracing/nativeframes.ts +++ b/src/js/tracing/nativeframes.ts @@ -1,4 +1,4 @@ -import type { Span, Transaction } from '@sentry/core'; +import { type Span, type Transaction,spanToJSON } from '@sentry/core'; import type { Event, EventProcessor, Measurements, MeasurementUnit } from '@sentry/types'; import { logger, timestampInSeconds } from '@sentry/utils'; @@ -169,6 +169,11 @@ export class NativeFramesInstrumentation { * Fetch finish frames for a transaction at the current time. Calls any awaiting listeners. */ private async _fetchFramesForTransaction(transaction: Transaction): Promise { + const traceId = spanToJSON(transaction).trace_id; + if (!traceId) { + return; + } + const startFrames = transaction.data.__startFrames as NativeFramesResponse | undefined; // This timestamp marks when the finish frames were retrieved. It should be pretty close to the transaction finish. @@ -178,12 +183,12 @@ export class NativeFramesInstrumentation { finishFrames = await NATIVE.fetchNativeFrames(); } - this._finishFrames.set(transaction.traceId, { + this._finishFrames.set(traceId, { nativeFrames: finishFrames, timestamp, }); - this._framesListeners.get(transaction.traceId)?.(); + this._framesListeners.get(traceId)?.(); setTimeout(() => this._cancelFinishFrames(transaction), 2000); } @@ -192,11 +197,16 @@ export class NativeFramesInstrumentation { * On a finish frames failure, we cancel the await. */ private _cancelFinishFrames(transaction: Transaction): void { - if (this._finishFrames.has(transaction.traceId)) { - this._finishFrames.delete(transaction.traceId); + const traceId = spanToJSON(transaction).trace_id; + if (!traceId) { + return; + } + + if (this._finishFrames.has(traceId)) { + this._finishFrames.delete(traceId); logger.log( - `[NativeFrames] Native frames timed out for ${transaction.op} transaction ${transaction.name}. Not adding native frames measurements.`, + `[NativeFrames] Native frames timed out for ${spanToJSON(transaction).op} transaction ${spanToJSON(transaction).description}. Not adding native frames measurements.`, ); } } diff --git a/src/js/tracing/reactnativeprofiler.tsx b/src/js/tracing/reactnativeprofiler.tsx index 71fcfb8434..a6d15deddf 100644 --- a/src/js/tracing/reactnativeprofiler.tsx +++ b/src/js/tracing/reactnativeprofiler.tsx @@ -1,7 +1,8 @@ -import { getCurrentHub, Profiler } from '@sentry/react'; +import { spanToJSON } from '@sentry/core'; +import { getClient, Profiler } from '@sentry/react'; import { createIntegration } from '../integrations/factory'; -import { ReactNativeTracing } from './reactnativetracing'; +import type { ReactNativeTracing } from './reactnativetracing'; const ReactNativeProfilerGlobalState = { appStartReported: false, @@ -28,8 +29,7 @@ export class ReactNativeProfiler extends Profiler { * Notifies the Tracing integration that the app start has finished. */ private _reportAppStart(): void { - const hub = getCurrentHub(); - const client = hub.getClient(); + const client = getClient(); if (!client) { // We can't use logger here because this will be logged before the `Sentry.init`. @@ -40,11 +40,11 @@ export class ReactNativeProfiler extends Profiler { client.addIntegration && client.addIntegration(createIntegration(this.name)); - const tracingIntegration = hub.getIntegration(ReactNativeTracing); + const endTimestamp = this._mountSpan && typeof spanToJSON(this._mountSpan).timestamp + const tracingIntegration = client.getIntegrationByName && client.getIntegrationByName('ReactNativeTracing'); tracingIntegration - && this._mountSpan - && typeof this._mountSpan.endTimestamp !== 'undefined' + && typeof endTimestamp === 'number' // The first root component mount is the app start finish. - && tracingIntegration.onAppStartFinish(this._mountSpan.endTimestamp); + && tracingIntegration.onAppStartFinish(endTimestamp); } } diff --git a/src/js/tracing/reactnativetracing.ts b/src/js/tracing/reactnativetracing.ts index 397cc1ee50..ef73d50f80 100644 --- a/src/js/tracing/reactnativetracing.ts +++ b/src/js/tracing/reactnativetracing.ts @@ -2,7 +2,7 @@ import type { RequestInstrumentationOptions } from '@sentry/browser'; import { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from '@sentry/browser'; import type { Hub, IdleTransaction, Transaction } from '@sentry/core'; -import { getActiveTransaction, getCurrentHub, startIdleTransaction } from '@sentry/core'; +import { getActiveTransaction, getCurrentHub, spanToJSON, startIdleTransaction } from '@sentry/core'; import type { Event, EventProcessor, @@ -272,7 +272,7 @@ export class ReactNativeTracing implements Integration { * To be called on a transaction start. Can have async methods */ public onTransactionStart(transaction: Transaction): void { - if (isNearToNow(transaction.startTimestamp)) { + if (isNearToNow(spanToJSON(transaction).start_timestamp)) { // Only if this method is called at or within margin of error to the start timestamp. this.nativeFramesInstrumentation?.onTransactionStart(transaction); this.stallTrackingInstrumentation?.onTransactionStart(transaction); @@ -324,11 +324,11 @@ export class ReactNativeTracing implements Integration { const hub = this._getCurrentHub?.() || getCurrentHub(); const activeTransaction = getActiveTransaction(hub); - const activeTransactionIsNotInteraction = - activeTransaction?.spanId !== this._inflightInteractionTransaction?.spanId; + const activeTransactionIsNotInteraction = !activeTransaction || !this._inflightInteractionTransaction || + spanToJSON(activeTransaction).span_id !== spanToJSON(this._inflightInteractionTransaction).span_id; if (activeTransaction && activeTransactionIsNotInteraction) { logger.warn( - `[ReactNativeTracing] Did not create ${op} transaction because active transaction ${activeTransaction.name} exists on the scope.`, + `[ReactNativeTracing] Did not create ${op} transaction because active transaction ${spanToJSON(activeTransaction).description} exists on the scope.`, ); return; } @@ -534,10 +534,10 @@ export class ReactNativeTracing implements Integration { if (this._inflightInteractionTransaction) { logger.log( - `[ReactNativeTracing] Canceling ${this._inflightInteractionTransaction.op} transaction because navigation ${context.op}.`, + `[ReactNativeTracing] Canceling ${spanToJSON(this._inflightInteractionTransaction).op} transaction because navigation ${context.op}.`, ); this._inflightInteractionTransaction.setStatus('cancelled'); - this._inflightInteractionTransaction.finish(); + this._inflightInteractionTransaction.end(); } const { finalTimeoutMs } = this.options; diff --git a/src/js/tracing/stalltracking.ts b/src/js/tracing/stalltracking.ts index 8d2fef31ac..66c4d03738 100644 --- a/src/js/tracing/stalltracking.ts +++ b/src/js/tracing/stalltracking.ts @@ -1,5 +1,5 @@ /* eslint-disable max-lines */ -import type { IdleTransaction, Span, Transaction } from '@sentry/core'; +import { type IdleTransaction, type Span, type Transaction,spanToJSON } from '@sentry/core'; import type { Measurements, MeasurementUnit } from '@sentry/types'; import { logger, timestampInSeconds } from '@sentry/utils'; import type { AppStateStatus } from 'react-native'; @@ -118,8 +118,9 @@ export class StallTrackingInstrumentation { originalSpanFinish.apply(span, [endTimestamp]); // The span should set a timestamp, so this would be defined. - if (span.endTimestamp) { - this._markSpanFinish(transaction, span.endTimestamp); + const finalEndTimestamp = spanToJSON(span).timestamp; + if (finalEndTimestamp) { + this._markSpanFinish(transaction, finalEndTimestamp); } }; }; @@ -144,10 +145,10 @@ export class StallTrackingInstrumentation { return; } - const endTimestamp = passedEndTimestamp ?? transaction.endTimestamp; + const endTimestamp = passedEndTimestamp ?? spanToJSON(transaction).timestamp; const spans = transaction.spanRecorder ? transaction.spanRecorder.spans : []; - const finishedSpanCount = spans.reduce((count, s) => (s !== transaction && s.endTimestamp ? count + 1 : count), 0); + const finishedSpanCount = spans.reduce((count, s) => (s !== transaction && spanToJSON(s).timestamp ? count + 1 : count), 0); const trimEnd = transaction.toContext().trimEnd; const endWillBeTrimmed = trimEnd && finishedSpanCount > 0; @@ -170,7 +171,7 @@ export class StallTrackingInstrumentation { // There will be cancelled spans, which means that the end won't be trimmed const spansWillBeCancelled = spans.some( - s => s !== transaction && s.startTimestamp < endTimestamp && !s.endTimestamp, + s => s !== transaction && s.startTimestamp < endTimestamp && !spanToJSON(s).timestamp, ); if (endWillBeTrimmed && !spansWillBeCancelled) { diff --git a/src/js/tracing/transaction.ts b/src/js/tracing/transaction.ts index 2686fe9603..5c58d6fc36 100644 --- a/src/js/tracing/transaction.ts +++ b/src/js/tracing/transaction.ts @@ -1,4 +1,4 @@ -import { type BeforeFinishCallback, type IdleTransaction } from '@sentry/core'; +import { type BeforeFinishCallback, type IdleTransaction,spanToJSON } from '@sentry/core'; import { logger } from '@sentry/utils'; import type { AppStateStatus } from 'react-native'; import { AppState } from 'react-native'; @@ -10,10 +10,10 @@ import { AppState } from 'react-native'; export const onlySampleIfChildSpans: BeforeFinishCallback = (transaction: IdleTransaction): void => { const spansCount = transaction.spanRecorder && - transaction.spanRecorder.spans.filter(span => span.spanId !== transaction.spanId).length; + transaction.spanRecorder.spans.filter(span => spanToJSON(span).span_id !== spanToJSON(transaction).span_id).length; if (!spansCount || spansCount <= 0) { - logger.log(`Not sampling as ${transaction.op} transaction has no child spans.`); + logger.log(`Not sampling as ${spanToJSON(transaction).op} transaction has no child spans.`); transaction.sampled = false; } }; @@ -24,13 +24,13 @@ export const onlySampleIfChildSpans: BeforeFinishCallback = (transaction: IdleTr export const cancelInBackground = (transaction: IdleTransaction): void => { const subscription = AppState.addEventListener('change', (newState: AppStateStatus) => { if (newState === 'background') { - logger.debug(`Setting ${transaction.op} transaction to cancelled because the app is in the background.`); + logger.debug(`Setting ${spanToJSON(transaction).op} transaction to cancelled because the app is in the background.`); transaction.setStatus('cancelled'); - transaction.finish(); + transaction.end(); } }); transaction.registerBeforeFinishCallback(() => { - logger.debug(`Removing AppState listener for ${transaction.op} transaction.`); + logger.debug(`Removing AppState listener for ${spanToJSON(transaction).op} transaction.`); subscription.remove(); }); }; diff --git a/src/js/tracing/utils.ts b/src/js/tracing/utils.ts index de74bfe447..98e90d4bc7 100644 --- a/src/js/tracing/utils.ts +++ b/src/js/tracing/utils.ts @@ -94,7 +94,10 @@ export function instrumentChildSpanFinish( /** * Determines if the timestamp is now or within the specified margin of error from now. */ -export function isNearToNow(timestamp: number): boolean { +export function isNearToNow(timestamp: number | undefined): boolean { + if (!timestamp) { + return false; + } return Math.abs(timestampInSeconds() - timestamp) <= MARGIN_OF_ERROR_SECONDS; }