@sentry/react-router 9.18.0 → 9.20.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/server/instrumentation/reactRouter.js +103 -0
- package/build/cjs/server/instrumentation/reactRouter.js.map +1 -0
- package/build/cjs/server/instrumentation/util.js +63 -0
- package/build/cjs/server/instrumentation/util.js.map +1 -0
- package/build/cjs/server/{lowQualityTransactionsFilterIntegration.js → integration/lowQualityTransactionsFilterIntegration.js} +1 -1
- package/build/cjs/server/integration/lowQualityTransactionsFilterIntegration.js.map +1 -0
- package/build/cjs/server/integration/reactRouterServer.js +34 -0
- package/build/cjs/server/integration/reactRouterServer.js.map +1 -0
- package/build/cjs/server/sdk.js +41 -4
- package/build/cjs/server/sdk.js.map +1 -1
- package/build/cjs/server/wrapSentryHandleRequest.js +3 -0
- package/build/cjs/server/wrapSentryHandleRequest.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/server/instrumentation/reactRouter.js +101 -0
- package/build/esm/server/instrumentation/reactRouter.js.map +1 -0
- package/build/esm/server/instrumentation/util.js +56 -0
- package/build/esm/server/instrumentation/util.js.map +1 -0
- package/build/esm/server/{lowQualityTransactionsFilterIntegration.js → integration/lowQualityTransactionsFilterIntegration.js} +1 -1
- package/build/esm/server/integration/lowQualityTransactionsFilterIntegration.js.map +1 -0
- package/build/esm/server/integration/reactRouterServer.js +31 -0
- package/build/esm/server/integration/reactRouterServer.js.map +1 -0
- package/build/esm/server/sdk.js +43 -7
- package/build/esm/server/sdk.js.map +1 -1
- package/build/esm/server/wrapSentryHandleRequest.js +4 -1
- package/build/esm/server/wrapSentryHandleRequest.js.map +1 -1
- package/build/types/server/instrumentation/reactRouter.d.ts +19 -0
- package/build/types/server/instrumentation/reactRouter.d.ts.map +1 -0
- package/build/types/server/instrumentation/util.d.ts +31 -0
- package/build/types/server/instrumentation/util.d.ts.map +1 -0
- package/build/types/server/integration/lowQualityTransactionsFilterIntegration.d.ts.map +1 -0
- package/build/types/server/integration/reactRouterServer.d.ts +8 -0
- package/build/types/server/integration/reactRouterServer.d.ts.map +1 -0
- package/build/types/server/sdk.d.ts +6 -0
- package/build/types/server/sdk.d.ts.map +1 -1
- package/build/types/server/wrapSentryHandleRequest.d.ts.map +1 -1
- package/package.json +5 -4
- package/build/cjs/server/lowQualityTransactionsFilterIntegration.js.map +0 -1
- package/build/esm/server/lowQualityTransactionsFilterIntegration.js.map +0 -1
- package/build/types/server/lowQualityTransactionsFilterIntegration.d.ts.map +0 -1
- /package/build/types/server/{lowQualityTransactionsFilterIntegration.d.ts → integration/lowQualityTransactionsFilterIntegration.d.ts} +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const instrumentation = require('@opentelemetry/instrumentation');
|
|
4
|
+
const core = require('@sentry/core');
|
|
5
|
+
const debugBuild = require('../../common/debug-build.js');
|
|
6
|
+
const util = require('./util.js');
|
|
7
|
+
|
|
8
|
+
const supportedVersions = ['>=7.0.0'];
|
|
9
|
+
const COMPONENT = 'react-router';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Instrumentation for React Router's server request handler.
|
|
13
|
+
* This patches the requestHandler function to add Sentry performance monitoring for data loaders.
|
|
14
|
+
*/
|
|
15
|
+
class ReactRouterInstrumentation extends instrumentation.InstrumentationBase {
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
super('ReactRouterInstrumentation', core.SDK_VERSION, config);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Initializes the instrumentation by defining the React Router server modules to be patched.
|
|
22
|
+
*/
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
24
|
+
init() {
|
|
25
|
+
const reactRouterServerModule = new instrumentation.InstrumentationNodeModuleDefinition(
|
|
26
|
+
COMPONENT,
|
|
27
|
+
supportedVersions,
|
|
28
|
+
(moduleExports) => {
|
|
29
|
+
return this._createPatchedModuleProxy(moduleExports);
|
|
30
|
+
},
|
|
31
|
+
(_moduleExports) => {
|
|
32
|
+
// nothing to unwrap here
|
|
33
|
+
return _moduleExports;
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return reactRouterServerModule;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates a proxy around the React Router module exports that patches the createRequestHandler function.
|
|
42
|
+
* This allows us to wrap the request handler to add performance monitoring for data loaders and actions.
|
|
43
|
+
*/
|
|
44
|
+
_createPatchedModuleProxy(moduleExports) {
|
|
45
|
+
return new Proxy(moduleExports, {
|
|
46
|
+
get(target, prop, receiver) {
|
|
47
|
+
if (prop === 'createRequestHandler') {
|
|
48
|
+
const original = target[prop];
|
|
49
|
+
return function sentryWrappedCreateRequestHandler( ...args) {
|
|
50
|
+
const originalRequestHandler = original.apply(this, args);
|
|
51
|
+
|
|
52
|
+
return async function sentryWrappedRequestHandler(request, initialContext) {
|
|
53
|
+
let url;
|
|
54
|
+
try {
|
|
55
|
+
url = new URL(request.url);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return originalRequestHandler(request, initialContext);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// We currently just want to trace loaders and actions
|
|
61
|
+
if (!util.isDataRequest(url.pathname)) {
|
|
62
|
+
return originalRequestHandler(request, initialContext);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const activeSpan = core.getActiveSpan();
|
|
66
|
+
const rootSpan = activeSpan && core.getRootSpan(activeSpan);
|
|
67
|
+
|
|
68
|
+
if (!rootSpan) {
|
|
69
|
+
debugBuild.DEBUG_BUILD && core.logger.debug('No active root span found, skipping tracing for data request');
|
|
70
|
+
return originalRequestHandler(request, initialContext);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Set the source and overwrite attributes on the root span to ensure the transaction name
|
|
74
|
+
// is derived from the raw URL pathname rather than any parameterized route that may be set later
|
|
75
|
+
// TODO: try to set derived parameterized route from build here (args[0])
|
|
76
|
+
rootSpan.setAttributes({
|
|
77
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
|
|
78
|
+
[util.SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE]: `${request.method} ${url.pathname}`,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return core.startSpan(
|
|
82
|
+
{
|
|
83
|
+
name: util.getSpanName(url.pathname, request.method),
|
|
84
|
+
attributes: {
|
|
85
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react-router',
|
|
86
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: util.getOpName(url.pathname, request.method),
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
() => {
|
|
90
|
+
return originalRequestHandler(request, initialContext);
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return Reflect.get(target, prop, receiver);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
exports.ReactRouterInstrumentation = ReactRouterInstrumentation;
|
|
103
|
+
//# sourceMappingURL=reactRouter.js.map
|
|
@@ -0,0 +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 {\n getActiveSpan,\n getRootSpan,\n logger,\n SDK_VERSION,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n startSpan,\n} from '@sentry/core';\nimport type * as reactRouter from 'react-router';\nimport { DEBUG_BUILD } from '../../common/debug-build';\nimport { getOpName, getSpanName, isDataRequest, SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE } 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 (error) {\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 && logger.debug('No active root span found, skipping tracing for data request');\n return originalRequestHandler(request, initialContext);\n }\n\n // Set the source and overwrite attributes on the root span to ensure the transaction name\n // is derived from the raw URL pathname rather than any parameterized route that may be set later\n // TODO: try to set derived parameterized route from build here (args[0])\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE]: `${request.method} ${url.pathname}`,\n });\n\n return startSpan(\n {\n name: getSpanName(url.pathname, request.method),\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react-router',\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","isDataRequest","getActiveSpan","getRootSpan","DEBUG_BUILD","logger","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE","startSpan","getSpanName","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","getOpName"],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gets the op name for a request based on whether it's a loader or action request.
|
|
5
|
+
* @param pathName The URL pathname to check
|
|
6
|
+
* @param requestMethod The HTTP request method
|
|
7
|
+
*/
|
|
8
|
+
function getOpName(pathName, requestMethod) {
|
|
9
|
+
return isLoaderRequest(pathName, requestMethod)
|
|
10
|
+
? 'function.react-router.loader'
|
|
11
|
+
: isActionRequest(pathName, requestMethod)
|
|
12
|
+
? 'function.react-router.action'
|
|
13
|
+
: 'function.react-router';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Gets the span name for a request based on whether it's a loader or action request.
|
|
18
|
+
* @param pathName The URL pathname to check
|
|
19
|
+
* @param requestMethod The HTTP request method
|
|
20
|
+
*/
|
|
21
|
+
function getSpanName(pathName, requestMethod) {
|
|
22
|
+
return isLoaderRequest(pathName, requestMethod)
|
|
23
|
+
? 'Executing Server Loader'
|
|
24
|
+
: isActionRequest(pathName, requestMethod)
|
|
25
|
+
? 'Executing Server Action'
|
|
26
|
+
: 'Unknown Data Request';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Checks if the request is a server loader request
|
|
31
|
+
* @param pathname The URL pathname to check
|
|
32
|
+
* @param requestMethod The HTTP request method
|
|
33
|
+
*/
|
|
34
|
+
function isLoaderRequest(pathname, requestMethod) {
|
|
35
|
+
return isDataRequest(pathname) && requestMethod === 'GET';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Checks if the request is a server action request
|
|
40
|
+
* @param pathname The URL pathname to check
|
|
41
|
+
* @param requestMethod The HTTP request method
|
|
42
|
+
*/
|
|
43
|
+
function isActionRequest(pathname, requestMethod) {
|
|
44
|
+
return isDataRequest(pathname) && requestMethod === 'POST';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Checks if the request is a react-router data request
|
|
49
|
+
* @param pathname The URL pathname to check
|
|
50
|
+
*/
|
|
51
|
+
function isDataRequest(pathname) {
|
|
52
|
+
return pathname.endsWith('.data');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE = 'sentry.overwrite-route';
|
|
56
|
+
|
|
57
|
+
exports.SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE = SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE;
|
|
58
|
+
exports.getOpName = getOpName;
|
|
59
|
+
exports.getSpanName = getSpanName;
|
|
60
|
+
exports.isActionRequest = isActionRequest;
|
|
61
|
+
exports.isDataRequest = isDataRequest;
|
|
62
|
+
exports.isLoaderRequest = isLoaderRequest;
|
|
63
|
+
//# sourceMappingURL=util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sources":["../../../../src/server/instrumentation/util.ts"],"sourcesContent":["/**\n * Gets the op name for a request based on whether it's a loader or action request.\n * @param pathName The URL pathname to check\n * @param requestMethod The HTTP request method\n */\nexport function getOpName(pathName: string, requestMethod: string): string {\n return isLoaderRequest(pathName, requestMethod)\n ? 'function.react-router.loader'\n : isActionRequest(pathName, requestMethod)\n ? 'function.react-router.action'\n : 'function.react-router';\n}\n\n/**\n * Gets the span name for a request based on whether it's a loader or action request.\n * @param pathName The URL pathname to check\n * @param requestMethod The HTTP request method\n */\nexport function getSpanName(pathName: string, requestMethod: string): string {\n return isLoaderRequest(pathName, requestMethod)\n ? 'Executing Server Loader'\n : isActionRequest(pathName, requestMethod)\n ? 'Executing Server Action'\n : 'Unknown Data Request';\n}\n\n/**\n * Checks if the request is a server loader request\n * @param pathname The URL pathname to check\n * @param requestMethod The HTTP request method\n */\nexport function isLoaderRequest(pathname: string, requestMethod: string): boolean {\n return isDataRequest(pathname) && requestMethod === 'GET';\n}\n\n/**\n * Checks if the request is a server action request\n * @param pathname The URL pathname to check\n * @param requestMethod The HTTP request method\n */\nexport function isActionRequest(pathname: string, requestMethod: string): boolean {\n return isDataRequest(pathname) && requestMethod === 'POST';\n}\n\n/**\n * Checks if the request is a react-router data request\n * @param pathname The URL pathname to check\n */\nexport function isDataRequest(pathname: string): boolean {\n return pathname.endsWith('.data');\n}\n\nexport const SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE = 'sentry.overwrite-route';\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,QAAQ,EAAU,aAAa,EAAkB;AAC3E,EAAE,OAAO,eAAe,CAAC,QAAQ,EAAE,aAAa;AAChD,MAAM;AACN,MAAM,eAAe,CAAC,QAAQ,EAAE,aAAa;AAC7C,QAAQ;AACR,QAAQ,uBAAuB;AAC/B;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,QAAQ,EAAU,aAAa,EAAkB;AAC7E,EAAE,OAAO,eAAe,CAAC,QAAQ,EAAE,aAAa;AAChD,MAAM;AACN,MAAM,eAAe,CAAC,QAAQ,EAAE,aAAa;AAC7C,QAAQ;AACR,QAAQ,sBAAsB;AAC9B;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,QAAQ,EAAU,aAAa,EAAmB;AAClF,EAAE,OAAO,aAAa,CAAC,QAAQ,KAAK,aAAA,KAAkB,KAAK;AAC3D;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,QAAQ,EAAU,aAAa,EAAmB;AAClF,EAAE,OAAO,aAAa,CAAC,QAAQ,KAAK,aAAA,KAAkB,MAAM;AAC5D;;AAEA;AACA;AACA;AACA;AACO,SAAS,aAAa,CAAC,QAAQ,EAAmB;AACzD,EAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;AACnC;;AAEO,MAAM,mCAAoC,GAAE;;;;;;;;;"}
|
|
@@ -10,7 +10,7 @@ const core = require('@sentry/core');
|
|
|
10
10
|
function _lowQualityTransactionsFilterIntegration(options)
|
|
11
11
|
|
|
12
12
|
{
|
|
13
|
-
const matchedRegexes = [/GET \/node_modules\//, /GET \/favicon\.ico/, /GET \/@id
|
|
13
|
+
const matchedRegexes = [/GET \/node_modules\//, /GET \/favicon\.ico/, /GET \/@id\//, /GET \/__manifest\?/];
|
|
14
14
|
|
|
15
15
|
return {
|
|
16
16
|
name: 'LowQualityTransactionsFilter',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lowQualityTransactionsFilterIntegration.js","sources":["../../../../src/server/integration/lowQualityTransactionsFilterIntegration.ts"],"sourcesContent":["import { type Client, type Event, type EventHint, defineIntegration, logger } from '@sentry/core';\nimport type { NodeOptions } from '@sentry/node';\n\n/**\n * Integration that filters out noisy http transactions such as requests to node_modules, favicon.ico, @id/\n *\n */\n\nfunction _lowQualityTransactionsFilterIntegration(options: NodeOptions): {\n name: string;\n processEvent: (event: Event, hint: EventHint, client: Client) => Event | null;\n} {\n const matchedRegexes = [/GET \\/node_modules\\//, /GET \\/favicon\\.ico/, /GET \\/@id\\//, /GET \\/__manifest\\?/];\n\n return {\n name: 'LowQualityTransactionsFilter',\n\n processEvent(event: Event, _hint: EventHint, _client: Client): Event | null {\n if (event.type !== 'transaction' || !event.transaction) {\n return event;\n }\n\n const transaction = event.transaction;\n\n if (matchedRegexes.some(regex => transaction.match(regex))) {\n options.debug && logger.log('[ReactRouter] Filtered node_modules transaction:', event.transaction);\n return null;\n }\n\n return event;\n },\n };\n}\n\nexport const lowQualityTransactionsFilterIntegration = defineIntegration((options: NodeOptions) =>\n _lowQualityTransactionsFilterIntegration(options),\n);\n"],"names":["logger","defineIntegration"],"mappings":";;;;AAGA;AACA;AACA;AACA;;AAEA,SAAS,wCAAwC,CAAC,OAAO;;AAGzD,CAAE;AACF,EAAE,MAAM,cAAe,GAAE,CAAC,sBAAsB,EAAE,oBAAoB,EAAE,aAAa,EAAE,oBAAoB,CAAC;;AAE5G,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,8BAA8B;;AAExC,IAAI,YAAY,CAAC,KAAK,EAAS,KAAK,EAAa,OAAO,EAAwB;AAChF,MAAM,IAAI,KAAK,CAAC,IAAK,KAAI,aAAc,IAAG,CAAC,KAAK,CAAC,WAAW,EAAE;AAC9D,QAAQ,OAAO,KAAK;AACpB;;AAEA,MAAM,MAAM,WAAA,GAAc,KAAK,CAAC,WAAW;;AAE3C,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC,KAAA,IAAS,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE;AAClE,QAAQ,OAAO,CAAC,KAAM,IAAGA,WAAM,CAAC,GAAG,CAAC,kDAAkD,EAAE,KAAK,CAAC,WAAW,CAAC;AAC1G,QAAQ,OAAO,IAAI;AACnB;;AAEA,MAAM,OAAO,KAAK;AAClB,KAAK;AACL,GAAG;AACH;;MAEa,uCAAwC,GAAEC,sBAAiB,CAAC,CAAC,OAAO;AACjF,EAAE,wCAAwC,CAAC,OAAO,CAAC;AACnD;;;;"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
const node = require('@sentry/node');
|
|
5
|
+
const reactRouter = require('../instrumentation/reactRouter.js');
|
|
6
|
+
|
|
7
|
+
const INTEGRATION_NAME = 'ReactRouterServer';
|
|
8
|
+
|
|
9
|
+
const instrumentReactRouter = node.generateInstrumentOnce('React-Router-Server', () => {
|
|
10
|
+
return new reactRouter.ReactRouterInstrumentation();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const instrumentReactRouterServer = Object.assign(
|
|
14
|
+
() => {
|
|
15
|
+
instrumentReactRouter();
|
|
16
|
+
},
|
|
17
|
+
{ id: INTEGRATION_NAME },
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Integration capturing tracing data for React Router server functions.
|
|
22
|
+
*/
|
|
23
|
+
const reactRouterServerIntegration = core.defineIntegration(() => {
|
|
24
|
+
return {
|
|
25
|
+
name: INTEGRATION_NAME,
|
|
26
|
+
setupOnce() {
|
|
27
|
+
instrumentReactRouterServer();
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
exports.instrumentReactRouterServer = instrumentReactRouterServer;
|
|
33
|
+
exports.reactRouterServerIntegration = reactRouterServerIntegration;
|
|
34
|
+
//# sourceMappingURL=reactRouterServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactRouterServer.js","sources":["../../../../src/server/integration/reactRouterServer.ts"],"sourcesContent":["import { defineIntegration } from '@sentry/core';\nimport { generateInstrumentOnce } from '@sentry/node';\nimport { ReactRouterInstrumentation } from '../instrumentation/reactRouter';\n\nconst INTEGRATION_NAME = 'ReactRouterServer';\n\nconst instrumentReactRouter = generateInstrumentOnce('React-Router-Server', () => {\n return new ReactRouterInstrumentation();\n});\n\nexport const instrumentReactRouterServer = Object.assign(\n (): void => {\n instrumentReactRouter();\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 instrumentReactRouterServer();\n },\n };\n});\n"],"names":["generateInstrumentOnce","ReactRouterInstrumentation","defineIntegration"],"mappings":";;;;;;AAIA,MAAM,gBAAA,GAAmB,mBAAmB;;AAE5C,MAAM,qBAAA,GAAwBA,2BAAsB,CAAC,qBAAqB,EAAE,MAAM;AAClF,EAAE,OAAO,IAAIC,sCAA0B,EAAE;AACzC,CAAC,CAAC;;AAEW,MAAA,2BAAA,GAA8B,MAAM,CAAC,MAAM;AACxD,EAAE,MAAY;AACd,IAAI,qBAAqB,EAAE;AAC3B,GAAG;AACH,EAAE,EAAE,EAAE,EAAE,gBAAA,EAAkB;AAC1B;;AAEA;AACA;AACA;MACa,4BAA6B,GAAEC,sBAAiB,CAAC,MAAM;AACpE,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,SAAS,GAAG;AAChB,MAAM,2BAA2B,EAAE;AACnC,KAAK;AACL,GAAG;AACH,CAAC;;;;;"}
|
package/build/cjs/server/sdk.js
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
|
+
const semanticConventions = require('@opentelemetry/semantic-conventions');
|
|
3
4
|
const core = require('@sentry/core');
|
|
4
5
|
const node = require('@sentry/node');
|
|
5
6
|
const debugBuild = require('../common/debug-build.js');
|
|
6
|
-
const
|
|
7
|
+
const util = require('./instrumentation/util.js');
|
|
8
|
+
const lowQualityTransactionsFilterIntegration = require('./integration/lowQualityTransactionsFilterIntegration.js');
|
|
9
|
+
const reactRouterServer = require('./integration/reactRouterServer.js');
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Returns the default integrations for the React Router SDK.
|
|
13
|
+
* @param options The options for the SDK.
|
|
14
|
+
*/
|
|
15
|
+
function getDefaultReactRouterServerIntegrations(options) {
|
|
16
|
+
return [
|
|
17
|
+
...node.getDefaultIntegrations(options),
|
|
18
|
+
lowQualityTransactionsFilterIntegration.lowQualityTransactionsFilterIntegration(options),
|
|
19
|
+
reactRouterServer.reactRouterServerIntegration(),
|
|
20
|
+
];
|
|
10
21
|
}
|
|
11
22
|
|
|
12
23
|
/**
|
|
@@ -15,7 +26,7 @@ function getDefaultIntegrations(options) {
|
|
|
15
26
|
function init(options) {
|
|
16
27
|
const opts = {
|
|
17
28
|
...options,
|
|
18
|
-
defaultIntegrations:
|
|
29
|
+
defaultIntegrations: getDefaultReactRouterServerIntegrations(options),
|
|
19
30
|
};
|
|
20
31
|
|
|
21
32
|
debugBuild.DEBUG_BUILD && core.logger.log('Initializing SDK...');
|
|
@@ -26,10 +37,36 @@ function init(options) {
|
|
|
26
37
|
|
|
27
38
|
core.setTag('runtime', 'node');
|
|
28
39
|
|
|
40
|
+
// Overwrite the transaction name for instrumented data loaders because the trace data gets overwritten at a later point.
|
|
41
|
+
// We only update the tx in case SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE got set in our instrumentation before.
|
|
42
|
+
core.getGlobalScope().addEventProcessor(
|
|
43
|
+
Object.assign(
|
|
44
|
+
(event => {
|
|
45
|
+
const overwrite = event.contexts?.trace?.data?.[util.SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE];
|
|
46
|
+
if (
|
|
47
|
+
event.type === 'transaction' &&
|
|
48
|
+
(event.transaction === 'GET *' || event.transaction === 'POST *') &&
|
|
49
|
+
event.contexts?.trace?.data?.[semanticConventions.ATTR_HTTP_ROUTE] === '*' &&
|
|
50
|
+
overwrite
|
|
51
|
+
) {
|
|
52
|
+
event.transaction = overwrite;
|
|
53
|
+
event.contexts.trace.data[semanticConventions.ATTR_HTTP_ROUTE] = 'url';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// always yeet this attribute into the void, as this should not reach the server
|
|
57
|
+
delete event.contexts?.trace?.data?.[util.SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE];
|
|
58
|
+
|
|
59
|
+
return event;
|
|
60
|
+
}) ,
|
|
61
|
+
{ id: 'ReactRouterTransactionEnhancer' },
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
|
|
29
65
|
debugBuild.DEBUG_BUILD && core.logger.log('SDK successfully initialized');
|
|
30
66
|
|
|
31
67
|
return client;
|
|
32
68
|
}
|
|
33
69
|
|
|
70
|
+
exports.getDefaultReactRouterServerIntegrations = getDefaultReactRouterServerIntegrations;
|
|
34
71
|
exports.init = init;
|
|
35
72
|
//# sourceMappingURL=sdk.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport { applySdkMetadata, logger, setTag } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getNodeDefaultIntegrations, init as initNodeSdk } from '@sentry/node';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { lowQualityTransactionsFilterIntegration } from './lowQualityTransactionsFilterIntegration';\n\
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport type { EventProcessor, Integration } from '@sentry/core';\nimport { applySdkMetadata, getGlobalScope, logger, setTag } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getNodeDefaultIntegrations, init as initNodeSdk } from '@sentry/node';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE } from './instrumentation/util';\nimport { lowQualityTransactionsFilterIntegration } from './integration/lowQualityTransactionsFilterIntegration';\nimport { reactRouterServerIntegration } from './integration/reactRouterServer';\n\n/**\n * Returns the default integrations for the React Router SDK.\n * @param options The options for the SDK.\n */\nexport function getDefaultReactRouterServerIntegrations(options: NodeOptions): Integration[] {\n return [\n ...getNodeDefaultIntegrations(options),\n lowQualityTransactionsFilterIntegration(options),\n reactRouterServerIntegration(),\n ];\n}\n\n/**\n * Initializes the server side of the React Router SDK\n */\nexport function init(options: NodeOptions): NodeClient | undefined {\n const opts: NodeOptions = {\n ...options,\n defaultIntegrations: getDefaultReactRouterServerIntegrations(options),\n };\n\n DEBUG_BUILD && logger.log('Initializing SDK...');\n\n applySdkMetadata(opts, 'react-router', ['react-router', 'node']);\n\n const client = initNodeSdk(opts);\n\n setTag('runtime', 'node');\n\n // Overwrite the transaction name for instrumented data loaders because the trace data gets overwritten at a later point.\n // We only update the tx in case SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE got set in our instrumentation before.\n getGlobalScope().addEventProcessor(\n Object.assign(\n (event => {\n const overwrite = event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE];\n if (\n event.type === 'transaction' &&\n (event.transaction === 'GET *' || event.transaction === 'POST *') &&\n event.contexts?.trace?.data?.[ATTR_HTTP_ROUTE] === '*' &&\n overwrite\n ) {\n event.transaction = overwrite;\n event.contexts.trace.data[ATTR_HTTP_ROUTE] = 'url';\n }\n\n // always yeet this attribute into the void, as this should not reach the server\n delete event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE];\n\n return event;\n }) satisfies EventProcessor,\n { id: 'ReactRouterTransactionEnhancer' },\n ),\n );\n\n DEBUG_BUILD && logger.log('SDK successfully initialized');\n\n return client;\n}\n"],"names":["getNodeDefaultIntegrations","lowQualityTransactionsFilterIntegration","reactRouterServerIntegration","DEBUG_BUILD","logger","applySdkMetadata","initNodeSdk","setTag","getGlobalScope","SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE","ATTR_HTTP_ROUTE"],"mappings":";;;;;;;;;;AAUA;AACA;AACA;AACA;AACO,SAAS,uCAAuC,CAAC,OAAO,EAA8B;AAC7F,EAAE,OAAO;AACT,IAAI,GAAGA,2BAA0B,CAAC,OAAO,CAAC;AAC1C,IAAIC,+EAAuC,CAAC,OAAO,CAAC;AACpD,IAAIC,8CAA4B,EAAE;AAClC,GAAG;AACH;;AAEA;AACA;AACA;AACO,SAAS,IAAI,CAAC,OAAO,EAAuC;AACnE,EAAE,MAAM,IAAI,GAAgB;AAC5B,IAAI,GAAG,OAAO;AACd,IAAI,mBAAmB,EAAE,uCAAuC,CAAC,OAAO,CAAC;AACzE,GAAG;;AAEH,EAAEC,0BAAeC,WAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC;;AAElD,EAAEC,qBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;;AAElE,EAAE,MAAM,MAAO,GAAEC,SAAW,CAAC,IAAI,CAAC;;AAElC,EAAEC,WAAM,CAAC,SAAS,EAAE,MAAM,CAAC;;AAE3B;AACA;AACA,EAAEC,mBAAc,EAAE,CAAC,iBAAiB;AACpC,IAAI,MAAM,CAAC,MAAM;AACjB,OAAO,SAAS;AAChB,QAAQ,MAAM,SAAA,GAAY,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,GAAGC,wCAAmC,CAAC;AAC5F,QAAQ;AACR,UAAU,KAAK,CAAC,IAAK,KAAI,aAAc;AACvC,WAAW,KAAK,CAAC,WAAA,KAAgB,OAAA,IAAW,KAAK,CAAC,WAAA,KAAgB,QAAQ,CAAE;AAC5E,UAAU,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,GAAGC,mCAAe,CAAE,KAAI,GAAI;AACjE,UAAU;AACV,UAAU;AACV,UAAU,KAAK,CAAC,WAAY,GAAE,SAAS;AACvC,UAAU,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAACA,mCAAe,CAAE,GAAE,KAAK;AAC5D;;AAEA;AACA,QAAQ,OAAO,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,GAAGD,wCAAmC,CAAC;;AAEjF,QAAQ,OAAO,KAAK;AACpB,OAAO;AACP,MAAM,EAAE,EAAE,EAAE,gCAAA,EAAkC;AAC9C,KAAK;AACL,GAAG;;AAEH,EAAEN,0BAAeC,WAAM,CAAC,GAAG,CAAC,8BAA8B,CAAC;;AAE3D,EAAE,OAAO,MAAM;AACf;;;;;"}
|
|
@@ -22,6 +22,7 @@ function wrapSentryHandleRequest(originalHandle) {
|
|
|
22
22
|
) {
|
|
23
23
|
const parameterizedPath =
|
|
24
24
|
routerContext?.staticHandlerContext?.matches?.[routerContext.staticHandlerContext.matches.length - 1]?.route.path;
|
|
25
|
+
|
|
25
26
|
if (parameterizedPath) {
|
|
26
27
|
const activeSpan = core.getActiveSpan();
|
|
27
28
|
if (activeSpan) {
|
|
@@ -30,6 +31,7 @@ function wrapSentryHandleRequest(originalHandle) {
|
|
|
30
31
|
|
|
31
32
|
// The express instrumentation writes on the rpcMetadata and that ends up stomping on the `http.route` attribute.
|
|
32
33
|
const rpcMetadata = core$1.getRPCMetadata(api.context.active());
|
|
34
|
+
|
|
33
35
|
if (rpcMetadata?.type === core$1.RPCType.HTTP) {
|
|
34
36
|
rpcMetadata.route = routeName;
|
|
35
37
|
}
|
|
@@ -38,6 +40,7 @@ function wrapSentryHandleRequest(originalHandle) {
|
|
|
38
40
|
rootSpan.setAttributes({
|
|
39
41
|
[semanticConventions.ATTR_HTTP_ROUTE]: routeName,
|
|
40
42
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
|
|
43
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME]: `${request.method} ${routeName}`,
|
|
41
44
|
});
|
|
42
45
|
}
|
|
43
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapSentryHandleRequest.js","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"sourcesContent":["import { context } from '@opentelemetry/api';\nimport { getRPCMetadata, RPCType } from '@opentelemetry/core';\nimport { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport {
|
|
1
|
+
{"version":3,"file":"wrapSentryHandleRequest.js","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"sourcesContent":["import { context } from '@opentelemetry/api';\nimport { getRPCMetadata, RPCType } from '@opentelemetry/core';\nimport { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport {\n getActiveSpan,\n getRootSpan,\n getTraceMetaTags,\n SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n} from '@sentry/core';\nimport type { AppLoadContext, EntryContext } from 'react-router';\nimport type { PassThrough } from 'stream';\nimport { Transform } from 'stream';\n\ntype OriginalHandleRequest = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(originalHandle: OriginalHandleRequest): OriginalHandleRequest {\n return async function sentryInstrumentedHandleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n ) {\n const parameterizedPath =\n routerContext?.staticHandlerContext?.matches?.[routerContext.staticHandlerContext.matches.length - 1]?.route.path;\n\n if (parameterizedPath) {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const rootSpan = getRootSpan(activeSpan);\n const routeName = `/${parameterizedPath}`;\n\n // The express instrumentation writes on the rpcMetadata and that ends up stomping on the `http.route` attribute.\n const rpcMetadata = getRPCMetadata(context.active());\n\n if (rpcMetadata?.type === RPCType.HTTP) {\n rpcMetadata.route = routeName;\n }\n\n // The span exporter picks up the `http.route` (ATTR_HTTP_ROUTE) attribute to set the transaction name\n rootSpan.setAttributes({\n [ATTR_HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME]: `${request.method} ${routeName}`,\n });\n }\n }\n\n return originalHandle(request, responseStatusCode, responseHeaders, routerContext, loadContext);\n };\n}\n\n/** @deprecated Use `wrapSentryHandleRequest` instead. */\nexport const sentryHandleRequest = wrapSentryHandleRequest;\n\n/**\n * Injects Sentry trace meta tags into the HTML response by piping through a transform stream.\n * This enables distributed tracing by adding trace context to the HTML document head.\n *\n * @param body - PassThrough stream containing the HTML response body to modify\n */\nexport function getMetaTagTransformer(body: PassThrough): Transform {\n const headClosingTag = '</head>';\n const htmlMetaTagTransformer = new Transform({\n transform(chunk, _encoding, callback) {\n const html = Buffer.isBuffer(chunk) ? chunk.toString() : String(chunk);\n if (html.includes(headClosingTag)) {\n const modifiedHtml = html.replace(headClosingTag, `${getTraceMetaTags()}${headClosingTag}`);\n callback(null, modifiedHtml);\n return;\n }\n callback(null, chunk);\n },\n });\n htmlMetaTagTransformer.pipe(body);\n return htmlMetaTagTransformer;\n}\n"],"names":["getActiveSpan","getRootSpan","getRPCMetadata","context","RPCType","ATTR_HTTP_ROUTE","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME","Transform","getTraceMetaTags"],"mappings":";;;;;;;;AAsBA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,uBAAuB,CAAC,cAAc,EAAgD;AACtG,EAAE,OAAO,eAAe,+BAA+B;AACvD,IAAI,OAAO;AACX,IAAI,kBAAkB;AACtB,IAAI,eAAe;AACnB,IAAI,aAAa;AACjB,IAAI,WAAW;AACf,IAAI;AACJ,IAAI,MAAM,iBAAkB;AAC5B,MAAM,aAAa,EAAE,oBAAoB,EAAE,OAAO,GAAG,aAAa,CAAC,oBAAoB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI;;AAEvH,IAAI,IAAI,iBAAiB,EAAE;AAC3B,MAAM,MAAM,UAAA,GAAaA,kBAAa,EAAE;AACxC,MAAM,IAAI,UAAU,EAAE;AACtB,QAAQ,MAAM,QAAS,GAAEC,gBAAW,CAAC,UAAU,CAAC;AAChD,QAAQ,MAAM,YAAY,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAA;;AAEA;AACA,QAAA,MAAA,WAAA,GAAAC,qBAAA,CAAAC,WAAA,CAAA,MAAA,EAAA,CAAA;;AAEA,QAAA,IAAA,WAAA,EAAA,IAAA,KAAAC,cAAA,CAAA,IAAA,EAAA;AACA,UAAA,WAAA,CAAA,KAAA,GAAA,SAAA;AACA;;AAEA;AACA,QAAA,QAAA,CAAA,aAAA,CAAA;AACA,UAAA,CAAAC,mCAAA,GAAA,SAAA;AACA,UAAA,CAAAC,qCAAA,GAAA,OAAA;AACA,UAAA,CAAAC,+CAAA,GAAA,CAAA,EAAA,OAAA,CAAA,MAAA,CAAA,CAAA,EAAA,SAAA,CAAA,CAAA;AACA,SAAA,CAAA;AACA;AACA;;AAEA,IAAA,OAAA,cAAA,CAAA,OAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,aAAA,EAAA,WAAA,CAAA;AACA,GAAA;AACA;;AAEA;AACA,MAAA,mBAAA,GAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAA,qBAAA,CAAA,IAAA,EAAA;AACA,EAAA,MAAA,cAAA,GAAA,SAAA;AACA,EAAA,MAAA,sBAAA,GAAA,IAAAC,gBAAA,CAAA;AACA,IAAA,SAAA,CAAA,KAAA,EAAA,SAAA,EAAA,QAAA,EAAA;AACA,MAAA,MAAA,IAAA,GAAA,MAAA,CAAA,QAAA,CAAA,KAAA,CAAA,GAAA,KAAA,CAAA,QAAA,EAAA,GAAA,MAAA,CAAA,KAAA,CAAA;AACA,MAAA,IAAA,IAAA,CAAA,QAAA,CAAA,cAAA,CAAA,EAAA;AACA,QAAA,MAAA,YAAA,GAAA,IAAA,CAAA,OAAA,CAAA,cAAA,EAAA,CAAA,EAAAC,qBAAA,EAAA,CAAA,EAAA,cAAA,CAAA,CAAA,CAAA;AACA,QAAA,QAAA,CAAA,IAAA,EAAA,YAAA,CAAA;AACA,QAAA;AACA;AACA,MAAA,QAAA,CAAA,IAAA,EAAA,KAAA,CAAA;AACA,KAAA;AACA,GAAA,CAAA;AACA,EAAA,sBAAA,CAAA,IAAA,CAAA,IAAA,CAAA;AACA,EAAA,OAAA,sBAAA;AACA;;;;;;"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"9.
|
|
1
|
+
{"type":"module","version":"9.20.0"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
|
|
2
|
+
import { SDK_VERSION, getActiveSpan, getRootSpan, logger, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
|
|
3
|
+
import { DEBUG_BUILD } from '../../common/debug-build.js';
|
|
4
|
+
import { isDataRequest, SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE, getOpName, getSpanName } from './util.js';
|
|
5
|
+
|
|
6
|
+
const supportedVersions = ['>=7.0.0'];
|
|
7
|
+
const COMPONENT = 'react-router';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Instrumentation for React Router's server request handler.
|
|
11
|
+
* This patches the requestHandler function to add Sentry performance monitoring for data loaders.
|
|
12
|
+
*/
|
|
13
|
+
class ReactRouterInstrumentation extends InstrumentationBase {
|
|
14
|
+
constructor(config = {}) {
|
|
15
|
+
super('ReactRouterInstrumentation', SDK_VERSION, config);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Initializes the instrumentation by defining the React Router server modules to be patched.
|
|
20
|
+
*/
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
22
|
+
init() {
|
|
23
|
+
const reactRouterServerModule = new InstrumentationNodeModuleDefinition(
|
|
24
|
+
COMPONENT,
|
|
25
|
+
supportedVersions,
|
|
26
|
+
(moduleExports) => {
|
|
27
|
+
return this._createPatchedModuleProxy(moduleExports);
|
|
28
|
+
},
|
|
29
|
+
(_moduleExports) => {
|
|
30
|
+
// nothing to unwrap here
|
|
31
|
+
return _moduleExports;
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return reactRouterServerModule;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates a proxy around the React Router module exports that patches the createRequestHandler function.
|
|
40
|
+
* This allows us to wrap the request handler to add performance monitoring for data loaders and actions.
|
|
41
|
+
*/
|
|
42
|
+
_createPatchedModuleProxy(moduleExports) {
|
|
43
|
+
return new Proxy(moduleExports, {
|
|
44
|
+
get(target, prop, receiver) {
|
|
45
|
+
if (prop === 'createRequestHandler') {
|
|
46
|
+
const original = target[prop];
|
|
47
|
+
return function sentryWrappedCreateRequestHandler( ...args) {
|
|
48
|
+
const originalRequestHandler = original.apply(this, args);
|
|
49
|
+
|
|
50
|
+
return async function sentryWrappedRequestHandler(request, initialContext) {
|
|
51
|
+
let url;
|
|
52
|
+
try {
|
|
53
|
+
url = new URL(request.url);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return originalRequestHandler(request, initialContext);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// We currently just want to trace loaders and actions
|
|
59
|
+
if (!isDataRequest(url.pathname)) {
|
|
60
|
+
return originalRequestHandler(request, initialContext);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const activeSpan = getActiveSpan();
|
|
64
|
+
const rootSpan = activeSpan && getRootSpan(activeSpan);
|
|
65
|
+
|
|
66
|
+
if (!rootSpan) {
|
|
67
|
+
DEBUG_BUILD && logger.debug('No active root span found, skipping tracing for data request');
|
|
68
|
+
return originalRequestHandler(request, initialContext);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Set the source and overwrite attributes on the root span to ensure the transaction name
|
|
72
|
+
// is derived from the raw URL pathname rather than any parameterized route that may be set later
|
|
73
|
+
// TODO: try to set derived parameterized route from build here (args[0])
|
|
74
|
+
rootSpan.setAttributes({
|
|
75
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
|
|
76
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE]: `${request.method} ${url.pathname}`,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return startSpan(
|
|
80
|
+
{
|
|
81
|
+
name: getSpanName(url.pathname, request.method),
|
|
82
|
+
attributes: {
|
|
83
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react-router',
|
|
84
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: getOpName(url.pathname, request.method),
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
() => {
|
|
88
|
+
return originalRequestHandler(request, initialContext);
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return Reflect.get(target, prop, receiver);
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { ReactRouterInstrumentation };
|
|
101
|
+
//# sourceMappingURL=reactRouter.js.map
|
|
@@ -0,0 +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 {\n getActiveSpan,\n getRootSpan,\n logger,\n SDK_VERSION,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n startSpan,\n} from '@sentry/core';\nimport type * as reactRouter from 'react-router';\nimport { DEBUG_BUILD } from '../../common/debug-build';\nimport { getOpName, getSpanName, isDataRequest, SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE } 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 (error) {\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 && logger.debug('No active root span found, skipping tracing for data request');\n return originalRequestHandler(request, initialContext);\n }\n\n // Set the source and overwrite attributes on the root span to ensure the transaction name\n // is derived from the raw URL pathname rather than any parameterized route that may be set later\n // TODO: try to set derived parameterized route from build here (args[0])\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE]: `${request.method} ${url.pathname}`,\n });\n\n return startSpan(\n {\n name: getSpanName(url.pathname, request.method),\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react-router',\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":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets the op name for a request based on whether it's a loader or action request.
|
|
3
|
+
* @param pathName The URL pathname to check
|
|
4
|
+
* @param requestMethod The HTTP request method
|
|
5
|
+
*/
|
|
6
|
+
function getOpName(pathName, requestMethod) {
|
|
7
|
+
return isLoaderRequest(pathName, requestMethod)
|
|
8
|
+
? 'function.react-router.loader'
|
|
9
|
+
: isActionRequest(pathName, requestMethod)
|
|
10
|
+
? 'function.react-router.action'
|
|
11
|
+
: 'function.react-router';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Gets the span name for a request based on whether it's a loader or action request.
|
|
16
|
+
* @param pathName The URL pathname to check
|
|
17
|
+
* @param requestMethod The HTTP request method
|
|
18
|
+
*/
|
|
19
|
+
function getSpanName(pathName, requestMethod) {
|
|
20
|
+
return isLoaderRequest(pathName, requestMethod)
|
|
21
|
+
? 'Executing Server Loader'
|
|
22
|
+
: isActionRequest(pathName, requestMethod)
|
|
23
|
+
? 'Executing Server Action'
|
|
24
|
+
: 'Unknown Data Request';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Checks if the request is a server loader request
|
|
29
|
+
* @param pathname The URL pathname to check
|
|
30
|
+
* @param requestMethod The HTTP request method
|
|
31
|
+
*/
|
|
32
|
+
function isLoaderRequest(pathname, requestMethod) {
|
|
33
|
+
return isDataRequest(pathname) && requestMethod === 'GET';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Checks if the request is a server action request
|
|
38
|
+
* @param pathname The URL pathname to check
|
|
39
|
+
* @param requestMethod The HTTP request method
|
|
40
|
+
*/
|
|
41
|
+
function isActionRequest(pathname, requestMethod) {
|
|
42
|
+
return isDataRequest(pathname) && requestMethod === 'POST';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Checks if the request is a react-router data request
|
|
47
|
+
* @param pathname The URL pathname to check
|
|
48
|
+
*/
|
|
49
|
+
function isDataRequest(pathname) {
|
|
50
|
+
return pathname.endsWith('.data');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE = 'sentry.overwrite-route';
|
|
54
|
+
|
|
55
|
+
export { SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE, getOpName, getSpanName, isActionRequest, isDataRequest, isLoaderRequest };
|
|
56
|
+
//# sourceMappingURL=util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sources":["../../../../src/server/instrumentation/util.ts"],"sourcesContent":["/**\n * Gets the op name for a request based on whether it's a loader or action request.\n * @param pathName The URL pathname to check\n * @param requestMethod The HTTP request method\n */\nexport function getOpName(pathName: string, requestMethod: string): string {\n return isLoaderRequest(pathName, requestMethod)\n ? 'function.react-router.loader'\n : isActionRequest(pathName, requestMethod)\n ? 'function.react-router.action'\n : 'function.react-router';\n}\n\n/**\n * Gets the span name for a request based on whether it's a loader or action request.\n * @param pathName The URL pathname to check\n * @param requestMethod The HTTP request method\n */\nexport function getSpanName(pathName: string, requestMethod: string): string {\n return isLoaderRequest(pathName, requestMethod)\n ? 'Executing Server Loader'\n : isActionRequest(pathName, requestMethod)\n ? 'Executing Server Action'\n : 'Unknown Data Request';\n}\n\n/**\n * Checks if the request is a server loader request\n * @param pathname The URL pathname to check\n * @param requestMethod The HTTP request method\n */\nexport function isLoaderRequest(pathname: string, requestMethod: string): boolean {\n return isDataRequest(pathname) && requestMethod === 'GET';\n}\n\n/**\n * Checks if the request is a server action request\n * @param pathname The URL pathname to check\n * @param requestMethod The HTTP request method\n */\nexport function isActionRequest(pathname: string, requestMethod: string): boolean {\n return isDataRequest(pathname) && requestMethod === 'POST';\n}\n\n/**\n * Checks if the request is a react-router data request\n * @param pathname The URL pathname to check\n */\nexport function isDataRequest(pathname: string): boolean {\n return pathname.endsWith('.data');\n}\n\nexport const SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE = 'sentry.overwrite-route';\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,QAAQ,EAAU,aAAa,EAAkB;AAC3E,EAAE,OAAO,eAAe,CAAC,QAAQ,EAAE,aAAa;AAChD,MAAM;AACN,MAAM,eAAe,CAAC,QAAQ,EAAE,aAAa;AAC7C,QAAQ;AACR,QAAQ,uBAAuB;AAC/B;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,QAAQ,EAAU,aAAa,EAAkB;AAC7E,EAAE,OAAO,eAAe,CAAC,QAAQ,EAAE,aAAa;AAChD,MAAM;AACN,MAAM,eAAe,CAAC,QAAQ,EAAE,aAAa;AAC7C,QAAQ;AACR,QAAQ,sBAAsB;AAC9B;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,QAAQ,EAAU,aAAa,EAAmB;AAClF,EAAE,OAAO,aAAa,CAAC,QAAQ,KAAK,aAAA,KAAkB,KAAK;AAC3D;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,QAAQ,EAAU,aAAa,EAAmB;AAClF,EAAE,OAAO,aAAa,CAAC,QAAQ,KAAK,aAAA,KAAkB,MAAM;AAC5D;;AAEA;AACA;AACA;AACA;AACO,SAAS,aAAa,CAAC,QAAQ,EAAmB;AACzD,EAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;AACnC;;AAEO,MAAM,mCAAoC,GAAE;;;;"}
|
|
@@ -8,7 +8,7 @@ import { defineIntegration, logger } from '@sentry/core';
|
|
|
8
8
|
function _lowQualityTransactionsFilterIntegration(options)
|
|
9
9
|
|
|
10
10
|
{
|
|
11
|
-
const matchedRegexes = [/GET \/node_modules\//, /GET \/favicon\.ico/, /GET \/@id
|
|
11
|
+
const matchedRegexes = [/GET \/node_modules\//, /GET \/favicon\.ico/, /GET \/@id\//, /GET \/__manifest\?/];
|
|
12
12
|
|
|
13
13
|
return {
|
|
14
14
|
name: 'LowQualityTransactionsFilter',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lowQualityTransactionsFilterIntegration.js","sources":["../../../../src/server/integration/lowQualityTransactionsFilterIntegration.ts"],"sourcesContent":["import { type Client, type Event, type EventHint, defineIntegration, logger } from '@sentry/core';\nimport type { NodeOptions } from '@sentry/node';\n\n/**\n * Integration that filters out noisy http transactions such as requests to node_modules, favicon.ico, @id/\n *\n */\n\nfunction _lowQualityTransactionsFilterIntegration(options: NodeOptions): {\n name: string;\n processEvent: (event: Event, hint: EventHint, client: Client) => Event | null;\n} {\n const matchedRegexes = [/GET \\/node_modules\\//, /GET \\/favicon\\.ico/, /GET \\/@id\\//, /GET \\/__manifest\\?/];\n\n return {\n name: 'LowQualityTransactionsFilter',\n\n processEvent(event: Event, _hint: EventHint, _client: Client): Event | null {\n if (event.type !== 'transaction' || !event.transaction) {\n return event;\n }\n\n const transaction = event.transaction;\n\n if (matchedRegexes.some(regex => transaction.match(regex))) {\n options.debug && logger.log('[ReactRouter] Filtered node_modules transaction:', event.transaction);\n return null;\n }\n\n return event;\n },\n };\n}\n\nexport const lowQualityTransactionsFilterIntegration = defineIntegration((options: NodeOptions) =>\n _lowQualityTransactionsFilterIntegration(options),\n);\n"],"names":[],"mappings":";;AAGA;AACA;AACA;AACA;;AAEA,SAAS,wCAAwC,CAAC,OAAO;;AAGzD,CAAE;AACF,EAAE,MAAM,cAAe,GAAE,CAAC,sBAAsB,EAAE,oBAAoB,EAAE,aAAa,EAAE,oBAAoB,CAAC;;AAE5G,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,8BAA8B;;AAExC,IAAI,YAAY,CAAC,KAAK,EAAS,KAAK,EAAa,OAAO,EAAwB;AAChF,MAAM,IAAI,KAAK,CAAC,IAAK,KAAI,aAAc,IAAG,CAAC,KAAK,CAAC,WAAW,EAAE;AAC9D,QAAQ,OAAO,KAAK;AACpB;;AAEA,MAAM,MAAM,WAAA,GAAc,KAAK,CAAC,WAAW;;AAE3C,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC,KAAA,IAAS,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE;AAClE,QAAQ,OAAO,CAAC,KAAM,IAAG,MAAM,CAAC,GAAG,CAAC,kDAAkD,EAAE,KAAK,CAAC,WAAW,CAAC;AAC1G,QAAQ,OAAO,IAAI;AACnB;;AAEA,MAAM,OAAO,KAAK;AAClB,KAAK;AACL,GAAG;AACH;;MAEa,uCAAwC,GAAE,iBAAiB,CAAC,CAAC,OAAO;AACjF,EAAE,wCAAwC,CAAC,OAAO,CAAC;AACnD;;;;"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { defineIntegration } from '@sentry/core';
|
|
2
|
+
import { generateInstrumentOnce } from '@sentry/node';
|
|
3
|
+
import { ReactRouterInstrumentation } from '../instrumentation/reactRouter.js';
|
|
4
|
+
|
|
5
|
+
const INTEGRATION_NAME = 'ReactRouterServer';
|
|
6
|
+
|
|
7
|
+
const instrumentReactRouter = generateInstrumentOnce('React-Router-Server', () => {
|
|
8
|
+
return new ReactRouterInstrumentation();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const instrumentReactRouterServer = Object.assign(
|
|
12
|
+
() => {
|
|
13
|
+
instrumentReactRouter();
|
|
14
|
+
},
|
|
15
|
+
{ id: INTEGRATION_NAME },
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Integration capturing tracing data for React Router server functions.
|
|
20
|
+
*/
|
|
21
|
+
const reactRouterServerIntegration = defineIntegration(() => {
|
|
22
|
+
return {
|
|
23
|
+
name: INTEGRATION_NAME,
|
|
24
|
+
setupOnce() {
|
|
25
|
+
instrumentReactRouterServer();
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export { instrumentReactRouterServer, reactRouterServerIntegration };
|
|
31
|
+
//# sourceMappingURL=reactRouterServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactRouterServer.js","sources":["../../../../src/server/integration/reactRouterServer.ts"],"sourcesContent":["import { defineIntegration } from '@sentry/core';\nimport { generateInstrumentOnce } from '@sentry/node';\nimport { ReactRouterInstrumentation } from '../instrumentation/reactRouter';\n\nconst INTEGRATION_NAME = 'ReactRouterServer';\n\nconst instrumentReactRouter = generateInstrumentOnce('React-Router-Server', () => {\n return new ReactRouterInstrumentation();\n});\n\nexport const instrumentReactRouterServer = Object.assign(\n (): void => {\n instrumentReactRouter();\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 instrumentReactRouterServer();\n },\n };\n});\n"],"names":[],"mappings":";;;;AAIA,MAAM,gBAAA,GAAmB,mBAAmB;;AAE5C,MAAM,qBAAA,GAAwB,sBAAsB,CAAC,qBAAqB,EAAE,MAAM;AAClF,EAAE,OAAO,IAAI,0BAA0B,EAAE;AACzC,CAAC,CAAC;;AAEW,MAAA,2BAAA,GAA8B,MAAM,CAAC,MAAM;AACxD,EAAE,MAAY;AACd,IAAI,qBAAqB,EAAE;AAC3B,GAAG;AACH,EAAE,EAAE,EAAE,EAAE,gBAAA,EAAkB;AAC1B;;AAEA;AACA;AACA;MACa,4BAA6B,GAAE,iBAAiB,CAAC,MAAM;AACpE,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,SAAS,GAAG;AAChB,MAAM,2BAA2B,EAAE;AACnC,KAAK;AACL,GAAG;AACH,CAAC;;;;"}
|
package/build/esm/server/sdk.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';
|
|
2
|
+
import { logger, applySdkMetadata, setTag, getGlobalScope } from '@sentry/core';
|
|
3
|
+
import { init as init$1, getDefaultIntegrations } from '@sentry/node';
|
|
3
4
|
import { DEBUG_BUILD } from '../common/debug-build.js';
|
|
4
|
-
import {
|
|
5
|
+
import { SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE } from './instrumentation/util.js';
|
|
6
|
+
import { lowQualityTransactionsFilterIntegration } from './integration/lowQualityTransactionsFilterIntegration.js';
|
|
7
|
+
import { reactRouterServerIntegration } from './integration/reactRouterServer.js';
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Returns the default integrations for the React Router SDK.
|
|
11
|
+
* @param options The options for the SDK.
|
|
12
|
+
*/
|
|
13
|
+
function getDefaultReactRouterServerIntegrations(options) {
|
|
14
|
+
return [
|
|
15
|
+
...getDefaultIntegrations(options),
|
|
16
|
+
lowQualityTransactionsFilterIntegration(options),
|
|
17
|
+
reactRouterServerIntegration(),
|
|
18
|
+
];
|
|
8
19
|
}
|
|
9
20
|
|
|
10
21
|
/**
|
|
@@ -13,7 +24,7 @@ function getDefaultIntegrations(options) {
|
|
|
13
24
|
function init(options) {
|
|
14
25
|
const opts = {
|
|
15
26
|
...options,
|
|
16
|
-
defaultIntegrations:
|
|
27
|
+
defaultIntegrations: getDefaultReactRouterServerIntegrations(options),
|
|
17
28
|
};
|
|
18
29
|
|
|
19
30
|
DEBUG_BUILD && logger.log('Initializing SDK...');
|
|
@@ -24,10 +35,35 @@ function init(options) {
|
|
|
24
35
|
|
|
25
36
|
setTag('runtime', 'node');
|
|
26
37
|
|
|
38
|
+
// Overwrite the transaction name for instrumented data loaders because the trace data gets overwritten at a later point.
|
|
39
|
+
// We only update the tx in case SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE got set in our instrumentation before.
|
|
40
|
+
getGlobalScope().addEventProcessor(
|
|
41
|
+
Object.assign(
|
|
42
|
+
(event => {
|
|
43
|
+
const overwrite = event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE];
|
|
44
|
+
if (
|
|
45
|
+
event.type === 'transaction' &&
|
|
46
|
+
(event.transaction === 'GET *' || event.transaction === 'POST *') &&
|
|
47
|
+
event.contexts?.trace?.data?.[ATTR_HTTP_ROUTE] === '*' &&
|
|
48
|
+
overwrite
|
|
49
|
+
) {
|
|
50
|
+
event.transaction = overwrite;
|
|
51
|
+
event.contexts.trace.data[ATTR_HTTP_ROUTE] = 'url';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// always yeet this attribute into the void, as this should not reach the server
|
|
55
|
+
delete event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE];
|
|
56
|
+
|
|
57
|
+
return event;
|
|
58
|
+
}) ,
|
|
59
|
+
{ id: 'ReactRouterTransactionEnhancer' },
|
|
60
|
+
),
|
|
61
|
+
);
|
|
62
|
+
|
|
27
63
|
DEBUG_BUILD && logger.log('SDK successfully initialized');
|
|
28
64
|
|
|
29
65
|
return client;
|
|
30
66
|
}
|
|
31
67
|
|
|
32
|
-
export { init };
|
|
68
|
+
export { getDefaultReactRouterServerIntegrations, init };
|
|
33
69
|
//# sourceMappingURL=sdk.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport { applySdkMetadata, logger, setTag } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getNodeDefaultIntegrations, init as initNodeSdk } from '@sentry/node';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { lowQualityTransactionsFilterIntegration } from './lowQualityTransactionsFilterIntegration';\n\
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport type { EventProcessor, Integration } from '@sentry/core';\nimport { applySdkMetadata, getGlobalScope, logger, setTag } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getNodeDefaultIntegrations, init as initNodeSdk } from '@sentry/node';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE } from './instrumentation/util';\nimport { lowQualityTransactionsFilterIntegration } from './integration/lowQualityTransactionsFilterIntegration';\nimport { reactRouterServerIntegration } from './integration/reactRouterServer';\n\n/**\n * Returns the default integrations for the React Router SDK.\n * @param options The options for the SDK.\n */\nexport function getDefaultReactRouterServerIntegrations(options: NodeOptions): Integration[] {\n return [\n ...getNodeDefaultIntegrations(options),\n lowQualityTransactionsFilterIntegration(options),\n reactRouterServerIntegration(),\n ];\n}\n\n/**\n * Initializes the server side of the React Router SDK\n */\nexport function init(options: NodeOptions): NodeClient | undefined {\n const opts: NodeOptions = {\n ...options,\n defaultIntegrations: getDefaultReactRouterServerIntegrations(options),\n };\n\n DEBUG_BUILD && logger.log('Initializing SDK...');\n\n applySdkMetadata(opts, 'react-router', ['react-router', 'node']);\n\n const client = initNodeSdk(opts);\n\n setTag('runtime', 'node');\n\n // Overwrite the transaction name for instrumented data loaders because the trace data gets overwritten at a later point.\n // We only update the tx in case SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE got set in our instrumentation before.\n getGlobalScope().addEventProcessor(\n Object.assign(\n (event => {\n const overwrite = event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE];\n if (\n event.type === 'transaction' &&\n (event.transaction === 'GET *' || event.transaction === 'POST *') &&\n event.contexts?.trace?.data?.[ATTR_HTTP_ROUTE] === '*' &&\n overwrite\n ) {\n event.transaction = overwrite;\n event.contexts.trace.data[ATTR_HTTP_ROUTE] = 'url';\n }\n\n // always yeet this attribute into the void, as this should not reach the server\n delete event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE];\n\n return event;\n }) satisfies EventProcessor,\n { id: 'ReactRouterTransactionEnhancer' },\n ),\n );\n\n DEBUG_BUILD && logger.log('SDK successfully initialized');\n\n return client;\n}\n"],"names":["getNodeDefaultIntegrations","initNodeSdk"],"mappings":";;;;;;;;AAUA;AACA;AACA;AACA;AACO,SAAS,uCAAuC,CAAC,OAAO,EAA8B;AAC7F,EAAE,OAAO;AACT,IAAI,GAAGA,sBAA0B,CAAC,OAAO,CAAC;AAC1C,IAAI,uCAAuC,CAAC,OAAO,CAAC;AACpD,IAAI,4BAA4B,EAAE;AAClC,GAAG;AACH;;AAEA;AACA;AACA;AACO,SAAS,IAAI,CAAC,OAAO,EAAuC;AACnE,EAAE,MAAM,IAAI,GAAgB;AAC5B,IAAI,GAAG,OAAO;AACd,IAAI,mBAAmB,EAAE,uCAAuC,CAAC,OAAO,CAAC;AACzE,GAAG;;AAEH,EAAE,eAAe,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC;;AAElD,EAAE,gBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;;AAElE,EAAE,MAAM,MAAO,GAAEC,MAAW,CAAC,IAAI,CAAC;;AAElC,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC;;AAE3B;AACA;AACA,EAAE,cAAc,EAAE,CAAC,iBAAiB;AACpC,IAAI,MAAM,CAAC,MAAM;AACjB,OAAO,SAAS;AAChB,QAAQ,MAAM,SAAA,GAAY,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,GAAG,mCAAmC,CAAC;AAC5F,QAAQ;AACR,UAAU,KAAK,CAAC,IAAK,KAAI,aAAc;AACvC,WAAW,KAAK,CAAC,WAAA,KAAgB,OAAA,IAAW,KAAK,CAAC,WAAA,KAAgB,QAAQ,CAAE;AAC5E,UAAU,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,GAAG,eAAe,CAAE,KAAI,GAAI;AACjE,UAAU;AACV,UAAU;AACV,UAAU,KAAK,CAAC,WAAY,GAAE,SAAS;AACvC,UAAU,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAE,GAAE,KAAK;AAC5D;;AAEA;AACA,QAAQ,OAAO,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,GAAG,mCAAmC,CAAC;;AAEjF,QAAQ,OAAO,KAAK;AACpB,OAAO;AACP,MAAM,EAAE,EAAE,EAAE,gCAAA,EAAkC;AAC9C,KAAK;AACL,GAAG;;AAEH,EAAE,eAAe,MAAM,CAAC,GAAG,CAAC,8BAA8B,CAAC;;AAE3D,EAAE,OAAO,MAAM;AACf;;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { context } from '@opentelemetry/api';
|
|
2
2
|
import { getRPCMetadata, RPCType } from '@opentelemetry/core';
|
|
3
3
|
import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';
|
|
4
|
-
import { getActiveSpan, getRootSpan, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getTraceMetaTags } from '@sentry/core';
|
|
4
|
+
import { getActiveSpan, getRootSpan, SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getTraceMetaTags } from '@sentry/core';
|
|
5
5
|
import { Transform } from 'stream';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -20,6 +20,7 @@ function wrapSentryHandleRequest(originalHandle) {
|
|
|
20
20
|
) {
|
|
21
21
|
const parameterizedPath =
|
|
22
22
|
routerContext?.staticHandlerContext?.matches?.[routerContext.staticHandlerContext.matches.length - 1]?.route.path;
|
|
23
|
+
|
|
23
24
|
if (parameterizedPath) {
|
|
24
25
|
const activeSpan = getActiveSpan();
|
|
25
26
|
if (activeSpan) {
|
|
@@ -28,6 +29,7 @@ function wrapSentryHandleRequest(originalHandle) {
|
|
|
28
29
|
|
|
29
30
|
// The express instrumentation writes on the rpcMetadata and that ends up stomping on the `http.route` attribute.
|
|
30
31
|
const rpcMetadata = getRPCMetadata(context.active());
|
|
32
|
+
|
|
31
33
|
if (rpcMetadata?.type === RPCType.HTTP) {
|
|
32
34
|
rpcMetadata.route = routeName;
|
|
33
35
|
}
|
|
@@ -36,6 +38,7 @@ function wrapSentryHandleRequest(originalHandle) {
|
|
|
36
38
|
rootSpan.setAttributes({
|
|
37
39
|
[ATTR_HTTP_ROUTE]: routeName,
|
|
38
40
|
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
|
|
41
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME]: `${request.method} ${routeName}`,
|
|
39
42
|
});
|
|
40
43
|
}
|
|
41
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapSentryHandleRequest.js","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"sourcesContent":["import { context } from '@opentelemetry/api';\nimport { getRPCMetadata, RPCType } from '@opentelemetry/core';\nimport { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport {
|
|
1
|
+
{"version":3,"file":"wrapSentryHandleRequest.js","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"sourcesContent":["import { context } from '@opentelemetry/api';\nimport { getRPCMetadata, RPCType } from '@opentelemetry/core';\nimport { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport {\n getActiveSpan,\n getRootSpan,\n getTraceMetaTags,\n SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n} from '@sentry/core';\nimport type { AppLoadContext, EntryContext } from 'react-router';\nimport type { PassThrough } from 'stream';\nimport { Transform } from 'stream';\n\ntype OriginalHandleRequest = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(originalHandle: OriginalHandleRequest): OriginalHandleRequest {\n return async function sentryInstrumentedHandleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n ) {\n const parameterizedPath =\n routerContext?.staticHandlerContext?.matches?.[routerContext.staticHandlerContext.matches.length - 1]?.route.path;\n\n if (parameterizedPath) {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const rootSpan = getRootSpan(activeSpan);\n const routeName = `/${parameterizedPath}`;\n\n // The express instrumentation writes on the rpcMetadata and that ends up stomping on the `http.route` attribute.\n const rpcMetadata = getRPCMetadata(context.active());\n\n if (rpcMetadata?.type === RPCType.HTTP) {\n rpcMetadata.route = routeName;\n }\n\n // The span exporter picks up the `http.route` (ATTR_HTTP_ROUTE) attribute to set the transaction name\n rootSpan.setAttributes({\n [ATTR_HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME]: `${request.method} ${routeName}`,\n });\n }\n }\n\n return originalHandle(request, responseStatusCode, responseHeaders, routerContext, loadContext);\n };\n}\n\n/** @deprecated Use `wrapSentryHandleRequest` instead. */\nexport const sentryHandleRequest = wrapSentryHandleRequest;\n\n/**\n * Injects Sentry trace meta tags into the HTML response by piping through a transform stream.\n * This enables distributed tracing by adding trace context to the HTML document head.\n *\n * @param body - PassThrough stream containing the HTML response body to modify\n */\nexport function getMetaTagTransformer(body: PassThrough): Transform {\n const headClosingTag = '</head>';\n const htmlMetaTagTransformer = new Transform({\n transform(chunk, _encoding, callback) {\n const html = Buffer.isBuffer(chunk) ? chunk.toString() : String(chunk);\n if (html.includes(headClosingTag)) {\n const modifiedHtml = html.replace(headClosingTag, `${getTraceMetaTags()}${headClosingTag}`);\n callback(null, modifiedHtml);\n return;\n }\n callback(null, chunk);\n },\n });\n htmlMetaTagTransformer.pipe(body);\n return htmlMetaTagTransformer;\n}\n"],"names":[],"mappings":";;;;;;AAsBA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,uBAAuB,CAAC,cAAc,EAAgD;AACtG,EAAE,OAAO,eAAe,+BAA+B;AACvD,IAAI,OAAO;AACX,IAAI,kBAAkB;AACtB,IAAI,eAAe;AACnB,IAAI,aAAa;AACjB,IAAI,WAAW;AACf,IAAI;AACJ,IAAI,MAAM,iBAAkB;AAC5B,MAAM,aAAa,EAAE,oBAAoB,EAAE,OAAO,GAAG,aAAa,CAAC,oBAAoB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI;;AAEvH,IAAI,IAAI,iBAAiB,EAAE;AAC3B,MAAM,MAAM,UAAA,GAAa,aAAa,EAAE;AACxC,MAAM,IAAI,UAAU,EAAE;AACtB,QAAQ,MAAM,QAAS,GAAE,WAAW,CAAC,UAAU,CAAC;AAChD,QAAQ,MAAM,YAAY,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAA;;AAEA;AACA,QAAA,MAAA,WAAA,GAAA,cAAA,CAAA,OAAA,CAAA,MAAA,EAAA,CAAA;;AAEA,QAAA,IAAA,WAAA,EAAA,IAAA,KAAA,OAAA,CAAA,IAAA,EAAA;AACA,UAAA,WAAA,CAAA,KAAA,GAAA,SAAA;AACA;;AAEA;AACA,QAAA,QAAA,CAAA,aAAA,CAAA;AACA,UAAA,CAAA,eAAA,GAAA,SAAA;AACA,UAAA,CAAA,gCAAA,GAAA,OAAA;AACA,UAAA,CAAA,0CAAA,GAAA,CAAA,EAAA,OAAA,CAAA,MAAA,CAAA,CAAA,EAAA,SAAA,CAAA,CAAA;AACA,SAAA,CAAA;AACA;AACA;;AAEA,IAAA,OAAA,cAAA,CAAA,OAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,aAAA,EAAA,WAAA,CAAA;AACA,GAAA;AACA;;AAEA;AACA,MAAA,mBAAA,GAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAA,qBAAA,CAAA,IAAA,EAAA;AACA,EAAA,MAAA,cAAA,GAAA,SAAA;AACA,EAAA,MAAA,sBAAA,GAAA,IAAA,SAAA,CAAA;AACA,IAAA,SAAA,CAAA,KAAA,EAAA,SAAA,EAAA,QAAA,EAAA;AACA,MAAA,MAAA,IAAA,GAAA,MAAA,CAAA,QAAA,CAAA,KAAA,CAAA,GAAA,KAAA,CAAA,QAAA,EAAA,GAAA,MAAA,CAAA,KAAA,CAAA;AACA,MAAA,IAAA,IAAA,CAAA,QAAA,CAAA,cAAA,CAAA,EAAA;AACA,QAAA,MAAA,YAAA,GAAA,IAAA,CAAA,OAAA,CAAA,cAAA,EAAA,CAAA,EAAA,gBAAA,EAAA,CAAA,EAAA,cAAA,CAAA,CAAA,CAAA;AACA,QAAA,QAAA,CAAA,IAAA,EAAA,YAAA,CAAA;AACA,QAAA;AACA;AACA,MAAA,QAAA,CAAA,IAAA,EAAA,KAAA,CAAA;AACA,KAAA;AACA,GAAA,CAAA;AACA,EAAA,sBAAA,CAAA,IAAA,CAAA,IAAA,CAAA;AACA,EAAA,OAAA,sBAAA;AACA;;;;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { InstrumentationConfig } from '@opentelemetry/instrumentation';
|
|
2
|
+
import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
|
|
3
|
+
/**
|
|
4
|
+
* Instrumentation for React Router's server request handler.
|
|
5
|
+
* This patches the requestHandler function to add Sentry performance monitoring for data loaders.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ReactRouterInstrumentation extends InstrumentationBase<InstrumentationConfig> {
|
|
8
|
+
constructor(config?: InstrumentationConfig);
|
|
9
|
+
/**
|
|
10
|
+
* Initializes the instrumentation by defining the React Router server modules to be patched.
|
|
11
|
+
*/
|
|
12
|
+
protected init(): InstrumentationNodeModuleDefinition;
|
|
13
|
+
/**
|
|
14
|
+
* Creates a proxy around the React Router module exports that patches the createRequestHandler function.
|
|
15
|
+
* This allows us to wrap the request handler to add performance monitoring for data loaders and actions.
|
|
16
|
+
*/
|
|
17
|
+
private _createPatchedModuleProxy;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=reactRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactRouter.d.ts","sourceRoot":"","sources":["../../../../src/server/instrumentation/reactRouter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,mCAAmC,EAAE,MAAM,gCAAgC,CAAC;AAoB1G;;;GAGG;AACH,qBAAa,0BAA2B,SAAQ,mBAAmB,CAAC,qBAAqB,CAAC;gBACrE,MAAM,GAAE,qBAA0B;IAIrD;;OAEG;IAEH,SAAS,CAAC,IAAI,IAAI,mCAAmC;IAgBrD;;;OAGG;IACH,OAAO,CAAC,yBAAyB;CAwDlC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets the op name for a request based on whether it's a loader or action request.
|
|
3
|
+
* @param pathName The URL pathname to check
|
|
4
|
+
* @param requestMethod The HTTP request method
|
|
5
|
+
*/
|
|
6
|
+
export declare function getOpName(pathName: string, requestMethod: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Gets the span name for a request based on whether it's a loader or action request.
|
|
9
|
+
* @param pathName The URL pathname to check
|
|
10
|
+
* @param requestMethod The HTTP request method
|
|
11
|
+
*/
|
|
12
|
+
export declare function getSpanName(pathName: string, requestMethod: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Checks if the request is a server loader request
|
|
15
|
+
* @param pathname The URL pathname to check
|
|
16
|
+
* @param requestMethod The HTTP request method
|
|
17
|
+
*/
|
|
18
|
+
export declare function isLoaderRequest(pathname: string, requestMethod: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Checks if the request is a server action request
|
|
21
|
+
* @param pathname The URL pathname to check
|
|
22
|
+
* @param requestMethod The HTTP request method
|
|
23
|
+
*/
|
|
24
|
+
export declare function isActionRequest(pathname: string, requestMethod: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Checks if the request is a react-router data request
|
|
27
|
+
* @param pathname The URL pathname to check
|
|
28
|
+
*/
|
|
29
|
+
export declare function isDataRequest(pathname: string): boolean;
|
|
30
|
+
export declare const SEMANTIC_ATTRIBUTE_SENTRY_OVERWRITE = "sentry.overwrite-route";
|
|
31
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../src/server/instrumentation/util.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAMzE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAM3E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAEhF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAEhF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,eAAO,MAAM,mCAAmC,2BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lowQualityTransactionsFilterIntegration.d.ts","sourceRoot":"","sources":["../../../../src/server/integration/lowQualityTransactionsFilterIntegration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAiChD,eAAO,MAAM,uCAAuC,8DAEnD,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const instrumentReactRouterServer: (() => void) & {
|
|
2
|
+
id: string;
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* Integration capturing tracing data for React Router server functions.
|
|
6
|
+
*/
|
|
7
|
+
export declare const reactRouterServerIntegration: () => import("@sentry/core").Integration;
|
|
8
|
+
//# sourceMappingURL=reactRouterServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactRouterServer.d.ts","sourceRoot":"","sources":["../../../../src/server/integration/reactRouterServer.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,2BAA2B,SAClC,IAAI;;CAIT,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,4BAA4B,0CAOvC,CAAC"}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import type { Integration } from '@sentry/core';
|
|
1
2
|
import type { NodeClient, NodeOptions } from '@sentry/node';
|
|
3
|
+
/**
|
|
4
|
+
* Returns the default integrations for the React Router SDK.
|
|
5
|
+
* @param options The options for the SDK.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getDefaultReactRouterServerIntegrations(options: NodeOptions): Integration[];
|
|
2
8
|
/**
|
|
3
9
|
* Initializes the server side of the React Router SDK
|
|
4
10
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../../src/server/sdk.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../../src/server/sdk.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAO5D;;;GAGG;AACH,wBAAgB,uCAAuC,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,EAAE,CAM3F;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,CA0CjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapSentryHandleRequest.d.ts","sourceRoot":"","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"wrapSentryHandleRequest.d.ts","sourceRoot":"","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"names":[],"mappings":";AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEnC,KAAK,qBAAqB,GAAG,CAC3B,OAAO,EAAE,OAAO,EAChB,kBAAkB,EAAE,MAAM,EAC1B,eAAe,EAAE,OAAO,EACxB,aAAa,EAAE,YAAY,EAC3B,WAAW,EAAE,cAAc,KACxB,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,qBAAqB,GAAG,qBAAqB,CAmCpG;AAED,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,gCAA0B,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,CAelE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/react-router",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.20.0",
|
|
4
4
|
"description": "Official Sentry SDK for React Router (Framework)",
|
|
5
5
|
"repository": "git://github.com/getsentry/sentry-javascript.git",
|
|
6
6
|
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/react-router",
|
|
@@ -36,11 +36,12 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@opentelemetry/api": "^1.9.0",
|
|
38
38
|
"@opentelemetry/core": "^1.30.1",
|
|
39
|
+
"@opentelemetry/instrumentation": "0.57.2",
|
|
39
40
|
"@opentelemetry/semantic-conventions": "^1.30.0",
|
|
40
|
-
"@sentry/browser": "9.
|
|
41
|
+
"@sentry/browser": "9.20.0",
|
|
41
42
|
"@sentry/cli": "^2.43.0",
|
|
42
|
-
"@sentry/core": "9.
|
|
43
|
-
"@sentry/node": "9.
|
|
43
|
+
"@sentry/core": "9.20.0",
|
|
44
|
+
"@sentry/node": "9.20.0",
|
|
44
45
|
"@sentry/vite-plugin": "^3.2.4",
|
|
45
46
|
"glob": "11.0.1"
|
|
46
47
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lowQualityTransactionsFilterIntegration.js","sources":["../../../src/server/lowQualityTransactionsFilterIntegration.ts"],"sourcesContent":["import { type Client, type Event, type EventHint, defineIntegration, logger } from '@sentry/core';\nimport type { NodeOptions } from '@sentry/node';\n\n/**\n * Integration that filters out noisy http transactions such as requests to node_modules, favicon.ico, @id/\n *\n */\n\nfunction _lowQualityTransactionsFilterIntegration(options: NodeOptions): {\n name: string;\n processEvent: (event: Event, hint: EventHint, client: Client) => Event | null;\n} {\n const matchedRegexes = [/GET \\/node_modules\\//, /GET \\/favicon\\.ico/, /GET \\/@id\\//];\n\n return {\n name: 'LowQualityTransactionsFilter',\n\n processEvent(event: Event, _hint: EventHint, _client: Client): Event | null {\n if (event.type !== 'transaction' || !event.transaction) {\n return event;\n }\n\n const transaction = event.transaction;\n\n if (matchedRegexes.some(regex => transaction.match(regex))) {\n options.debug && logger.log('[ReactRouter] Filtered node_modules transaction:', event.transaction);\n return null;\n }\n\n return event;\n },\n };\n}\n\nexport const lowQualityTransactionsFilterIntegration = defineIntegration((options: NodeOptions) =>\n _lowQualityTransactionsFilterIntegration(options),\n);\n"],"names":["logger","defineIntegration"],"mappings":";;;;AAGA;AACA;AACA;AACA;;AAEA,SAAS,wCAAwC,CAAC,OAAO;;AAGzD,CAAE;AACF,EAAE,MAAM,iBAAiB,CAAC,sBAAsB,EAAE,oBAAoB,EAAE,aAAa,CAAC;;AAEtF,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,8BAA8B;;AAExC,IAAI,YAAY,CAAC,KAAK,EAAS,KAAK,EAAa,OAAO,EAAwB;AAChF,MAAM,IAAI,KAAK,CAAC,IAAK,KAAI,aAAc,IAAG,CAAC,KAAK,CAAC,WAAW,EAAE;AAC9D,QAAQ,OAAO,KAAK;AACpB;;AAEA,MAAM,MAAM,WAAA,GAAc,KAAK,CAAC,WAAW;;AAE3C,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC,KAAA,IAAS,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE;AAClE,QAAQ,OAAO,CAAC,KAAM,IAAGA,WAAM,CAAC,GAAG,CAAC,kDAAkD,EAAE,KAAK,CAAC,WAAW,CAAC;AAC1G,QAAQ,OAAO,IAAI;AACnB;;AAEA,MAAM,OAAO,KAAK;AAClB,KAAK;AACL,GAAG;AACH;;MAEa,uCAAwC,GAAEC,sBAAiB,CAAC,CAAC,OAAO;AACjF,EAAE,wCAAwC,CAAC,OAAO,CAAC;AACnD;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lowQualityTransactionsFilterIntegration.js","sources":["../../../src/server/lowQualityTransactionsFilterIntegration.ts"],"sourcesContent":["import { type Client, type Event, type EventHint, defineIntegration, logger } from '@sentry/core';\nimport type { NodeOptions } from '@sentry/node';\n\n/**\n * Integration that filters out noisy http transactions such as requests to node_modules, favicon.ico, @id/\n *\n */\n\nfunction _lowQualityTransactionsFilterIntegration(options: NodeOptions): {\n name: string;\n processEvent: (event: Event, hint: EventHint, client: Client) => Event | null;\n} {\n const matchedRegexes = [/GET \\/node_modules\\//, /GET \\/favicon\\.ico/, /GET \\/@id\\//];\n\n return {\n name: 'LowQualityTransactionsFilter',\n\n processEvent(event: Event, _hint: EventHint, _client: Client): Event | null {\n if (event.type !== 'transaction' || !event.transaction) {\n return event;\n }\n\n const transaction = event.transaction;\n\n if (matchedRegexes.some(regex => transaction.match(regex))) {\n options.debug && logger.log('[ReactRouter] Filtered node_modules transaction:', event.transaction);\n return null;\n }\n\n return event;\n },\n };\n}\n\nexport const lowQualityTransactionsFilterIntegration = defineIntegration((options: NodeOptions) =>\n _lowQualityTransactionsFilterIntegration(options),\n);\n"],"names":[],"mappings":";;AAGA;AACA;AACA;AACA;;AAEA,SAAS,wCAAwC,CAAC,OAAO;;AAGzD,CAAE;AACF,EAAE,MAAM,iBAAiB,CAAC,sBAAsB,EAAE,oBAAoB,EAAE,aAAa,CAAC;;AAEtF,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,8BAA8B;;AAExC,IAAI,YAAY,CAAC,KAAK,EAAS,KAAK,EAAa,OAAO,EAAwB;AAChF,MAAM,IAAI,KAAK,CAAC,IAAK,KAAI,aAAc,IAAG,CAAC,KAAK,CAAC,WAAW,EAAE;AAC9D,QAAQ,OAAO,KAAK;AACpB;;AAEA,MAAM,MAAM,WAAA,GAAc,KAAK,CAAC,WAAW;;AAE3C,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC,KAAA,IAAS,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE;AAClE,QAAQ,OAAO,CAAC,KAAM,IAAG,MAAM,CAAC,GAAG,CAAC,kDAAkD,EAAE,KAAK,CAAC,WAAW,CAAC;AAC1G,QAAQ,OAAO,IAAI;AACnB;;AAEA,MAAM,OAAO,KAAK;AAClB,KAAK;AACL,GAAG;AACH;;MAEa,uCAAwC,GAAE,iBAAiB,CAAC,CAAC,OAAO;AACjF,EAAE,wCAAwC,CAAC,OAAO,CAAC;AACnD;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lowQualityTransactionsFilterIntegration.d.ts","sourceRoot":"","sources":["../../../src/server/lowQualityTransactionsFilterIntegration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAiChD,eAAO,MAAM,uCAAuC,8DAEnD,CAAC"}
|