Skip to content

Commit f1b29ef

Browse files
authored
ref(react): Add transaction source for react router v6 (#5385)
1 parent 0dbbac6 commit f1b29ef

File tree

2 files changed

+37
-20
lines changed

2 files changed

+37
-20
lines changed

packages/react/src/reactrouterv6.tsx

+25-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Inspired from Donnie McNeal's solution:
22
// https://gist.github.com/wontondon/e8c4bdf2888875e4c755712e99279536
33

4-
import { Transaction, TransactionContext } from '@sentry/types';
4+
import { Transaction, TransactionContext, TransactionSource } from '@sentry/types';
55
import { getGlobalObject, logger } from '@sentry/utils';
66
import hoistNonReactStatics from 'hoist-non-react-statics';
77
import React from 'react';
@@ -48,14 +48,6 @@ const SENTRY_TAGS = {
4848
'routing.instrumentation': 'react-router-v6',
4949
};
5050

51-
function getInitPathName(): string | undefined {
52-
if (global && global.location) {
53-
return global.location.pathname;
54-
}
55-
56-
return undefined;
57-
}
58-
5951
export function reactRouterV6Instrumentation(
6052
useEffect: UseEffect,
6153
useLocation: UseLocation,
@@ -68,12 +60,15 @@ export function reactRouterV6Instrumentation(
6860
startTransactionOnPageLoad = true,
6961
startTransactionOnLocationChange = true,
7062
): void => {
71-
const initPathName = getInitPathName();
63+
const initPathName = global && global.location && global.location.pathname;
7264
if (startTransactionOnPageLoad && initPathName) {
7365
activeTransaction = customStartTransaction({
7466
name: initPathName,
7567
op: 'pageload',
7668
tags: SENTRY_TAGS,
69+
metadata: {
70+
source: 'url',
71+
},
7772
});
7873
}
7974

@@ -88,9 +83,13 @@ export function reactRouterV6Instrumentation(
8883
};
8984
}
9085

91-
const getTransactionName = (routes: RouteObject[], location: Location, matchRoutes: MatchRoutes): string => {
86+
function getNormalizedName(
87+
routes: RouteObject[],
88+
location: Location,
89+
matchRoutes: MatchRoutes,
90+
): [string, TransactionSource] {
9291
if (!routes || routes.length === 0 || !matchRoutes) {
93-
return location.pathname;
92+
return [location.pathname, 'url'];
9493
}
9594

9695
const branches = matchRoutes(routes, location);
@@ -99,13 +98,16 @@ const getTransactionName = (routes: RouteObject[], location: Location, matchRout
9998
// eslint-disable-next-line @typescript-eslint/prefer-for-of
10099
for (let x = 0; x < branches.length; x++) {
101100
if (branches[x].route && branches[x].route.path && branches[x].pathname === location.pathname) {
102-
return branches[x].route.path || location.pathname;
101+
const path = branches[x].route.path;
102+
if (path) {
103+
return [path, 'route'];
104+
}
103105
}
104106
}
105107
}
106108

107-
return location.pathname;
108-
};
109+
return [location.pathname, 'url'];
110+
}
109111

110112
export function withSentryReactRouterV6Routing<P extends Record<string, any>, R extends React.FC<P>>(Routes: R): R {
111113
if (
@@ -136,7 +138,9 @@ export function withSentryReactRouterV6Routing<P extends Record<string, any>, R
136138
isBaseLocation = true;
137139

138140
if (activeTransaction) {
139-
activeTransaction.setName(getTransactionName(routes, location, _matchRoutes));
141+
const [name, source] = getNormalizedName(routes, location, _matchRoutes);
142+
activeTransaction.setName(name);
143+
activeTransaction.setMetadata({ source });
140144
}
141145

142146
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -156,10 +160,14 @@ export function withSentryReactRouterV6Routing<P extends Record<string, any>, R
156160
activeTransaction.finish();
157161
}
158162

163+
const [name, source] = getNormalizedName(routes, location, _matchRoutes);
159164
activeTransaction = _customStartTransaction({
160-
name: getTransactionName(routes, location, _matchRoutes),
165+
name,
161166
op: 'navigation',
162167
tags: SENTRY_TAGS,
168+
metadata: {
169+
source,
170+
},
163171
});
164172
}
165173
}, [props.children, location, navigationType, isBaseLocation]);

packages/react/test/reactrouterv6.test.tsx

+12-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ describe('React Router v6', () => {
1919
function createInstrumentation(_opts?: {
2020
startTransactionOnPageLoad?: boolean;
2121
startTransactionOnLocationChange?: boolean;
22-
}): [jest.Mock, { mockSetName: jest.Mock; mockFinish: jest.Mock }] {
22+
}): [jest.Mock, { mockSetName: jest.Mock; mockFinish: jest.Mock; mockSetMetadata: jest.Mock }] {
2323
const options = {
2424
matchPath: _opts ? matchPath : undefined,
2525
startTransactionOnLocationChange: true,
@@ -28,7 +28,10 @@ describe('React Router v6', () => {
2828
};
2929
const mockFinish = jest.fn();
3030
const mockSetName = jest.fn();
31-
const mockStartTransaction = jest.fn().mockReturnValue({ setName: mockSetName, finish: mockFinish });
31+
const mockSetMetadata = jest.fn();
32+
const mockStartTransaction = jest
33+
.fn()
34+
.mockReturnValue({ setName: mockSetName, finish: mockFinish, setMetadata: mockSetMetadata });
3235

3336
reactRouterV6Instrumentation(
3437
React.useEffect,
@@ -37,7 +40,7 @@ describe('React Router v6', () => {
3740
createRoutesFromChildren,
3841
matchRoutes,
3942
)(mockStartTransaction, options.startTransactionOnPageLoad, options.startTransactionOnLocationChange);
40-
return [mockStartTransaction, { mockSetName, mockFinish }];
43+
return [mockStartTransaction, { mockSetName, mockFinish, mockSetMetadata }];
4144
}
4245

4346
it('starts a pageload transaction', () => {
@@ -57,6 +60,7 @@ describe('React Router v6', () => {
5760
name: '/',
5861
op: 'pageload',
5962
tags: { 'routing.instrumentation': 'react-router-v6' },
63+
metadata: { source: 'url' },
6064
});
6165
});
6266

@@ -93,6 +97,7 @@ describe('React Router v6', () => {
9397
name: '/',
9498
op: 'pageload',
9599
tags: { 'routing.instrumentation': 'react-router-v6' },
100+
metadata: { source: 'url' },
96101
});
97102
});
98103

@@ -114,6 +119,7 @@ describe('React Router v6', () => {
114119
name: '/about',
115120
op: 'navigation',
116121
tags: { 'routing.instrumentation': 'react-router-v6' },
122+
metadata: { source: 'route' },
117123
});
118124
});
119125

@@ -137,6 +143,7 @@ describe('React Router v6', () => {
137143
name: '/about/us',
138144
op: 'navigation',
139145
tags: { 'routing.instrumentation': 'react-router-v6' },
146+
metadata: { source: 'route' },
140147
});
141148
});
142149

@@ -160,6 +167,7 @@ describe('React Router v6', () => {
160167
name: '/about/:page',
161168
op: 'navigation',
162169
tags: { 'routing.instrumentation': 'react-router-v6' },
170+
metadata: { source: 'route' },
163171
});
164172
});
165173

@@ -185,6 +193,7 @@ describe('React Router v6', () => {
185193
name: '/stores/:storeId/products/:productId',
186194
op: 'navigation',
187195
tags: { 'routing.instrumentation': 'react-router-v6' },
196+
metadata: { source: 'route' },
188197
});
189198
});
190199
});

0 commit comments

Comments
 (0)