123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- import { browserTracingIntegration, startBrowserTracingPageLoadSpan, startBrowserTracingNavigationSpan, WINDOW } from '@sentry/browser';
- import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getActiveSpan, getRootSpan, spanToJSON } from '@sentry/core';
- import hoistNonReactStatics from 'hoist-non-react-statics';
- import * as React from 'react';
- const _jsxFileName = "/home/runner/work/sentry-javascript/sentry-javascript/packages/react/src/reactrouter.tsx";
- // We need to disable eslint no-explict-any because any is required for the
- // react-router typings.
- let activeTransaction;
- /**
- * A browser tracing integration that uses React Router v4 to instrument navigations.
- * Expects `history` (and optionally `routes` and `matchPath`) to be passed as options.
- */
- function reactRouterV4BrowserTracingIntegration(
- options,
- ) {
- const integration = browserTracingIntegration({
- ...options,
- instrumentPageLoad: false,
- instrumentNavigation: false,
- });
- const { history, routes, matchPath, instrumentPageLoad = true, instrumentNavigation = true } = options;
- return {
- ...integration,
- afterAllSetup(client) {
- integration.afterAllSetup(client);
- const startPageloadCallback = (startSpanOptions) => {
- startBrowserTracingPageLoadSpan(client, startSpanOptions);
- return undefined;
- };
- const startNavigationCallback = (startSpanOptions) => {
- startBrowserTracingNavigationSpan(client, startSpanOptions);
- return undefined;
- };
- // eslint-disable-next-line deprecation/deprecation
- const instrumentation = reactRouterV4Instrumentation(history, routes, matchPath);
- // Now instrument page load & navigation with correct settings
- instrumentation(startPageloadCallback, instrumentPageLoad, false);
- instrumentation(startNavigationCallback, false, instrumentNavigation);
- },
- };
- }
- /**
- * A browser tracing integration that uses React Router v5 to instrument navigations.
- * Expects `history` (and optionally `routes` and `matchPath`) to be passed as options.
- */
- function reactRouterV5BrowserTracingIntegration(
- options,
- ) {
- const integration = browserTracingIntegration({
- ...options,
- instrumentPageLoad: false,
- instrumentNavigation: false,
- });
- const { history, routes, matchPath } = options;
- return {
- ...integration,
- afterAllSetup(client) {
- integration.afterAllSetup(client);
- const startPageloadCallback = (startSpanOptions) => {
- startBrowserTracingPageLoadSpan(client, startSpanOptions);
- return undefined;
- };
- const startNavigationCallback = (startSpanOptions) => {
- startBrowserTracingNavigationSpan(client, startSpanOptions);
- return undefined;
- };
- // eslint-disable-next-line deprecation/deprecation
- const instrumentation = reactRouterV5Instrumentation(history, routes, matchPath);
- // Now instrument page load & navigation with correct settings
- instrumentation(startPageloadCallback, options.instrumentPageLoad, false);
- instrumentation(startNavigationCallback, false, options.instrumentNavigation);
- },
- };
- }
- /**
- * @deprecated Use `browserTracingReactRouterV4()` instead.
- */
- function reactRouterV4Instrumentation(
- history,
- routes,
- matchPath,
- ) {
- return createReactRouterInstrumentation(history, 'reactrouter_v4', routes, matchPath);
- }
- /**
- * @deprecated Use `browserTracingReactRouterV5()` instead.
- */
- function reactRouterV5Instrumentation(
- history,
- routes,
- matchPath,
- ) {
- return createReactRouterInstrumentation(history, 'reactrouter_v5', routes, matchPath);
- }
- function createReactRouterInstrumentation(
- history,
- instrumentationName,
- allRoutes = [],
- matchPath,
- ) {
- function getInitPathName() {
- if (history && history.location) {
- return history.location.pathname;
- }
- if (WINDOW && WINDOW.location) {
- return WINDOW.location.pathname;
- }
- return undefined;
- }
- /**
- * Normalizes a transaction name. Returns the new name as well as the
- * source of the transaction.
- *
- * @param pathname The initial pathname we normalize
- */
- function normalizeTransactionName(pathname) {
- if (allRoutes.length === 0 || !matchPath) {
- return [pathname, 'url'];
- }
- const branches = matchRoutes(allRoutes, pathname, matchPath);
- // eslint-disable-next-line @typescript-eslint/prefer-for-of
- for (let x = 0; x < branches.length; x++) {
- if (branches[x].match.isExact) {
- return [branches[x].match.path, 'route'];
- }
- }
- return [pathname, 'url'];
- }
- return (customStartTransaction, startTransactionOnPageLoad = true, startTransactionOnLocationChange = true) => {
- const initPathName = getInitPathName();
- if (startTransactionOnPageLoad && initPathName) {
- const [name, source] = normalizeTransactionName(initPathName);
- activeTransaction = customStartTransaction({
- name,
- attributes: {
- [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
- [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.pageload.react.${instrumentationName}`,
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
- },
- });
- }
- if (startTransactionOnLocationChange && history.listen) {
- history.listen((location, action) => {
- if (action && (action === 'PUSH' || action === 'POP')) {
- if (activeTransaction) {
- activeTransaction.end();
- }
- const [name, source] = normalizeTransactionName(location.pathname);
- activeTransaction = customStartTransaction({
- name,
- attributes: {
- [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
- [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.navigation.react.${instrumentationName}`,
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
- },
- });
- }
- });
- }
- };
- }
- /**
- * Matches a set of routes to a pathname
- * Based on implementation from
- */
- function matchRoutes(
- routes,
- pathname,
- matchPath,
- branch = [],
- ) {
- routes.some(route => {
- const match = route.path
- ? matchPath(pathname, route)
- : branch.length
- ? branch[branch.length - 1].match // use parent match
- : computeRootMatch(pathname); // use default "root" match
- if (match) {
- branch.push({ route, match });
- if (route.routes) {
- matchRoutes(route.routes, pathname, matchPath, branch);
- }
- }
- return !!match;
- });
- return branch;
- }
- function computeRootMatch(pathname) {
- return { path: '/', url: '/', params: {}, isExact: pathname === '/' };
- }
- /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access */
- function withSentryRouting(Route) {
- const componentDisplayName = (Route ).displayName || (Route ).name;
- const activeRootSpan = getActiveRootSpan();
- const WrappedRoute = (props) => {
- if (activeRootSpan && props && props.computedMatch && props.computedMatch.isExact) {
- activeRootSpan.updateName(props.computedMatch.path);
- activeRootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
- }
- // @ts-expect-error Setting more specific React Component typing for `R` generic above
- // will break advanced type inference done by react router params:
- // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/13dc4235c069e25fe7ee16e11f529d909f9f3ff8/types/react-router/index.d.ts#L154-L164
- return React.createElement(Route, { ...props, __self: this, __source: {fileName: _jsxFileName, lineNumber: 277}} );
- };
- WrappedRoute.displayName = `sentryRoute(${componentDisplayName})`;
- hoistNonReactStatics(WrappedRoute, Route);
- // @ts-expect-error Setting more specific React Component typing for `R` generic above
- // will break advanced type inference done by react router params:
- // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/13dc4235c069e25fe7ee16e11f529d909f9f3ff8/types/react-router/index.d.ts#L154-L164
- return WrappedRoute;
- }
- /* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access */
- function getActiveRootSpan() {
- // Legacy behavior for "old" react router instrumentation
- if (activeTransaction) {
- return activeTransaction;
- }
- const span = getActiveSpan();
- const rootSpan = span ? getRootSpan(span) : undefined;
- if (!rootSpan) {
- return undefined;
- }
- const op = spanToJSON(rootSpan).op;
- // Only use this root span if it is a pageload or navigation span
- return op === 'navigation' || op === 'pageload' ? rootSpan : undefined;
- }
- export { reactRouterV4BrowserTracingIntegration, reactRouterV4Instrumentation, reactRouterV5BrowserTracingIntegration, reactRouterV5Instrumentation, withSentryRouting };
- //# sourceMappingURL=reactrouter.js.map
|