@sentry/react-router 10.40.0 → 10.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/client/createClientInstrumentation.js +18 -1
- package/build/cjs/client/createClientInstrumentation.js.map +1 -1
- package/build/cjs/server/createServerInstrumentation.js +73 -49
- package/build/cjs/server/createServerInstrumentation.js.map +1 -1
- package/build/cjs/server/instrumentation/reactRouter.js +23 -7
- package/build/cjs/server/instrumentation/reactRouter.js.map +1 -1
- package/build/cjs/server/integration/reactRouterServer.js +11 -8
- package/build/cjs/server/integration/reactRouterServer.js.map +1 -1
- package/build/cjs/server/serverBuild.js +54 -0
- package/build/cjs/server/serverBuild.js.map +1 -0
- package/build/cjs/server/serverGlobals.js +19 -0
- package/build/cjs/server/serverGlobals.js.map +1 -1
- package/build/cjs/vite/makeServerBuildCapturePlugin.js +43 -0
- package/build/cjs/vite/makeServerBuildCapturePlugin.js.map +1 -0
- package/build/cjs/vite/plugin.js +2 -0
- package/build/cjs/vite/plugin.js.map +1 -1
- package/build/esm/client/createClientInstrumentation.js +18 -1
- package/build/esm/client/createClientInstrumentation.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/server/createServerInstrumentation.js +74 -50
- package/build/esm/server/createServerInstrumentation.js.map +1 -1
- package/build/esm/server/instrumentation/reactRouter.js +25 -9
- package/build/esm/server/instrumentation/reactRouter.js.map +1 -1
- package/build/esm/server/integration/reactRouterServer.js +12 -9
- package/build/esm/server/integration/reactRouterServer.js.map +1 -1
- package/build/esm/server/serverBuild.js +48 -0
- package/build/esm/server/serverBuild.js.map +1 -0
- package/build/esm/server/serverGlobals.js +18 -1
- package/build/esm/server/serverGlobals.js.map +1 -1
- package/build/esm/vite/makeServerBuildCapturePlugin.js +41 -0
- package/build/esm/vite/makeServerBuildCapturePlugin.js.map +1 -0
- package/build/esm/vite/plugin.js +2 -0
- package/build/esm/vite/plugin.js.map +1 -1
- package/build/types/client/createClientInstrumentation.d.ts.map +1 -1
- package/build/types/server/createServerInstrumentation.d.ts.map +1 -1
- package/build/types/server/instrumentation/reactRouter.d.ts.map +1 -1
- package/build/types/server/integration/reactRouterServer.d.ts.map +1 -1
- package/build/types/server/serverBuild.d.ts +28 -0
- package/build/types/server/serverBuild.d.ts.map +1 -0
- package/build/types/server/serverGlobals.d.ts +10 -0
- package/build/types/server/serverGlobals.d.ts.map +1 -1
- package/build/types/vite/makeServerBuildCapturePlugin.d.ts +6 -0
- package/build/types/vite/makeServerBuildCapturePlugin.d.ts.map +1 -0
- package/build/types/vite/plugin.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -10,6 +10,9 @@ const WINDOW = core.GLOBAL_OBJ ;
|
|
|
10
10
|
// Tracks active numeric navigation span to prevent duplicate spans when popstate fires
|
|
11
11
|
let currentNumericNavigationSpan;
|
|
12
12
|
|
|
13
|
+
// Per-request middleware counters, keyed by Request
|
|
14
|
+
const middlewareCountersMap = new WeakMap();
|
|
15
|
+
|
|
13
16
|
const SENTRY_CLIENT_INSTRUMENTATION_FLAG = '__sentryReactRouterClientInstrumentationUsed';
|
|
14
17
|
// Intentionally never reset - once set, instrumentation API handles all navigations for the session.
|
|
15
18
|
const SENTRY_NAVIGATE_HOOK_INVOKED_FLAG = '__sentryReactRouterNavigateHookInvoked';
|
|
@@ -191,6 +194,8 @@ function createSentryClientInstrumentation(
|
|
|
191
194
|
},
|
|
192
195
|
|
|
193
196
|
route(route) {
|
|
197
|
+
const routeId = route.id;
|
|
198
|
+
|
|
194
199
|
route.instrument({
|
|
195
200
|
async loader(callLoader, info) {
|
|
196
201
|
const urlPath = utils.getPathFromRequest(info.request);
|
|
@@ -244,12 +249,24 @@ function createSentryClientInstrumentation(
|
|
|
244
249
|
const urlPath = utils.getPathFromRequest(info.request);
|
|
245
250
|
const routePattern = utils.normalizeRoutePath(utils.getPattern(info)) || urlPath;
|
|
246
251
|
|
|
252
|
+
let counters = middlewareCountersMap.get(info.request);
|
|
253
|
+
if (!counters) {
|
|
254
|
+
counters = {};
|
|
255
|
+
middlewareCountersMap.set(info.request, counters);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const middlewareIndex = counters[routeId] ?? 0;
|
|
259
|
+
counters[routeId] = middlewareIndex + 1;
|
|
260
|
+
|
|
247
261
|
await core.startSpan(
|
|
248
262
|
{
|
|
249
|
-
name:
|
|
263
|
+
name: `middleware ${routeId}`,
|
|
250
264
|
attributes: {
|
|
251
265
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_middleware',
|
|
252
266
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',
|
|
267
|
+
'react_router.route.id': routeId,
|
|
268
|
+
'http.route': routePattern,
|
|
269
|
+
'react_router.middleware.index': middlewareIndex,
|
|
253
270
|
},
|
|
254
271
|
},
|
|
255
272
|
async span => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createClientInstrumentation.js","sources":["../../../src/client/createClientInstrumentation.ts"],"sourcesContent":["import { startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getClient,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n SPAN_STATUS_ERROR,\n startSpan,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport type { ClientInstrumentation, InstrumentableRoute, InstrumentableRouter } from '../common/types';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\n// Tracks active numeric navigation span to prevent duplicate spans when popstate fires\nlet currentNumericNavigationSpan: Span | undefined;\n\nconst SENTRY_CLIENT_INSTRUMENTATION_FLAG = '__sentryReactRouterClientInstrumentationUsed';\n// Intentionally never reset - once set, instrumentation API handles all navigations for the session.\nconst SENTRY_NAVIGATE_HOOK_INVOKED_FLAG = '__sentryReactRouterNavigateHookInvoked';\nconst SENTRY_POPSTATE_LISTENER_ADDED_FLAG = '__sentryReactRouterPopstateListenerAdded';\n\ntype GlobalObjWithFlags = typeof GLOBAL_OBJ & {\n [SENTRY_CLIENT_INSTRUMENTATION_FLAG]?: boolean;\n [SENTRY_NAVIGATE_HOOK_INVOKED_FLAG]?: boolean;\n [SENTRY_POPSTATE_LISTENER_ADDED_FLAG]?: boolean;\n};\n\nconst GLOBAL_WITH_FLAGS = GLOBAL_OBJ as GlobalObjWithFlags;\n\n/**\n * Options for creating Sentry client instrumentation.\n */\nexport interface CreateSentryClientInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * Set to `false` to avoid duplicates if using custom error handlers.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry client instrumentation for React Router's instrumentation API.\n * @experimental\n */\nexport function createSentryClientInstrumentation(\n options: CreateSentryClientInstrumentationOptions = {},\n): ClientInstrumentation {\n const { captureErrors = true } = options;\n\n DEBUG_BUILD && debug.log('React Router client instrumentation API created.');\n\n return {\n router(router: InstrumentableRouter) {\n // Set the flag when React Router actually invokes our instrumentation.\n // This ensures the flag is only set in Library Mode (where hooks run),\n // not in Framework Mode (where hooks are never called).\n // See: https://github.com/remix-run/react-router/discussions/13749\n GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG] = true;\n DEBUG_BUILD && debug.log('React Router client instrumentation API router hook registered.');\n\n // Add popstate listener for browser back/forward navigation (persists for session, one listener only)\n if (!GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] && WINDOW.addEventListener) {\n GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] = true;\n\n WINDOW.addEventListener('popstate', () => {\n const client = getClient();\n if (!client) {\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n const pathname = WINDOW.location?.pathname || '/';\n\n // If there's an active numeric navigation span, update it instead of creating a duplicate\n if (currentNumericNavigationSpan) {\n if (currentNumericNavigationSpan.isRecording()) {\n currentNumericNavigationSpan.updateName(pathname);\n }\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n // Only create a new span for actual browser back/forward button clicks\n startBrowserTracingNavigationSpan(client, {\n name: pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'browser.popstate',\n },\n });\n });\n\n DEBUG_BUILD && debug.log('React Router popstate listener registered for browser back/forward navigation.');\n }\n\n router.instrument({\n async navigate(callNavigate, info) {\n // navigate(0) triggers a page reload - skip span creation, but still capture errors\n // (navigation can be rejected before reload, e.g., by a navigation guard)\n if (info.to === 0) {\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': info.currentUrl,\n });\n }\n return;\n }\n\n GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG] = true;\n\n // Handle numeric navigations (navigate(-1), navigate(1), etc.)\n if (typeof info.to === 'number') {\n const client = getClient();\n let navigationSpan;\n\n if (client) {\n const navigationType = info.to < 0 ? 'router.back' : 'router.forward';\n const currentPathname = WINDOW.location?.pathname || info.currentUrl;\n\n navigationSpan = startBrowserTracingNavigationSpan(client, {\n name: currentPathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': navigationType,\n },\n });\n\n // Store ref so popstate listener can update it instead of creating a duplicate\n currentNumericNavigationSpan = navigationSpan;\n }\n\n try {\n const result = await callNavigate();\n\n if (navigationSpan && WINDOW.location) {\n navigationSpan.updateName(WINDOW.location.pathname);\n }\n\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': WINDOW.location?.pathname || info.currentUrl,\n });\n }\n } finally {\n currentNumericNavigationSpan = undefined;\n }\n return;\n }\n\n // Handle string navigations (e.g., navigate('/about'))\n const client = getClient();\n const toPath = String(info.to);\n let navigationSpan;\n\n if (client) {\n navigationSpan = startBrowserTracingNavigationSpan(client, {\n name: toPath,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'router.navigate',\n },\n });\n }\n\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': toPath,\n });\n }\n return;\n },\n\n async fetch(callFetch, info) {\n await startSpan(\n {\n name: `Fetcher ${info.fetcherKey}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.fetcher',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callFetch();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.fetcher', {\n 'http.url': info.href,\n });\n }\n },\n );\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_loader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_loader', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_action',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_action', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_middleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_middleware', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the client.\n * @experimental\n */\nexport function isClientInstrumentationApiUsed(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG];\n}\n\n/**\n * Check if React Router's instrumentation API's navigate hook was invoked.\n * @experimental\n */\nexport function isNavigateHookInvoked(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG];\n}\n"],"names":["GLOBAL_OBJ","DEBUG_BUILD","debug","getClient","startBrowserTracingNavigationSpan","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","captureInstrumentationError","SPAN_STATUS_ERROR","startSpan","getPathFromRequest","normalizeRoutePath","getPattern"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createClientInstrumentation.js","sources":["../../../src/client/createClientInstrumentation.ts"],"sourcesContent":["import { startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getClient,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n SPAN_STATUS_ERROR,\n startSpan,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport type { ClientInstrumentation, InstrumentableRoute, InstrumentableRouter } from '../common/types';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\n// Tracks active numeric navigation span to prevent duplicate spans when popstate fires\nlet currentNumericNavigationSpan: Span | undefined;\n\n// Per-request middleware counters, keyed by Request\nconst middlewareCountersMap = new WeakMap<object, Record<string, number>>();\n\nconst SENTRY_CLIENT_INSTRUMENTATION_FLAG = '__sentryReactRouterClientInstrumentationUsed';\n// Intentionally never reset - once set, instrumentation API handles all navigations for the session.\nconst SENTRY_NAVIGATE_HOOK_INVOKED_FLAG = '__sentryReactRouterNavigateHookInvoked';\nconst SENTRY_POPSTATE_LISTENER_ADDED_FLAG = '__sentryReactRouterPopstateListenerAdded';\n\ntype GlobalObjWithFlags = typeof GLOBAL_OBJ & {\n [SENTRY_CLIENT_INSTRUMENTATION_FLAG]?: boolean;\n [SENTRY_NAVIGATE_HOOK_INVOKED_FLAG]?: boolean;\n [SENTRY_POPSTATE_LISTENER_ADDED_FLAG]?: boolean;\n};\n\nconst GLOBAL_WITH_FLAGS = GLOBAL_OBJ as GlobalObjWithFlags;\n\n/**\n * Options for creating Sentry client instrumentation.\n */\nexport interface CreateSentryClientInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * Set to `false` to avoid duplicates if using custom error handlers.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry client instrumentation for React Router's instrumentation API.\n * @experimental\n */\nexport function createSentryClientInstrumentation(\n options: CreateSentryClientInstrumentationOptions = {},\n): ClientInstrumentation {\n const { captureErrors = true } = options;\n\n DEBUG_BUILD && debug.log('React Router client instrumentation API created.');\n\n return {\n router(router: InstrumentableRouter) {\n // Set the flag when React Router actually invokes our instrumentation.\n // This ensures the flag is only set in Library Mode (where hooks run),\n // not in Framework Mode (where hooks are never called).\n // See: https://github.com/remix-run/react-router/discussions/13749\n GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG] = true;\n DEBUG_BUILD && debug.log('React Router client instrumentation API router hook registered.');\n\n // Add popstate listener for browser back/forward navigation (persists for session, one listener only)\n if (!GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] && WINDOW.addEventListener) {\n GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] = true;\n\n WINDOW.addEventListener('popstate', () => {\n const client = getClient();\n if (!client) {\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n const pathname = WINDOW.location?.pathname || '/';\n\n // If there's an active numeric navigation span, update it instead of creating a duplicate\n if (currentNumericNavigationSpan) {\n if (currentNumericNavigationSpan.isRecording()) {\n currentNumericNavigationSpan.updateName(pathname);\n }\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n // Only create a new span for actual browser back/forward button clicks\n startBrowserTracingNavigationSpan(client, {\n name: pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'browser.popstate',\n },\n });\n });\n\n DEBUG_BUILD && debug.log('React Router popstate listener registered for browser back/forward navigation.');\n }\n\n router.instrument({\n async navigate(callNavigate, info) {\n // navigate(0) triggers a page reload - skip span creation, but still capture errors\n // (navigation can be rejected before reload, e.g., by a navigation guard)\n if (info.to === 0) {\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': info.currentUrl,\n });\n }\n return;\n }\n\n GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG] = true;\n\n // Handle numeric navigations (navigate(-1), navigate(1), etc.)\n if (typeof info.to === 'number') {\n const client = getClient();\n let navigationSpan;\n\n if (client) {\n const navigationType = info.to < 0 ? 'router.back' : 'router.forward';\n const currentPathname = WINDOW.location?.pathname || info.currentUrl;\n\n navigationSpan = startBrowserTracingNavigationSpan(client, {\n name: currentPathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': navigationType,\n },\n });\n\n // Store ref so popstate listener can update it instead of creating a duplicate\n currentNumericNavigationSpan = navigationSpan;\n }\n\n try {\n const result = await callNavigate();\n\n if (navigationSpan && WINDOW.location) {\n navigationSpan.updateName(WINDOW.location.pathname);\n }\n\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': WINDOW.location?.pathname || info.currentUrl,\n });\n }\n } finally {\n currentNumericNavigationSpan = undefined;\n }\n return;\n }\n\n // Handle string navigations (e.g., navigate('/about'))\n const client = getClient();\n const toPath = String(info.to);\n let navigationSpan;\n\n if (client) {\n navigationSpan = startBrowserTracingNavigationSpan(client, {\n name: toPath,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'router.navigate',\n },\n });\n }\n\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': toPath,\n });\n }\n return;\n },\n\n async fetch(callFetch, info) {\n await startSpan(\n {\n name: `Fetcher ${info.fetcherKey}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.fetcher',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callFetch();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.fetcher', {\n 'http.url': info.href,\n });\n }\n },\n );\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n const routeId = route.id;\n\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_loader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_loader', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_action',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_action', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n let counters = middlewareCountersMap.get(info.request);\n if (!counters) {\n counters = {};\n middlewareCountersMap.set(info.request, counters);\n }\n\n const middlewareIndex = counters[routeId] ?? 0;\n counters[routeId] = middlewareIndex + 1;\n\n await startSpan(\n {\n name: `middleware ${routeId}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_middleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n 'react_router.route.id': routeId,\n 'http.route': routePattern,\n 'react_router.middleware.index': middlewareIndex,\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_middleware', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the client.\n * @experimental\n */\nexport function isClientInstrumentationApiUsed(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG];\n}\n\n/**\n * Check if React Router's instrumentation API's navigate hook was invoked.\n * @experimental\n */\nexport function isNavigateHookInvoked(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG];\n}\n"],"names":["GLOBAL_OBJ","DEBUG_BUILD","debug","getClient","startBrowserTracingNavigationSpan","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","captureInstrumentationError","SPAN_STATUS_ERROR","startSpan","getPathFromRequest","normalizeRoutePath","getPattern"],"mappings":"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"}
|
|
@@ -6,8 +6,11 @@ const semanticConventions = require('@opentelemetry/semantic-conventions');
|
|
|
6
6
|
const core = require('@sentry/core');
|
|
7
7
|
const debugBuild = require('../common/debug-build.js');
|
|
8
8
|
const utils = require('../common/utils.js');
|
|
9
|
+
const serverBuild = require('./serverBuild.js');
|
|
9
10
|
const serverGlobals = require('./serverGlobals.js');
|
|
10
11
|
|
|
12
|
+
const MIDDLEWARE_COUNTER_KEY = api.createContextKey('sentry_react_router_middleware_counter');
|
|
13
|
+
|
|
11
14
|
/**
|
|
12
15
|
* Options for creating Sentry server instrumentation.
|
|
13
16
|
*/
|
|
@@ -32,61 +35,68 @@ function createSentryServerInstrumentation(
|
|
|
32
35
|
const activeSpan = core.getActiveSpan();
|
|
33
36
|
const existingRootSpan = activeSpan ? core.getRootSpan(activeSpan) : undefined;
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
const counterStore = { counters: {} };
|
|
39
|
+
const ctx = api.context.active().setValue(MIDDLEWARE_COUNTER_KEY, counterStore);
|
|
40
|
+
|
|
41
|
+
await api.context.with(ctx, async () => {
|
|
42
|
+
if (existingRootSpan) {
|
|
43
|
+
core.updateSpanName(existingRootSpan, `${info.request.method} ${pathname}`);
|
|
44
|
+
existingRootSpan.setAttributes({
|
|
45
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',
|
|
46
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',
|
|
47
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const result = await handleRequest();
|
|
52
|
+
if (result.status === 'error' && result.error instanceof Error) {
|
|
53
|
+
existingRootSpan.setStatus({ code: core.SPAN_STATUS_ERROR, message: 'internal_error' });
|
|
54
|
+
utils.captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {
|
|
55
|
+
'http.method': info.request.method,
|
|
56
|
+
'http.url': pathname,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
} finally {
|
|
60
|
+
await core.flushIfServerless();
|
|
51
61
|
}
|
|
52
|
-
}
|
|
53
|
-
await core.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
'url.path': pathname,
|
|
66
|
-
'url.full': info.request.url,
|
|
62
|
+
} else {
|
|
63
|
+
await core.startSpan(
|
|
64
|
+
{
|
|
65
|
+
name: `${info.request.method} ${pathname}`,
|
|
66
|
+
forceTransaction: true,
|
|
67
|
+
attributes: {
|
|
68
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',
|
|
69
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',
|
|
70
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
|
|
71
|
+
'http.request.method': info.request.method,
|
|
72
|
+
'url.path': pathname,
|
|
73
|
+
'url.full': info.request.url,
|
|
74
|
+
},
|
|
67
75
|
},
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
76
|
+
async span => {
|
|
77
|
+
try {
|
|
78
|
+
const result = await handleRequest();
|
|
79
|
+
if (result.status === 'error' && result.error instanceof Error) {
|
|
80
|
+
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: 'internal_error' });
|
|
81
|
+
utils.captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {
|
|
82
|
+
'http.method': info.request.method,
|
|
83
|
+
'http.url': pathname,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
} finally {
|
|
87
|
+
await core.flushIfServerless();
|
|
78
88
|
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
);
|
|
84
|
-
}
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
85
93
|
},
|
|
86
94
|
});
|
|
87
95
|
},
|
|
88
96
|
|
|
89
97
|
route(route) {
|
|
98
|
+
const routeId = route.id;
|
|
99
|
+
|
|
90
100
|
route.instrument({
|
|
91
101
|
async loader(callLoader, info) {
|
|
92
102
|
const urlPath = utils.getPathFromRequest(info.request);
|
|
@@ -147,15 +157,29 @@ function createSentryServerInstrumentation(
|
|
|
147
157
|
const pattern = utils.getPattern(info);
|
|
148
158
|
const routePattern = utils.normalizeRoutePath(pattern) || urlPath;
|
|
149
159
|
|
|
150
|
-
// Update root span with parameterized route (same as loader/action)
|
|
151
160
|
updateRootSpanWithRoute(info.request.method, pattern, urlPath);
|
|
152
161
|
|
|
162
|
+
const counterStore = api.context.active().getValue(MIDDLEWARE_COUNTER_KEY)
|
|
163
|
+
|
|
164
|
+
;
|
|
165
|
+
let middlewareIndex = 0;
|
|
166
|
+
if (counterStore) {
|
|
167
|
+
middlewareIndex = counterStore.counters[routeId] ?? 0;
|
|
168
|
+
counterStore.counters[routeId] = middlewareIndex + 1;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const middlewareName = serverBuild.getMiddlewareName(routeId, middlewareIndex);
|
|
172
|
+
|
|
153
173
|
await core.startSpan(
|
|
154
174
|
{
|
|
155
|
-
name:
|
|
175
|
+
name: `middleware ${middlewareName || routeId}`,
|
|
156
176
|
attributes: {
|
|
157
177
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.middleware',
|
|
158
178
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',
|
|
179
|
+
'react_router.route.id': routeId,
|
|
180
|
+
[semanticConventions.ATTR_HTTP_ROUTE]: routePattern,
|
|
181
|
+
...(middlewareName && { 'react_router.middleware.name': middlewareName }),
|
|
182
|
+
'react_router.middleware.index': middlewareIndex,
|
|
159
183
|
},
|
|
160
184
|
},
|
|
161
185
|
async span => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServerInstrumentation.js","sources":["../../../src/server/createServerInstrumentation.ts"],"sourcesContent":["import { context } from '@opentelemetry/api';\nimport { getRPCMetadata, RPCType } from '@opentelemetry/core';\nimport { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport {\n debug,\n flushIfServerless,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n SPAN_STATUS_ERROR,\n startSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport type { InstrumentableRequestHandler, InstrumentableRoute, ServerInstrumentation } from '../common/types';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\nimport { markInstrumentationApiUsed } from './serverGlobals';\n\n// Re-export for backward compatibility and external use\nexport { isInstrumentationApiUsed } from './serverGlobals';\n\n/**\n * Options for creating Sentry server instrumentation.\n */\nexport interface CreateSentryServerInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry server instrumentation for React Router's instrumentation API.\n * @experimental\n */\nexport function createSentryServerInstrumentation(\n options: CreateSentryServerInstrumentationOptions = {},\n): ServerInstrumentation {\n const { captureErrors = true } = options;\n\n markInstrumentationApiUsed();\n DEBUG_BUILD && debug.log('React Router server instrumentation API enabled.');\n\n return {\n handler(handler: InstrumentableRequestHandler) {\n handler.instrument({\n async request(handleRequest, info) {\n const pathname = getPathFromRequest(info.request);\n const activeSpan = getActiveSpan();\n const existingRootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n if (existingRootSpan) {\n updateSpanName(existingRootSpan, `${info.request.method} ${pathname}`);\n existingRootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n });\n\n try {\n const result = await handleRequest();\n if (result.status === 'error' && result.error instanceof Error) {\n existingRootSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {\n 'http.method': info.request.method,\n 'http.url': pathname,\n });\n }\n } finally {\n await flushIfServerless();\n }\n } else {\n await startSpan(\n {\n name: `${info.request.method} ${pathname}`,\n forceTransaction: true,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n 'http.request.method': info.request.method,\n 'url.path': pathname,\n 'url.full': info.request.url,\n },\n },\n async span => {\n try {\n const result = await handleRequest();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {\n 'http.method': info.request.method,\n 'http.url': pathname,\n });\n }\n } finally {\n await flushIfServerless();\n }\n },\n );\n }\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.loader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.loader', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.action',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.action', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n\n // Update root span with parameterized route (same as loader/action)\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.middleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.middleware', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\nfunction updateRootSpanWithRoute(method: string, pattern: string | undefined, urlPath: string): void {\n const activeSpan = getActiveSpan();\n if (!activeSpan) return;\n const rootSpan = getRootSpan(activeSpan);\n if (!rootSpan) return;\n\n // Skip update if URL path is invalid (failed to parse)\n if (!urlPath || urlPath === '<unknown>') {\n DEBUG_BUILD && debug.warn('Cannot update span with invalid URL path:', urlPath);\n return;\n }\n\n const hasPattern = !!pattern;\n const routeName = hasPattern ? normalizeRoutePath(pattern) || urlPath : urlPath;\n\n const rpcMetadata = getRPCMetadata(context.active());\n if (rpcMetadata?.type === RPCType.HTTP) {\n rpcMetadata.route = routeName;\n }\n\n const transactionName = `${method} ${routeName}`;\n updateSpanName(rootSpan, transactionName);\n rootSpan.setAttributes({\n [ATTR_HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: hasPattern ? 'route' : 'url',\n });\n\n // Also update the scope's transaction name so errors captured during this request\n // have the correct transaction name (not the initial placeholder like \"GET *\")\n getCurrentScope().setTransactionName(transactionName);\n}\n"],"names":["markInstrumentationApiUsed","DEBUG_BUILD","debug","getPathFromRequest","getActiveSpan","getRootSpan","updateSpanName","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SPAN_STATUS_ERROR","captureInstrumentationError","flushIfServerless","startSpan","getPattern","normalizeRoutePath","getRPCMetadata","context","RPCType","ATTR_HTTP_ROUTE","getCurrentScope"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createServerInstrumentation.js","sources":["../../../src/server/createServerInstrumentation.ts"],"sourcesContent":["import { context, createContextKey } from '@opentelemetry/api';\nimport { getRPCMetadata, RPCType } from '@opentelemetry/core';\nimport { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport {\n debug,\n flushIfServerless,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n SPAN_STATUS_ERROR,\n startSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport type { InstrumentableRequestHandler, InstrumentableRoute, ServerInstrumentation } from '../common/types';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\nimport { getMiddlewareName } from './serverBuild';\nimport { markInstrumentationApiUsed } from './serverGlobals';\n\nconst MIDDLEWARE_COUNTER_KEY = createContextKey('sentry_react_router_middleware_counter');\n\n// Re-export for backward compatibility and external use\nexport { isInstrumentationApiUsed } from './serverGlobals';\n\n/**\n * Options for creating Sentry server instrumentation.\n */\nexport interface CreateSentryServerInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry server instrumentation for React Router's instrumentation API.\n * @experimental\n */\nexport function createSentryServerInstrumentation(\n options: CreateSentryServerInstrumentationOptions = {},\n): ServerInstrumentation {\n const { captureErrors = true } = options;\n\n markInstrumentationApiUsed();\n DEBUG_BUILD && debug.log('React Router server instrumentation API enabled.');\n\n return {\n handler(handler: InstrumentableRequestHandler) {\n handler.instrument({\n async request(handleRequest, info) {\n const pathname = getPathFromRequest(info.request);\n const activeSpan = getActiveSpan();\n const existingRootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n const counterStore = { counters: {} as Record<string, number> };\n const ctx = context.active().setValue(MIDDLEWARE_COUNTER_KEY, counterStore);\n\n await context.with(ctx, async () => {\n if (existingRootSpan) {\n updateSpanName(existingRootSpan, `${info.request.method} ${pathname}`);\n existingRootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n });\n\n try {\n const result = await handleRequest();\n if (result.status === 'error' && result.error instanceof Error) {\n existingRootSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {\n 'http.method': info.request.method,\n 'http.url': pathname,\n });\n }\n } finally {\n await flushIfServerless();\n }\n } else {\n await startSpan(\n {\n name: `${info.request.method} ${pathname}`,\n forceTransaction: true,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n 'http.request.method': info.request.method,\n 'url.path': pathname,\n 'url.full': info.request.url,\n },\n },\n async span => {\n try {\n const result = await handleRequest();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {\n 'http.method': info.request.method,\n 'http.url': pathname,\n });\n }\n } finally {\n await flushIfServerless();\n }\n },\n );\n }\n });\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n const routeId = route.id;\n\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.loader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.loader', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.action',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.action', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n const counterStore = context.active().getValue(MIDDLEWARE_COUNTER_KEY) as\n | { counters: Record<string, number> }\n | undefined;\n let middlewareIndex = 0;\n if (counterStore) {\n middlewareIndex = counterStore.counters[routeId] ?? 0;\n counterStore.counters[routeId] = middlewareIndex + 1;\n }\n\n const middlewareName = getMiddlewareName(routeId, middlewareIndex);\n\n await startSpan(\n {\n name: `middleware ${middlewareName || routeId}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.middleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n 'react_router.route.id': routeId,\n [ATTR_HTTP_ROUTE]: routePattern,\n ...(middlewareName && { 'react_router.middleware.name': middlewareName }),\n 'react_router.middleware.index': middlewareIndex,\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.middleware', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\nfunction updateRootSpanWithRoute(method: string, pattern: string | undefined, urlPath: string): void {\n const activeSpan = getActiveSpan();\n if (!activeSpan) return;\n const rootSpan = getRootSpan(activeSpan);\n if (!rootSpan) return;\n\n // Skip update if URL path is invalid (failed to parse)\n if (!urlPath || urlPath === '<unknown>') {\n DEBUG_BUILD && debug.warn('Cannot update span with invalid URL path:', urlPath);\n return;\n }\n\n const hasPattern = !!pattern;\n const routeName = hasPattern ? normalizeRoutePath(pattern) || urlPath : urlPath;\n\n const rpcMetadata = getRPCMetadata(context.active());\n if (rpcMetadata?.type === RPCType.HTTP) {\n rpcMetadata.route = routeName;\n }\n\n const transactionName = `${method} ${routeName}`;\n updateSpanName(rootSpan, transactionName);\n rootSpan.setAttributes({\n [ATTR_HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: hasPattern ? 'route' : 'url',\n });\n\n // Also update the scope's transaction name so errors captured during this request\n // have the correct transaction name (not the initial placeholder like \"GET *\")\n getCurrentScope().setTransactionName(transactionName);\n}\n"],"names":["createContextKey","markInstrumentationApiUsed","DEBUG_BUILD","debug","getPathFromRequest","getActiveSpan","getRootSpan","context","updateSpanName","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SPAN_STATUS_ERROR","captureInstrumentationError","flushIfServerless","startSpan","getPattern","normalizeRoutePath","getMiddlewareName","ATTR_HTTP_ROUTE","getRPCMetadata","RPCType","getCurrentScope"],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ const instrumentation = require('@opentelemetry/instrumentation');
|
|
|
4
4
|
const semanticConventions = require('@opentelemetry/semantic-conventions');
|
|
5
5
|
const core = require('@sentry/core');
|
|
6
6
|
const debugBuild = require('../../common/debug-build.js');
|
|
7
|
+
const serverBuild = require('../serverBuild.js');
|
|
7
8
|
const serverGlobals = require('../serverGlobals.js');
|
|
8
9
|
const util = require('./util.js');
|
|
9
10
|
|
|
@@ -49,9 +50,31 @@ class ReactRouterInstrumentation extends instrumentation.InstrumentationBase {
|
|
|
49
50
|
if (prop === 'createRequestHandler') {
|
|
50
51
|
const original = target[prop];
|
|
51
52
|
return function sentryWrappedCreateRequestHandler( ...args) {
|
|
53
|
+
// Capture the ServerBuild reference for middleware name lookup
|
|
54
|
+
const build = args[0];
|
|
55
|
+
if (serverBuild.isServerBuildLike(build)) {
|
|
56
|
+
serverBuild.setServerBuild(build);
|
|
57
|
+
} else if (typeof build === 'function') {
|
|
58
|
+
// Build arg can be a factory function (dev mode HMR). Wrap to capture resolved build.
|
|
59
|
+
const originalBuildFn = build ;
|
|
60
|
+
args[0] = async function sentryWrappedBuildFn() {
|
|
61
|
+
const resolvedBuild = await originalBuildFn();
|
|
62
|
+
if (serverBuild.isServerBuildLike(resolvedBuild)) {
|
|
63
|
+
serverBuild.setServerBuild(resolvedBuild);
|
|
64
|
+
}
|
|
65
|
+
return resolvedBuild;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
52
69
|
const originalRequestHandler = original.apply(this, args);
|
|
53
70
|
|
|
54
71
|
return async function sentryWrappedRequestHandler(request, initialContext) {
|
|
72
|
+
// Skip OTEL span creation when instrumentation API is active or when span creation is not enabled.
|
|
73
|
+
// Checked per-request (not at handler-creation time) because in dev, createRequestHandler runs before entry.server.tsx.
|
|
74
|
+
if (serverGlobals.isInstrumentationApiUsed() || !serverGlobals.isOtelDataLoaderSpanCreationEnabled()) {
|
|
75
|
+
return originalRequestHandler(request, initialContext);
|
|
76
|
+
}
|
|
77
|
+
|
|
55
78
|
let url;
|
|
56
79
|
try {
|
|
57
80
|
url = new URL(request.url);
|
|
@@ -64,13 +87,6 @@ class ReactRouterInstrumentation extends instrumentation.InstrumentationBase {
|
|
|
64
87
|
return originalRequestHandler(request, initialContext);
|
|
65
88
|
}
|
|
66
89
|
|
|
67
|
-
// Skip OTEL instrumentation if instrumentation API is being used
|
|
68
|
-
// as it handles loader/action spans itself
|
|
69
|
-
if (serverGlobals.isInstrumentationApiUsed()) {
|
|
70
|
-
debugBuild.DEBUG_BUILD && core.debug.log('Skipping OTEL loader/action instrumentation - using instrumentation API');
|
|
71
|
-
return originalRequestHandler(request, initialContext);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
90
|
const activeSpan = core.getActiveSpan();
|
|
75
91
|
const rootSpan = activeSpan && core.getRootSpan(activeSpan);
|
|
76
92
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactRouter.js","sources":["../../../../src/server/instrumentation/reactRouter.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@opentelemetry/instrumentation';\nimport { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';\nimport { SEMATTRS_HTTP_TARGET } from '@opentelemetry/semantic-conventions';\nimport {\n debug,\n getActiveSpan,\n getRootSpan,\n SDK_VERSION,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n startSpan,\n updateSpanName,\n} from '@sentry/core';\nimport type * as reactRouter from 'react-router';\nimport { DEBUG_BUILD } from '../../common/debug-build';\nimport { isInstrumentationApiUsed } from '../serverGlobals';\nimport { getOpName, getSpanName, isDataRequest } from './util';\n\ntype ReactRouterModuleExports = typeof reactRouter;\n\nconst supportedVersions = ['>=7.0.0'];\nconst COMPONENT = 'react-router';\n\n/**\n * Instrumentation for React Router's server request handler.\n * This patches the requestHandler function to add Sentry performance monitoring for data loaders.\n */\nexport class ReactRouterInstrumentation extends InstrumentationBase<InstrumentationConfig> {\n public constructor(config: InstrumentationConfig = {}) {\n super('ReactRouterInstrumentation', SDK_VERSION, config);\n }\n\n /**\n * Initializes the instrumentation by defining the React Router server modules to be patched.\n */\n // eslint-disable-next-line @typescript-eslint/naming-convention\n protected init(): InstrumentationNodeModuleDefinition {\n const reactRouterServerModule = new InstrumentationNodeModuleDefinition(\n COMPONENT,\n supportedVersions,\n (moduleExports: ReactRouterModuleExports) => {\n return this._createPatchedModuleProxy(moduleExports);\n },\n (_moduleExports: unknown) => {\n // nothing to unwrap here\n return _moduleExports;\n },\n );\n\n return reactRouterServerModule;\n }\n\n /**\n * Creates a proxy around the React Router module exports that patches the createRequestHandler function.\n * This allows us to wrap the request handler to add performance monitoring for data loaders and actions.\n */\n private _createPatchedModuleProxy(moduleExports: ReactRouterModuleExports): ReactRouterModuleExports {\n return new Proxy(moduleExports, {\n get(target, prop, receiver) {\n if (prop === 'createRequestHandler') {\n const original = target[prop];\n return function sentryWrappedCreateRequestHandler(this: unknown, ...args: unknown[]) {\n const originalRequestHandler = original.apply(this, args);\n\n return async function sentryWrappedRequestHandler(request: Request, initialContext?: unknown) {\n let url: URL;\n try {\n url = new URL(request.url);\n } catch {\n return originalRequestHandler(request, initialContext);\n }\n\n // We currently just want to trace loaders and actions\n if (!isDataRequest(url.pathname)) {\n return originalRequestHandler(request, initialContext);\n }\n\n
|
|
1
|
+
{"version":3,"file":"reactRouter.js","sources":["../../../../src/server/instrumentation/reactRouter.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@opentelemetry/instrumentation';\nimport { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';\nimport { SEMATTRS_HTTP_TARGET } from '@opentelemetry/semantic-conventions';\nimport {\n debug,\n getActiveSpan,\n getRootSpan,\n SDK_VERSION,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n startSpan,\n updateSpanName,\n} from '@sentry/core';\nimport type * as reactRouter from 'react-router';\nimport { DEBUG_BUILD } from '../../common/debug-build';\nimport { isServerBuildLike, setServerBuild } from '../serverBuild';\nimport { isInstrumentationApiUsed, isOtelDataLoaderSpanCreationEnabled } from '../serverGlobals';\nimport { getOpName, getSpanName, isDataRequest } from './util';\n\ntype ReactRouterModuleExports = typeof reactRouter;\n\nconst supportedVersions = ['>=7.0.0'];\nconst COMPONENT = 'react-router';\n\n/**\n * Instrumentation for React Router's server request handler.\n * This patches the requestHandler function to add Sentry performance monitoring for data loaders.\n */\nexport class ReactRouterInstrumentation extends InstrumentationBase<InstrumentationConfig> {\n public constructor(config: InstrumentationConfig = {}) {\n super('ReactRouterInstrumentation', SDK_VERSION, config);\n }\n\n /**\n * Initializes the instrumentation by defining the React Router server modules to be patched.\n */\n // eslint-disable-next-line @typescript-eslint/naming-convention\n protected init(): InstrumentationNodeModuleDefinition {\n const reactRouterServerModule = new InstrumentationNodeModuleDefinition(\n COMPONENT,\n supportedVersions,\n (moduleExports: ReactRouterModuleExports) => {\n return this._createPatchedModuleProxy(moduleExports);\n },\n (_moduleExports: unknown) => {\n // nothing to unwrap here\n return _moduleExports;\n },\n );\n\n return reactRouterServerModule;\n }\n\n /**\n * Creates a proxy around the React Router module exports that patches the createRequestHandler function.\n * This allows us to wrap the request handler to add performance monitoring for data loaders and actions.\n */\n private _createPatchedModuleProxy(moduleExports: ReactRouterModuleExports): ReactRouterModuleExports {\n return new Proxy(moduleExports, {\n get(target, prop, receiver) {\n if (prop === 'createRequestHandler') {\n const original = target[prop];\n return function sentryWrappedCreateRequestHandler(this: unknown, ...args: unknown[]) {\n // Capture the ServerBuild reference for middleware name lookup\n const build = args[0];\n if (isServerBuildLike(build)) {\n setServerBuild(build);\n } else if (typeof build === 'function') {\n // Build arg can be a factory function (dev mode HMR). Wrap to capture resolved build.\n const originalBuildFn = build as () => unknown;\n args[0] = async function sentryWrappedBuildFn() {\n const resolvedBuild = await originalBuildFn();\n if (isServerBuildLike(resolvedBuild)) {\n setServerBuild(resolvedBuild);\n }\n return resolvedBuild;\n };\n }\n\n const originalRequestHandler = original.apply(this, args);\n\n return async function sentryWrappedRequestHandler(request: Request, initialContext?: unknown) {\n // Skip OTEL span creation when instrumentation API is active or when span creation is not enabled.\n // Checked per-request (not at handler-creation time) because in dev, createRequestHandler runs before entry.server.tsx.\n if (isInstrumentationApiUsed() || !isOtelDataLoaderSpanCreationEnabled()) {\n return originalRequestHandler(request, initialContext);\n }\n\n let url: URL;\n try {\n url = new URL(request.url);\n } catch {\n return originalRequestHandler(request, initialContext);\n }\n\n // We currently just want to trace loaders and actions\n if (!isDataRequest(url.pathname)) {\n return originalRequestHandler(request, initialContext);\n }\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n\n if (!rootSpan) {\n DEBUG_BUILD && debug.log('No active root span found, skipping tracing for data request');\n return originalRequestHandler(request, initialContext);\n }\n\n // We cannot rely on the regular span name inferral here, as the express instrumentation sets `*` as the route\n // So we force this to be a more sensible name here\n // TODO: try to set derived parameterized route from build here (args[0])\n const spanData = spanToJSON(rootSpan);\n // eslint-disable-next-line deprecation/deprecation\n const target = spanData.data[SEMATTRS_HTTP_TARGET] || url.pathname;\n updateSpanName(rootSpan, `${request.method} ${target}`);\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.server',\n });\n\n return startSpan(\n {\n name: getSpanName(url.pathname, request.method),\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: getOpName(url.pathname, request.method),\n },\n },\n () => {\n return originalRequestHandler(request, initialContext);\n },\n );\n };\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n }\n}\n"],"names":["InstrumentationBase","SDK_VERSION","InstrumentationNodeModuleDefinition","isServerBuildLike","setServerBuild","isInstrumentationApiUsed","isOtelDataLoaderSpanCreationEnabled","isDataRequest","getActiveSpan","getRootSpan","DEBUG_BUILD","debug","spanToJSON","SEMATTRS_HTTP_TARGET","updateSpanName","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startSpan","getSpanName","SEMANTIC_ATTRIBUTE_SENTRY_OP","getOpName"],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ const semanticConventions = require('@opentelemetry/semantic-conventions');
|
|
|
4
4
|
const core = require('@sentry/core');
|
|
5
5
|
const node = require('@sentry/node');
|
|
6
6
|
const reactRouter = require('../instrumentation/reactRouter.js');
|
|
7
|
+
const serverBuild = require('../serverBuild.js');
|
|
7
8
|
const serverGlobals = require('../serverGlobals.js');
|
|
8
9
|
|
|
9
10
|
const INTEGRATION_NAME = 'ReactRouterServer';
|
|
@@ -15,6 +16,8 @@ const instrumentReactRouter = node.generateInstrumentOnce(INTEGRATION_NAME, () =
|
|
|
15
16
|
const instrumentReactRouterServer = Object.assign(
|
|
16
17
|
() => {
|
|
17
18
|
instrumentReactRouter();
|
|
19
|
+
// Register global for Vite plugin ServerBuild capture
|
|
20
|
+
serverBuild.registerServerBuildGlobal();
|
|
18
21
|
},
|
|
19
22
|
{ id: INTEGRATION_NAME },
|
|
20
23
|
);
|
|
@@ -26,17 +29,17 @@ const reactRouterServerIntegration = core.defineIntegration(() => {
|
|
|
26
29
|
return {
|
|
27
30
|
name: INTEGRATION_NAME,
|
|
28
31
|
setupOnce() {
|
|
29
|
-
//
|
|
30
|
-
if (serverGlobals.isInstrumentationApiUsed()) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
32
|
+
// Enable OTEL data-loader spans only on Node versions without the diagnostics_channel-based instrumentation API.
|
|
34
33
|
if (
|
|
35
|
-
(node.NODE_VERSION.major === 20 && node.NODE_VERSION.minor < 19) ||
|
|
36
|
-
(node.NODE_VERSION.major === 22 && node.NODE_VERSION.minor < 12)
|
|
34
|
+
(node.NODE_VERSION.major === 20 && node.NODE_VERSION.minor < 19) ||
|
|
35
|
+
(node.NODE_VERSION.major === 22 && node.NODE_VERSION.minor < 12)
|
|
37
36
|
) {
|
|
38
|
-
|
|
37
|
+
serverGlobals.enableOtelDataLoaderSpanCreation();
|
|
39
38
|
}
|
|
39
|
+
|
|
40
|
+
// Always install to capture ServerBuild for middleware names.
|
|
41
|
+
// Skips per-request wrapping when instrumentation API is active or OTEL span creation is disabled.
|
|
42
|
+
instrumentReactRouterServer();
|
|
40
43
|
},
|
|
41
44
|
processEvent(event) {
|
|
42
45
|
// Express generates bogus `*` routes for data loaders, which we want to remove here
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactRouterServer.js","sources":["../../../../src/server/integration/reactRouterServer.ts"],"sourcesContent":["import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport { defineIntegration } from '@sentry/core';\nimport { generateInstrumentOnce, NODE_VERSION } from '@sentry/node';\nimport { ReactRouterInstrumentation } from '../instrumentation/reactRouter';\nimport {
|
|
1
|
+
{"version":3,"file":"reactRouterServer.js","sources":["../../../../src/server/integration/reactRouterServer.ts"],"sourcesContent":["import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport { defineIntegration } from '@sentry/core';\nimport { generateInstrumentOnce, NODE_VERSION } from '@sentry/node';\nimport { ReactRouterInstrumentation } from '../instrumentation/reactRouter';\nimport { registerServerBuildGlobal } from '../serverBuild';\nimport { enableOtelDataLoaderSpanCreation } from '../serverGlobals';\n\nconst INTEGRATION_NAME = 'ReactRouterServer';\n\nconst instrumentReactRouter = generateInstrumentOnce(INTEGRATION_NAME, () => {\n return new ReactRouterInstrumentation();\n});\n\nexport const instrumentReactRouterServer = Object.assign(\n (): void => {\n instrumentReactRouter();\n // Register global for Vite plugin ServerBuild capture\n registerServerBuildGlobal();\n },\n { id: INTEGRATION_NAME },\n);\n\n/**\n * Integration capturing tracing data for React Router server functions.\n */\nexport const reactRouterServerIntegration = defineIntegration(() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // Enable OTEL data-loader spans only on Node versions without the diagnostics_channel-based instrumentation API.\n if (\n (NODE_VERSION.major === 20 && NODE_VERSION.minor < 19) ||\n (NODE_VERSION.major === 22 && NODE_VERSION.minor < 12)\n ) {\n enableOtelDataLoaderSpanCreation();\n }\n\n // Always install to capture ServerBuild for middleware names.\n // Skips per-request wrapping when instrumentation API is active or OTEL span creation is disabled.\n instrumentReactRouterServer();\n },\n processEvent(event) {\n // Express generates bogus `*` routes for data loaders, which we want to remove here\n // we cannot do this earlier because some OTEL instrumentation adds this at some unexpected point\n if (\n event.type === 'transaction' &&\n event.contexts?.trace?.data &&\n event.contexts.trace.data[ATTR_HTTP_ROUTE] === '*'\n ) {\n const origin = event.contexts.trace.origin;\n const isInstrumentationApiOrigin = origin?.includes('instrumentation_api');\n\n // For instrumentation_api, always clean up bogus `*` route since we set better names\n // For legacy, only clean up if the name has been adjusted (not METHOD *)\n if (isInstrumentationApiOrigin || !event.transaction?.endsWith(' *')) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete event.contexts.trace.data[ATTR_HTTP_ROUTE];\n }\n }\n\n return event;\n },\n };\n});\n"],"names":["generateInstrumentOnce","ReactRouterInstrumentation","registerServerBuildGlobal","defineIntegration","NODE_VERSION","enableOtelDataLoaderSpanCreation","ATTR_HTTP_ROUTE"],"mappings":";;;;;;;;;AAOA,MAAM,gBAAA,GAAmB,mBAAmB;;AAE5C,MAAM,qBAAA,GAAwBA,2BAAsB,CAAC,gBAAgB,EAAE,MAAM;AAC7E,EAAE,OAAO,IAAIC,sCAA0B,EAAE;AACzC,CAAC,CAAC;;AAEK,MAAM,2BAAA,GAA8B,MAAM,CAAC,MAAM;AACxD,EAAE,MAAY;AACd,IAAI,qBAAqB,EAAE;AAC3B;AACA,IAAIC,qCAAyB,EAAE;AAC/B,EAAE,CAAC;AACH,EAAE,EAAE,EAAE,EAAE,gBAAA,EAAkB;AAC1B;;AAEA;AACA;AACA;MACa,4BAAA,GAA+BC,sBAAiB,CAAC,MAAM;AACpE,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,SAAS,GAAG;AAChB;AACA,MAAM;AACN,QAAQ,CAACC,iBAAY,CAAC,KAAA,KAAU,EAAA,IAAMA,iBAAY,CAAC,KAAA,GAAQ,EAAE;AAC7D,SAASA,iBAAY,CAAC,KAAA,KAAU,EAAA,IAAMA,iBAAY,CAAC,KAAA,GAAQ,EAAE;AAC7D,QAAQ;AACR,QAAQC,8CAAgC,EAAE;AAC1C,MAAM;;AAEN;AACA;AACA,MAAM,2BAA2B,EAAE;AACnC,IAAI,CAAC;AACL,IAAI,YAAY,CAAC,KAAK,EAAE;AACxB;AACA;AACA,MAAM;AACN,QAAQ,KAAK,CAAC,IAAA,KAAS,aAAA;AACvB,QAAQ,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAA;AAC/B,QAAQ,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAACC,mCAAe,CAAA,KAAM;AACvD,QAAQ;AACR,QAAQ,MAAM,SAAS,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM;AAClD,QAAQ,MAAM,6BAA6B,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC;;AAElF;AACA;AACA,QAAQ,IAAI,0BAAA,IAA8B,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE;AAC9E;AACA,UAAU,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAACA,mCAAe,CAAC;AAC3D,QAAQ;AACR,MAAM;;AAEN,MAAM,OAAO,KAAK;AAClB,IAAI,CAAC;AACL,GAAG;AACH,CAAC;;;;;"}
|