Skip to content

Commit fcdc337

Browse files
committed
Deduplicate span end logic
1 parent 3345b67 commit fcdc337

File tree

1 file changed

+25
-59
lines changed

1 file changed

+25
-59
lines changed

packages/react/src/reactrouter-compat-utils/instrumentation.tsx

Lines changed: 25 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -777,14 +777,16 @@ function getTransactionNameAndSource(
777777
* Patches the span.end() method to update the transaction name one last time before the span is sent.
778778
* This handles cases where the span is cancelled early (e.g., document.hidden) before lazy routes have finished loading.
779779
*/
780-
function patchPageloadSpanEnd(
780+
function patchSpanEnd(
781781
span: Span,
782782
location: Location,
783783
routes: RouteObject[],
784784
basename: string | undefined,
785785
_allRoutes: RouteObject[] | undefined,
786+
spanType: 'pageload' | 'navigation',
786787
): void {
787-
const hasEndBeenPatched = (span as { __sentry_pageload_end_patched__?: boolean })?.__sentry_pageload_end_patched__;
788+
const patchedPropertyName = `__sentry_${spanType}_end_patched__` as const;
789+
const hasEndBeenPatched = (span as unknown as Record<string, boolean | undefined>)?.[patchedPropertyName];
788790

789791
if (hasEndBeenPatched || !span.end) {
790792
return;
@@ -803,80 +805,44 @@ function patchPageloadSpanEnd(
803805
const branches = _matchRoutes(currentAllRoutes || routes, location, basename) as unknown as RouteMatch[];
804806

805807
if (branches) {
806-
const [latestName, latestSource] = getTransactionNameAndSource(
807-
location,
808-
routes,
809-
branches,
810-
basename,
811-
currentAllRoutes,
812-
);
808+
const [name, source] =
809+
spanType === 'pageload'
810+
? getTransactionNameAndSource(location, routes, branches, basename, currentAllRoutes)
811+
: resolveRouteNameAndSource(location, routes, currentAllRoutes, branches, basename);
813812

814-
span.updateName(latestName);
815-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, latestSource);
813+
// Only update if we have a valid name
814+
if (name && (spanType === 'pageload' || !spanJson.timestamp)) {
815+
span.updateName(name);
816+
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
817+
}
816818
}
817819
}
818820

819821
return originalEnd(...args);
820822
};
821823

822824
// Mark this span as having its end() method patched to prevent duplicate patching
823-
addNonEnumerableProperty(
824-
span as { __sentry_pageload_end_patched__?: boolean },
825-
'__sentry_pageload_end_patched__',
826-
true,
827-
);
825+
addNonEnumerableProperty(span as unknown as Record<string, boolean>, patchedPropertyName, true);
828826
}
829827

830-
/**
831-
* Patches the navigation span.end() method to update the transaction name one last time before the span is sent.
832-
* This handles cases where the span is cancelled early (e.g., document.hidden) before lazy routes have finished loading.
833-
*/
834-
function patchNavigationSpanEnd(
828+
function patchPageloadSpanEnd(
835829
span: Span,
836830
location: Location,
837831
routes: RouteObject[],
838832
basename: string | undefined,
839833
_allRoutes: RouteObject[] | undefined,
840834
): void {
841-
const hasEndBeenPatched = (span as { __sentry_navigation_end_patched__?: boolean })
842-
?.__sentry_navigation_end_patched__;
843-
844-
if (hasEndBeenPatched || !span.end) {
845-
return;
846-
}
847-
848-
const originalEnd = span.end.bind(span);
849-
850-
span.end = function patchedEnd(...args) {
851-
// Only update if the span source is not already 'route' (i.e., it hasn't been parameterized yet)
852-
const spanJson = spanToJSON(span);
853-
const currentSource = spanJson.data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
854-
if (currentSource !== 'route') {
855-
// Last chance to update the transaction name with the latest route info
856-
// Use the live global allRoutes Set to include any lazy routes loaded after patching
857-
const currentAllRoutes = Array.from(allRoutes);
858-
const branches = _matchRoutes(currentAllRoutes || routes, location, basename) as unknown as RouteMatch[];
859-
860-
if (branches) {
861-
const [name, source] = resolveRouteNameAndSource(location, routes, currentAllRoutes, branches, basename);
862-
863-
// Only update if we have a valid name and the span hasn't finished
864-
if (name && !spanJson.timestamp) {
865-
span.updateName(name);
866-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
867-
}
868-
}
869-
}
870-
871-
return originalEnd(...args);
872-
};
835+
patchSpanEnd(span, location, routes, basename, _allRoutes, 'pageload');
836+
}
873837

874-
// Mark this span as having its end() method patched to prevent duplicate patching
875-
addNonEnumerableProperty(
876-
span as { __sentry_navigation_end_patched__?: boolean },
877-
'__sentry_navigation_end_patched__',
878-
true,
879-
);
838+
function patchNavigationSpanEnd(
839+
span: Span,
840+
location: Location,
841+
routes: RouteObject[],
842+
basename: string | undefined,
843+
_allRoutes: RouteObject[] | undefined,
844+
): void {
845+
patchSpanEnd(span, location, routes, basename, _allRoutes, 'navigation');
880846
}
881847

882848
// eslint-disable-next-line @typescript-eslint/no-explicit-any

0 commit comments

Comments
 (0)