Skip to content

Commit

Permalink
feat(react): Add reactRouterV3BrowserTracingIntegration for react r…
Browse files Browse the repository at this point in the history
…outer v3 (#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...
  • Loading branch information
mydea authored Feb 5, 2024
1 parent e4806d1 commit 2227b27
Show file tree
Hide file tree
Showing 3 changed files with 298 additions and 63 deletions.
6 changes: 5 additions & 1 deletion packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ export { Profiler, withProfiler, useProfiler } from './profiler';
export type { ErrorBoundaryProps, FallbackRender } from './errorboundary';
export { ErrorBoundary, withErrorBoundary } from './errorboundary';
export { createReduxEnhancer } from './redux';
export { reactRouterV3Instrumentation } from './reactrouterv3';
export {
// eslint-disable-next-line deprecation/deprecation
reactRouterV3Instrumentation,
reactRouterV3BrowserTracingIntegration,
} from './reactrouterv3';
export {
// eslint-disable-next-line deprecation/deprecation
reactRouterV4Instrumentation,
Expand Down
100 changes: 79 additions & 21 deletions packages/react/src/reactrouterv3.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
import { WINDOW } from '@sentry/browser';
import type { Primitive, Transaction, TransactionContext, TransactionSource } from '@sentry/types';
import {
WINDOW,
browserTracingIntegration,
startBrowserTracingNavigationSpan,
startBrowserTracingPageLoadSpan,
} from '@sentry/browser';
import {
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
} from '@sentry/core';
import type {
Integration,
SpanAttributes,
StartSpanOptions,
Transaction,
TransactionContext,
TransactionSource,
} from '@sentry/types';

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

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

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

interface ReactRouterOptions {
history: HistoryV3;
routes: Route[];
match: Match;
}

/**
* A browser tracing integration that uses React Router v3 to instrument navigations.
* Expects `history` (and optionally `routes` and `matchPath`) to be passed as options.
*/
export function reactRouterV3BrowserTracingIntegration(
options: Parameters<typeof browserTracingIntegration>[0] & ReactRouterOptions,
): Integration {
const integration = browserTracingIntegration({
...options,
instrumentPageLoad: false,
instrumentNavigation: false,
});

const { history, routes, match, instrumentPageLoad = true, instrumentNavigation = true } = options;

return {
...integration,
afterAllSetup(client) {
integration.afterAllSetup(client);

const startPageloadCallback = (startSpanOptions: StartSpanOptions): undefined => {
startBrowserTracingPageLoadSpan(client, startSpanOptions);
return undefined;
};

const startNavigationCallback = (startSpanOptions: StartSpanOptions): undefined => {
startBrowserTracingNavigationSpan(client, startSpanOptions);
return undefined;
};

// eslint-disable-next-line deprecation/deprecation
const instrumentation = reactRouterV3Instrumentation(history, routes, match);

// Now instrument page load & navigation with correct settings
instrumentation(startPageloadCallback, instrumentPageLoad, false);
instrumentation(startNavigationCallback, false, instrumentNavigation);
},
};
}

/**
* Creates routing instrumentation for React Router v3
* Works for React Router >= 3.2.0 and < 4.0.0
*
* @param history object from the `history` library
* @param routes a list of all routes, should be
* @param match `Router.match` utility
*
* @deprecated Use `reactRouterV3BrowserTracingIntegration()` instead
*/
export function reactRouterV3Instrumentation(
history: HistoryV3,
Expand All @@ -52,13 +117,10 @@ export function reactRouterV3Instrumentation(
prevName = localName;
activeTransaction = startTransaction({
name: prevName,
op: 'pageload',
origin: 'auto.pageload.react.reactrouterv3',
tags: {
'routing.instrumentation': 'react-router-v3',
},
metadata: {
source,
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.react.reactrouter_v3',
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
},
});
},
Expand All @@ -71,22 +133,18 @@ export function reactRouterV3Instrumentation(
if (activeTransaction) {
activeTransaction.end();
}
const tags: Record<string, Primitive> = {
'routing.instrumentation': 'react-router-v3',
};
if (prevName) {
tags.from = prevName;
}
normalizeTransactionName(routes, location, match, (localName: string, source: TransactionSource = 'url') => {
prevName = localName;

const attributes: SpanAttributes = {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react.reactrouter_v3',
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
};

activeTransaction = startTransaction({
name: prevName,
op: 'navigation',
origin: 'auto.navigation.react.reactrouterv3',
tags,
metadata: {
source,
},
attributes,
});
});
}
Expand Down
Loading

0 comments on commit 2227b27

Please sign in to comment.