Skip to content

Commit 2227b27

Browse files
authored
feat(react): Add reactRouterV3BrowserTracingIntegration for react router v3 (getsentry#10489)
To replace the routing instrumentation. There is a _small_ issue here, which is that we do not set the `from` attribute for the first navigation after the pageload (as technically we are calling instrument twice there...) - IMHO that's acceptable, we don't really have a `from` field anyhow in other instrumentations, so we may even think about removing this I'd say...
1 parent e4806d1 commit 2227b27

File tree

3 files changed

+298
-63
lines changed

3 files changed

+298
-63
lines changed

packages/react/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ export { Profiler, withProfiler, useProfiler } from './profiler';
55
export type { ErrorBoundaryProps, FallbackRender } from './errorboundary';
66
export { ErrorBoundary, withErrorBoundary } from './errorboundary';
77
export { createReduxEnhancer } from './redux';
8-
export { reactRouterV3Instrumentation } from './reactrouterv3';
8+
export {
9+
// eslint-disable-next-line deprecation/deprecation
10+
reactRouterV3Instrumentation,
11+
reactRouterV3BrowserTracingIntegration,
12+
} from './reactrouterv3';
913
export {
1014
// eslint-disable-next-line deprecation/deprecation
1115
reactRouterV4Instrumentation,

packages/react/src/reactrouterv3.ts

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
1-
import { WINDOW } from '@sentry/browser';
2-
import type { Primitive, Transaction, TransactionContext, TransactionSource } from '@sentry/types';
1+
import {
2+
WINDOW,
3+
browserTracingIntegration,
4+
startBrowserTracingNavigationSpan,
5+
startBrowserTracingPageLoadSpan,
6+
} from '@sentry/browser';
7+
import {
8+
SEMANTIC_ATTRIBUTE_SENTRY_OP,
9+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
10+
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
11+
} from '@sentry/core';
12+
import type {
13+
Integration,
14+
SpanAttributes,
15+
StartSpanOptions,
16+
Transaction,
17+
TransactionContext,
18+
TransactionSource,
19+
} from '@sentry/types';
320

421
import type { Location, ReactRouterInstrumentation } from './types';
522

@@ -21,13 +38,61 @@ export type Match = (
2138

2239
type ReactRouterV3TransactionSource = Extract<TransactionSource, 'url' | 'route'>;
2340

41+
interface ReactRouterOptions {
42+
history: HistoryV3;
43+
routes: Route[];
44+
match: Match;
45+
}
46+
47+
/**
48+
* A browser tracing integration that uses React Router v3 to instrument navigations.
49+
* Expects `history` (and optionally `routes` and `matchPath`) to be passed as options.
50+
*/
51+
export function reactRouterV3BrowserTracingIntegration(
52+
options: Parameters<typeof browserTracingIntegration>[0] & ReactRouterOptions,
53+
): Integration {
54+
const integration = browserTracingIntegration({
55+
...options,
56+
instrumentPageLoad: false,
57+
instrumentNavigation: false,
58+
});
59+
60+
const { history, routes, match, instrumentPageLoad = true, instrumentNavigation = true } = options;
61+
62+
return {
63+
...integration,
64+
afterAllSetup(client) {
65+
integration.afterAllSetup(client);
66+
67+
const startPageloadCallback = (startSpanOptions: StartSpanOptions): undefined => {
68+
startBrowserTracingPageLoadSpan(client, startSpanOptions);
69+
return undefined;
70+
};
71+
72+
const startNavigationCallback = (startSpanOptions: StartSpanOptions): undefined => {
73+
startBrowserTracingNavigationSpan(client, startSpanOptions);
74+
return undefined;
75+
};
76+
77+
// eslint-disable-next-line deprecation/deprecation
78+
const instrumentation = reactRouterV3Instrumentation(history, routes, match);
79+
80+
// Now instrument page load & navigation with correct settings
81+
instrumentation(startPageloadCallback, instrumentPageLoad, false);
82+
instrumentation(startNavigationCallback, false, instrumentNavigation);
83+
},
84+
};
85+
}
86+
2487
/**
2588
* Creates routing instrumentation for React Router v3
2689
* Works for React Router >= 3.2.0 and < 4.0.0
2790
*
2891
* @param history object from the `history` library
2992
* @param routes a list of all routes, should be
3093
* @param match `Router.match` utility
94+
*
95+
* @deprecated Use `reactRouterV3BrowserTracingIntegration()` instead
3196
*/
3297
export function reactRouterV3Instrumentation(
3398
history: HistoryV3,
@@ -52,13 +117,10 @@ export function reactRouterV3Instrumentation(
52117
prevName = localName;
53118
activeTransaction = startTransaction({
54119
name: prevName,
55-
op: 'pageload',
56-
origin: 'auto.pageload.react.reactrouterv3',
57-
tags: {
58-
'routing.instrumentation': 'react-router-v3',
59-
},
60-
metadata: {
61-
source,
120+
attributes: {
121+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
122+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.react.reactrouter_v3',
123+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
62124
},
63125
});
64126
},
@@ -71,22 +133,18 @@ export function reactRouterV3Instrumentation(
71133
if (activeTransaction) {
72134
activeTransaction.end();
73135
}
74-
const tags: Record<string, Primitive> = {
75-
'routing.instrumentation': 'react-router-v3',
76-
};
77-
if (prevName) {
78-
tags.from = prevName;
79-
}
80136
normalizeTransactionName(routes, location, match, (localName: string, source: TransactionSource = 'url') => {
81137
prevName = localName;
138+
139+
const attributes: SpanAttributes = {
140+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
141+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react.reactrouter_v3',
142+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
143+
};
144+
82145
activeTransaction = startTransaction({
83146
name: prevName,
84-
op: 'navigation',
85-
origin: 'auto.navigation.react.reactrouterv3',
86-
tags,
87-
metadata: {
88-
source,
89-
},
147+
attributes,
90148
});
91149
});
92150
}

0 commit comments

Comments
 (0)