@sentry/node 9.16.0 → 9.17.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/index.js +18 -18
- package/build/cjs/integrations/anr/index.js +1 -1
- package/build/cjs/integrations/http/index.js +0 -18
- package/build/cjs/integrations/http/index.js.map +1 -1
- package/build/cjs/integrations/local-variables/local-variables-async.js +1 -1
- package/build/cjs/integrations/tracing/fastify/index.js +187 -0
- package/build/cjs/integrations/tracing/fastify/index.js.map +1 -0
- package/build/cjs/integrations/tracing/fastify/v3/constants.js +23 -0
- package/build/cjs/integrations/tracing/fastify/v3/constants.js.map +1 -0
- package/build/cjs/integrations/tracing/fastify/v3/enums/AttributeNames.js +37 -0
- package/build/cjs/integrations/tracing/fastify/v3/enums/AttributeNames.js.map +1 -0
- package/build/cjs/integrations/tracing/fastify/v3/instrumentation.js +303 -0
- package/build/cjs/integrations/tracing/fastify/v3/instrumentation.js.map +1 -0
- package/build/cjs/integrations/tracing/fastify/v3/utils.js +135 -0
- package/build/cjs/integrations/tracing/fastify/v3/utils.js.map +1 -0
- package/build/cjs/integrations/tracing/index.js +11 -10
- package/build/cjs/integrations/tracing/index.js.map +1 -1
- package/build/esm/index.js +1 -1
- package/build/esm/integrations/anr/index.js +1 -1
- package/build/esm/integrations/anr/worker-script.js +2 -2
- package/build/esm/integrations/http/index.js +0 -18
- package/build/esm/integrations/http/index.js.map +1 -1
- package/build/esm/integrations/local-variables/local-variables-async.js +1 -1
- package/build/esm/integrations/local-variables/worker-script.js +2 -2
- package/build/esm/integrations/tracing/fastify/index.js +182 -0
- package/build/esm/integrations/tracing/fastify/index.js.map +1 -0
- package/build/esm/integrations/tracing/fastify/v3/constants.js +21 -0
- package/build/esm/integrations/tracing/fastify/v3/constants.js.map +1 -0
- package/build/esm/integrations/tracing/fastify/v3/enums/AttributeNames.js +37 -0
- package/build/esm/integrations/tracing/fastify/v3/enums/AttributeNames.js.map +1 -0
- package/build/esm/integrations/tracing/fastify/v3/instrumentation.js +301 -0
- package/build/esm/integrations/tracing/fastify/v3/instrumentation.js.map +1 -0
- package/build/esm/integrations/tracing/fastify/v3/utils.js +131 -0
- package/build/esm/integrations/tracing/fastify/v3/utils.js.map +1 -0
- package/build/esm/integrations/tracing/index.js +2 -1
- package/build/esm/integrations/tracing/index.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/types/integrations/http/index.d.ts.map +1 -1
- package/build/{types-ts3.8/integrations/tracing/fastify.d.ts → types/integrations/tracing/fastify/index.d.ts} +83 -103
- package/build/types/integrations/tracing/fastify/index.d.ts.map +1 -0
- package/build/types/integrations/tracing/fastify/types.d.ts +25 -0
- package/build/types/integrations/tracing/fastify/types.d.ts.map +1 -0
- package/build/types/integrations/tracing/fastify/v3/constants.d.ts +3 -0
- package/build/types/integrations/tracing/fastify/v3/constants.d.ts.map +1 -0
- package/build/types/integrations/tracing/fastify/v3/enums/AttributeNames.d.ts +15 -0
- package/build/types/integrations/tracing/fastify/v3/enums/AttributeNames.d.ts.map +1 -0
- package/build/types/integrations/tracing/fastify/v3/instrumentation.d.ts +16 -0
- package/build/types/integrations/tracing/fastify/v3/instrumentation.d.ts.map +1 -0
- package/build/types/integrations/tracing/fastify/v3/internal-types.d.ts +7 -0
- package/build/types/integrations/tracing/fastify/v3/internal-types.d.ts.map +1 -0
- package/build/types/integrations/tracing/fastify/v3/types.d.ts +21 -0
- package/build/types/integrations/tracing/fastify/v3/types.d.ts.map +1 -0
- package/build/types/integrations/tracing/fastify/v3/utils.d.ts +28 -0
- package/build/types/integrations/tracing/fastify/v3/utils.d.ts.map +1 -0
- package/build/types/integrations/tracing/index.d.ts.map +1 -1
- package/build/{types/integrations/tracing/fastify.d.ts → types-ts3.8/integrations/tracing/fastify/index.d.ts} +83 -103
- package/build/types-ts3.8/integrations/tracing/fastify/types.d.ts +25 -0
- package/build/types-ts3.8/integrations/tracing/fastify/v3/constants.d.ts +3 -0
- package/build/types-ts3.8/integrations/tracing/fastify/v3/enums/AttributeNames.d.ts +15 -0
- package/build/types-ts3.8/integrations/tracing/fastify/v3/instrumentation.d.ts +16 -0
- package/build/types-ts3.8/integrations/tracing/fastify/v3/internal-types.d.ts +7 -0
- package/build/types-ts3.8/integrations/tracing/fastify/v3/types.d.ts +21 -0
- package/build/types-ts3.8/integrations/tracing/fastify/v3/utils.d.ts +28 -0
- package/package.json +4 -4
- package/build/cjs/integrations/http/SentryHttpInstrumentationBeforeOtel.js +0 -136
- package/build/cjs/integrations/http/SentryHttpInstrumentationBeforeOtel.js.map +0 -1
- package/build/cjs/integrations/http/utils.js +0 -44
- package/build/cjs/integrations/http/utils.js.map +0 -1
- package/build/cjs/integrations/tracing/fastify.js +0 -160
- package/build/cjs/integrations/tracing/fastify.js.map +0 -1
- package/build/esm/integrations/http/SentryHttpInstrumentationBeforeOtel.js +0 -134
- package/build/esm/integrations/http/SentryHttpInstrumentationBeforeOtel.js.map +0 -1
- package/build/esm/integrations/http/utils.js +0 -42
- package/build/esm/integrations/http/utils.js.map +0 -1
- package/build/esm/integrations/tracing/fastify.js +0 -156
- package/build/esm/integrations/tracing/fastify.js.map +0 -1
- package/build/types/integrations/http/SentryHttpInstrumentationBeforeOtel.d.ts +0 -17
- package/build/types/integrations/http/SentryHttpInstrumentationBeforeOtel.d.ts.map +0 -1
- package/build/types/integrations/tracing/fastify.d.ts.map +0 -1
- package/build/types-ts3.8/integrations/http/SentryHttpInstrumentationBeforeOtel.d.ts +0 -20
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Span } from '@opentelemetry/api';
|
|
2
|
+
import { InstrumentationConfig } from '@opentelemetry/instrumentation';
|
|
3
|
+
export interface FastifyRequestInfo {
|
|
4
|
+
request: any;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Function that can be used to add custom attributes to the current span
|
|
8
|
+
* @param span - The Fastify handler span.
|
|
9
|
+
* @param info - The Fastify request info object.
|
|
10
|
+
*/
|
|
11
|
+
export interface FastifyCustomAttributeFunction {
|
|
12
|
+
(span: Span, info: FastifyRequestInfo): void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Options available for the Fastify Instrumentation
|
|
16
|
+
*/
|
|
17
|
+
export interface FastifyInstrumentationConfig extends InstrumentationConfig {
|
|
18
|
+
/** Function for adding custom attributes to each handler span */
|
|
19
|
+
requestHook?: FastifyCustomAttributeFunction;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Attributes, Span, Tracer } from '@opentelemetry/api';
|
|
2
|
+
import { PluginFastifyReply } from './internal-types';
|
|
3
|
+
/**
|
|
4
|
+
* Starts Span
|
|
5
|
+
* @param reply - reply function
|
|
6
|
+
* @param tracer - tracer
|
|
7
|
+
* @param spanName - span name
|
|
8
|
+
* @param spanAttributes - span attributes
|
|
9
|
+
*/
|
|
10
|
+
export declare function startSpan(reply: PluginFastifyReply, tracer: Tracer, spanName: string, spanAttributes?: Attributes): Span;
|
|
11
|
+
/**
|
|
12
|
+
* Ends span
|
|
13
|
+
* @param reply - reply function
|
|
14
|
+
* @param err - error
|
|
15
|
+
*/
|
|
16
|
+
export declare function endSpan(reply: PluginFastifyReply, err?: any): void;
|
|
17
|
+
/**
|
|
18
|
+
* This function handles the missing case from instrumentation package when
|
|
19
|
+
* execute can either return a promise or void. And using async is not an
|
|
20
|
+
* option as it is producing unwanted side effects.
|
|
21
|
+
* @param execute - function to be executed
|
|
22
|
+
* @param onFinish - function called when function executed
|
|
23
|
+
* @param preventThrowingError - prevent to throw error when execute
|
|
24
|
+
* function fails
|
|
25
|
+
*/
|
|
26
|
+
export declare function safeExecuteInTheMiddleMaybePromise<T>(execute: () => Promise<T>, onFinish: (e: unknown, result?: T) => void, preventThrowingError?: boolean): Promise<T>;
|
|
27
|
+
export declare function safeExecuteInTheMiddleMaybePromise<T>(execute: () => T, onFinish: (e: unknown, result?: T) => void, preventThrowingError?: boolean): T;
|
|
28
|
+
//# sourceMappingURL=utils.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/node",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.17.0",
|
|
4
4
|
"description": "Sentry Node SDK using OpenTelemetry for performance instrumentation",
|
|
5
5
|
"repository": "git://github.com/getsentry/sentry-javascript.git",
|
|
6
6
|
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/node",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"access": "public"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
+
"@fastify/otel": "0.6.0",
|
|
68
69
|
"@opentelemetry/api": "^1.9.0",
|
|
69
70
|
"@opentelemetry/context-async-hooks": "^1.30.1",
|
|
70
71
|
"@opentelemetry/core": "^1.30.1",
|
|
@@ -73,7 +74,6 @@
|
|
|
73
74
|
"@opentelemetry/instrumentation-connect": "0.43.1",
|
|
74
75
|
"@opentelemetry/instrumentation-dataloader": "0.16.1",
|
|
75
76
|
"@opentelemetry/instrumentation-express": "0.47.1",
|
|
76
|
-
"@opentelemetry/instrumentation-fastify": "0.44.2",
|
|
77
77
|
"@opentelemetry/instrumentation-fs": "0.19.1",
|
|
78
78
|
"@opentelemetry/instrumentation-generic-pool": "0.43.1",
|
|
79
79
|
"@opentelemetry/instrumentation-graphql": "0.47.1",
|
|
@@ -96,8 +96,8 @@
|
|
|
96
96
|
"@opentelemetry/sdk-trace-base": "^1.30.1",
|
|
97
97
|
"@opentelemetry/semantic-conventions": "^1.30.0",
|
|
98
98
|
"@prisma/instrumentation": "6.7.0",
|
|
99
|
-
"@sentry/core": "9.
|
|
100
|
-
"@sentry/opentelemetry": "9.
|
|
99
|
+
"@sentry/core": "9.17.0",
|
|
100
|
+
"@sentry/opentelemetry": "9.17.0",
|
|
101
101
|
"import-in-the-middle": "^1.13.0"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
|
|
3
|
-
const core = require('@opentelemetry/core');
|
|
4
|
-
const instrumentation = require('@opentelemetry/instrumentation');
|
|
5
|
-
const core$1 = require('@sentry/core');
|
|
6
|
-
const debugBuild = require('../../debug-build.js');
|
|
7
|
-
const utils = require('./utils.js');
|
|
8
|
-
|
|
9
|
-
// The reason this "before OTEL" integration even exists is due to timing reasons. We need to be able to register a
|
|
10
|
-
// `res.on('close')` handler **after** OTEL registers its own handler (which it uses to end spans), so that we can do
|
|
11
|
-
// something (ie. flush) after OTEL has ended a span for a request. If you think about it like an onion:
|
|
12
|
-
//
|
|
13
|
-
// (Sentry after OTEL instrumentation
|
|
14
|
-
// (OTEL instrumentation
|
|
15
|
-
// (Sentry before OTEL instrumentation
|
|
16
|
-
// (orig HTTP request handler))))
|
|
17
|
-
//
|
|
18
|
-
// registering an instrumentation before OTEL allows us to do this for incoming requests.
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* A Sentry specific http instrumentation that is applied before the otel instrumentation.
|
|
22
|
-
*/
|
|
23
|
-
class SentryHttpInstrumentationBeforeOtel extends instrumentation.InstrumentationBase {
|
|
24
|
-
constructor() {
|
|
25
|
-
super('@sentry/instrumentation-http-before-otel', core.VERSION, {});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
29
|
-
init() {
|
|
30
|
-
return [this._getHttpsInstrumentation(), this._getHttpInstrumentation()];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Get the instrumentation for the http module. */
|
|
34
|
-
_getHttpInstrumentation() {
|
|
35
|
-
return new instrumentation.InstrumentationNodeModuleDefinition('http', ['*'], (moduleExports) => {
|
|
36
|
-
// Patch incoming requests
|
|
37
|
-
utils.stealthWrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction());
|
|
38
|
-
|
|
39
|
-
return moduleExports;
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Get the instrumentation for the https module. */
|
|
44
|
-
_getHttpsInstrumentation() {
|
|
45
|
-
return new instrumentation.InstrumentationNodeModuleDefinition('https', ['*'], (moduleExports) => {
|
|
46
|
-
// Patch incoming requests
|
|
47
|
-
utils.stealthWrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction());
|
|
48
|
-
|
|
49
|
-
return moduleExports;
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Patch the incoming request function for request isolation.
|
|
55
|
-
*/
|
|
56
|
-
_getPatchIncomingRequestFunction()
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
return (
|
|
60
|
-
original,
|
|
61
|
-
) => {
|
|
62
|
-
return function incomingRequest( ...args) {
|
|
63
|
-
// Only traces request events
|
|
64
|
-
if (args[0] !== 'request') {
|
|
65
|
-
return original.apply(this, args);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const response = args[2] ;
|
|
69
|
-
patchResponseToFlushOnServerlessPlatforms(response);
|
|
70
|
-
|
|
71
|
-
return original.apply(this, args);
|
|
72
|
-
};
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function patchResponseToFlushOnServerlessPlatforms(res) {
|
|
78
|
-
// Freely extend this function with other platforms if necessary
|
|
79
|
-
if (process.env.VERCEL) {
|
|
80
|
-
debugBuild.DEBUG_BUILD && core$1.logger.log('Patching response to flush on Vercel');
|
|
81
|
-
|
|
82
|
-
// In some cases res.end does not seem to be defined leading to errors if passed to Proxy
|
|
83
|
-
// https://github.com/getsentry/sentry-javascript/issues/15759
|
|
84
|
-
if (typeof res.end !== 'function') {
|
|
85
|
-
debugBuild.DEBUG_BUILD && core$1.logger.warn('res.end is not a function, skipping patch...');
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
let markOnEndDone = () => undefined;
|
|
90
|
-
const onEndDonePromise = new Promise(res => {
|
|
91
|
-
markOnEndDone = res;
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
res.on('close', () => {
|
|
95
|
-
markOnEndDone();
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
core$1.logger.log('Patching res.end()');
|
|
99
|
-
|
|
100
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
101
|
-
res.end = new Proxy(res.end, {
|
|
102
|
-
apply(target, thisArg, argArray) {
|
|
103
|
-
core$1.vercelWaitUntil(
|
|
104
|
-
new Promise(finishWaitUntil => {
|
|
105
|
-
// Define a timeout that unblocks the lambda just to be safe so we're not indefinitely keeping it alive, exploding server bills
|
|
106
|
-
const timeout = setTimeout(() => {
|
|
107
|
-
finishWaitUntil();
|
|
108
|
-
}, 2000);
|
|
109
|
-
|
|
110
|
-
onEndDonePromise
|
|
111
|
-
.then(() => {
|
|
112
|
-
debugBuild.DEBUG_BUILD && core$1.logger.log('Flushing events before Vercel Lambda freeze');
|
|
113
|
-
return core$1.flush(2000);
|
|
114
|
-
})
|
|
115
|
-
.then(
|
|
116
|
-
() => {
|
|
117
|
-
clearTimeout(timeout);
|
|
118
|
-
finishWaitUntil();
|
|
119
|
-
},
|
|
120
|
-
e => {
|
|
121
|
-
clearTimeout(timeout);
|
|
122
|
-
debugBuild.DEBUG_BUILD && core$1.logger.log('Error while flushing events for Vercel:\n', e);
|
|
123
|
-
finishWaitUntil();
|
|
124
|
-
},
|
|
125
|
-
);
|
|
126
|
-
}),
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
return target.apply(thisArg, argArray);
|
|
130
|
-
},
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
exports.SentryHttpInstrumentationBeforeOtel = SentryHttpInstrumentationBeforeOtel;
|
|
136
|
-
//# sourceMappingURL=SentryHttpInstrumentationBeforeOtel.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SentryHttpInstrumentationBeforeOtel.js","sources":["../../../../src/integrations/http/SentryHttpInstrumentationBeforeOtel.ts"],"sourcesContent":["import type * as http from 'node:http';\nimport type * as https from 'node:https';\nimport { VERSION } from '@opentelemetry/core';\nimport { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';\nimport { flush, logger, vercelWaitUntil } from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { stealthWrap } from './utils';\n\ntype Http = typeof http;\ntype Https = typeof https;\n\n// The reason this \"before OTEL\" integration even exists is due to timing reasons. We need to be able to register a\n// `res.on('close')` handler **after** OTEL registers its own handler (which it uses to end spans), so that we can do\n// something (ie. flush) after OTEL has ended a span for a request. If you think about it like an onion:\n//\n// (Sentry after OTEL instrumentation\n// (OTEL instrumentation\n// (Sentry before OTEL instrumentation\n// (orig HTTP request handler))))\n//\n// registering an instrumentation before OTEL allows us to do this for incoming requests.\n\n/**\n * A Sentry specific http instrumentation that is applied before the otel instrumentation.\n */\nexport class SentryHttpInstrumentationBeforeOtel extends InstrumentationBase {\n public constructor() {\n super('@sentry/instrumentation-http-before-otel', VERSION, {});\n }\n\n // eslint-disable-next-line jsdoc/require-jsdoc\n public init(): [InstrumentationNodeModuleDefinition, InstrumentationNodeModuleDefinition] {\n return [this._getHttpsInstrumentation(), this._getHttpInstrumentation()];\n }\n\n /** Get the instrumentation for the http module. */\n private _getHttpInstrumentation(): InstrumentationNodeModuleDefinition {\n return new InstrumentationNodeModuleDefinition('http', ['*'], (moduleExports: Http): Http => {\n // Patch incoming requests\n stealthWrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction());\n\n return moduleExports;\n });\n }\n\n /** Get the instrumentation for the https module. */\n private _getHttpsInstrumentation(): InstrumentationNodeModuleDefinition {\n return new InstrumentationNodeModuleDefinition('https', ['*'], (moduleExports: Https): Https => {\n // Patch incoming requests\n stealthWrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction());\n\n return moduleExports;\n });\n }\n\n /**\n * Patch the incoming request function for request isolation.\n */\n private _getPatchIncomingRequestFunction(): (\n original: (event: string, ...args: unknown[]) => boolean,\n ) => (this: unknown, event: string, ...args: unknown[]) => boolean {\n return (\n original: (event: string, ...args: unknown[]) => boolean,\n ): ((this: unknown, event: string, ...args: unknown[]) => boolean) => {\n return function incomingRequest(this: unknown, ...args: [event: string, ...args: unknown[]]): boolean {\n // Only traces request events\n if (args[0] !== 'request') {\n return original.apply(this, args);\n }\n\n const response = args[2] as http.OutgoingMessage;\n patchResponseToFlushOnServerlessPlatforms(response);\n\n return original.apply(this, args);\n };\n };\n }\n}\n\nfunction patchResponseToFlushOnServerlessPlatforms(res: http.OutgoingMessage): void {\n // Freely extend this function with other platforms if necessary\n if (process.env.VERCEL) {\n DEBUG_BUILD && logger.log('Patching response to flush on Vercel');\n\n // In some cases res.end does not seem to be defined leading to errors if passed to Proxy\n // https://github.com/getsentry/sentry-javascript/issues/15759\n if (typeof res.end !== 'function') {\n DEBUG_BUILD && logger.warn('res.end is not a function, skipping patch...');\n return;\n }\n\n let markOnEndDone = (): void => undefined;\n const onEndDonePromise = new Promise<void>(res => {\n markOnEndDone = res;\n });\n\n res.on('close', () => {\n markOnEndDone();\n });\n\n logger.log('Patching res.end()');\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n res.end = new Proxy(res.end, {\n apply(target, thisArg, argArray) {\n vercelWaitUntil(\n new Promise<void>(finishWaitUntil => {\n // Define a timeout that unblocks the lambda just to be safe so we're not indefinitely keeping it alive, exploding server bills\n const timeout = setTimeout(() => {\n finishWaitUntil();\n }, 2000);\n\n onEndDonePromise\n .then(() => {\n DEBUG_BUILD && logger.log('Flushing events before Vercel Lambda freeze');\n return flush(2000);\n })\n .then(\n () => {\n clearTimeout(timeout);\n finishWaitUntil();\n },\n e => {\n clearTimeout(timeout);\n DEBUG_BUILD && logger.log('Error while flushing events for Vercel:\\n', e);\n finishWaitUntil();\n },\n );\n }),\n );\n\n return target.apply(thisArg, argArray);\n },\n });\n }\n}\n"],"names":["InstrumentationBase","VERSION","InstrumentationNodeModuleDefinition","stealthWrap","DEBUG_BUILD","logger","vercelWaitUntil","flush"],"mappings":"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"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* This is a minimal version of `wrap` from shimmer:
|
|
5
|
-
* https://github.com/othiym23/shimmer/blob/master/index.js
|
|
6
|
-
*
|
|
7
|
-
* In contrast to the original implementation, this version does not allow to unwrap,
|
|
8
|
-
* and does not make it clear that the method is wrapped.
|
|
9
|
-
* This is necessary because we want to wrap the http module with our own code,
|
|
10
|
-
* while still allowing to use the HttpInstrumentation from OTEL.
|
|
11
|
-
*
|
|
12
|
-
* Without this, if we'd just use `wrap` from shimmer, the OTEL instrumentation would remove our wrapping,
|
|
13
|
-
* because it only allows any module to be wrapped a single time.
|
|
14
|
-
*/
|
|
15
|
-
function stealthWrap(
|
|
16
|
-
nodule,
|
|
17
|
-
name,
|
|
18
|
-
wrapper,
|
|
19
|
-
) {
|
|
20
|
-
const original = nodule[name];
|
|
21
|
-
const wrapped = wrapper(original);
|
|
22
|
-
|
|
23
|
-
defineProperty(nodule, name, wrapped);
|
|
24
|
-
return wrapped;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Sets a property on an object, preserving its enumerability.
|
|
28
|
-
function defineProperty(
|
|
29
|
-
obj,
|
|
30
|
-
name,
|
|
31
|
-
value,
|
|
32
|
-
) {
|
|
33
|
-
const enumerable = !!obj[name] && Object.prototype.propertyIsEnumerable.call(obj, name);
|
|
34
|
-
|
|
35
|
-
Object.defineProperty(obj, name, {
|
|
36
|
-
configurable: true,
|
|
37
|
-
enumerable: enumerable,
|
|
38
|
-
writable: true,
|
|
39
|
-
value: value,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
exports.stealthWrap = stealthWrap;
|
|
44
|
-
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../../src/integrations/http/utils.ts"],"sourcesContent":["/**\n * This is a minimal version of `wrap` from shimmer:\n * https://github.com/othiym23/shimmer/blob/master/index.js\n *\n * In contrast to the original implementation, this version does not allow to unwrap,\n * and does not make it clear that the method is wrapped.\n * This is necessary because we want to wrap the http module with our own code,\n * while still allowing to use the HttpInstrumentation from OTEL.\n *\n * Without this, if we'd just use `wrap` from shimmer, the OTEL instrumentation would remove our wrapping,\n * because it only allows any module to be wrapped a single time.\n */\nexport function stealthWrap<Nodule extends object, FieldName extends keyof Nodule>(\n nodule: Nodule,\n name: FieldName,\n wrapper: (original: Nodule[FieldName]) => Nodule[FieldName],\n): Nodule[FieldName] {\n const original = nodule[name];\n const wrapped = wrapper(original);\n\n defineProperty(nodule, name, wrapped);\n return wrapped;\n}\n\n// Sets a property on an object, preserving its enumerability.\nfunction defineProperty<Nodule extends object, FieldName extends keyof Nodule>(\n obj: Nodule,\n name: FieldName,\n value: Nodule[FieldName],\n): void {\n const enumerable = !!obj[name] && Object.prototype.propertyIsEnumerable.call(obj, name);\n\n Object.defineProperty(obj, name, {\n configurable: true,\n enumerable: enumerable,\n writable: true,\n value: value,\n });\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW;AAC3B,EAAE,MAAM;AACR,EAAE,IAAI;AACN,EAAE,OAAO;AACT,EAAqB;AACrB,EAAE,MAAM,QAAS,GAAE,MAAM,CAAC,IAAI,CAAC;AAC/B,EAAE,MAAM,OAAQ,GAAE,OAAO,CAAC,QAAQ,CAAC;;AAEnC,EAAE,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;AACvC,EAAE,OAAO,OAAO;AAChB;;AAEA;AACA,SAAS,cAAc;AACvB,EAAE,GAAG;AACL,EAAE,IAAI;AACN,EAAE,KAAK;AACP,EAAQ;AACR,EAAE,MAAM,aAAa,CAAC,CAAC,GAAG,CAAC,IAAI,CAAE,IAAG,MAAM,CAAC,SAAS,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC;;AAEzF,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE;AACnC,IAAI,YAAY,EAAE,IAAI;AACtB,IAAI,UAAU,EAAE,UAAU;AAC1B,IAAI,QAAQ,EAAE,IAAI;AAClB,IAAI,KAAK,EAAE,KAAK;AAChB,GAAG,CAAC;AACJ;;;;"}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
|
|
3
|
-
const instrumentationFastify = require('@opentelemetry/instrumentation-fastify');
|
|
4
|
-
const core = require('@sentry/core');
|
|
5
|
-
const instrument = require('../../otel/instrument.js');
|
|
6
|
-
const ensureIsWrapped = require('../../utils/ensureIsWrapped.js');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Minimal request type containing properties around route information.
|
|
10
|
-
* Works for Fastify 3, 4 and presumably 5.
|
|
11
|
-
*
|
|
12
|
-
* Based on https://github.com/fastify/fastify/blob/ce3811f5f718be278bbcd4392c615d64230065a6/types/request.d.ts
|
|
13
|
-
*/
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
-
|
|
16
|
-
const INTEGRATION_NAME = 'Fastify';
|
|
17
|
-
|
|
18
|
-
const instrumentFastify = instrument.generateInstrumentOnce(
|
|
19
|
-
INTEGRATION_NAME,
|
|
20
|
-
() =>
|
|
21
|
-
// eslint-disable-next-line deprecation/deprecation
|
|
22
|
-
new instrumentationFastify.FastifyInstrumentation({
|
|
23
|
-
requestHook(span) {
|
|
24
|
-
addFastifySpanAttributes(span);
|
|
25
|
-
},
|
|
26
|
-
}),
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
const _fastifyIntegration = (() => {
|
|
30
|
-
return {
|
|
31
|
-
name: INTEGRATION_NAME,
|
|
32
|
-
setupOnce() {
|
|
33
|
-
instrumentFastify();
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
}) ;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Adds Sentry tracing instrumentation for [Fastify](https://fastify.dev/).
|
|
40
|
-
*
|
|
41
|
-
* If you also want to capture errors, you need to call `setupFastifyErrorHandler(app)` after you set up your Fastify server.
|
|
42
|
-
*
|
|
43
|
-
* For more information, see the [fastify documentation](https://docs.sentry.io/platforms/javascript/guides/fastify/).
|
|
44
|
-
*
|
|
45
|
-
* @example
|
|
46
|
-
* ```javascript
|
|
47
|
-
* const Sentry = require('@sentry/node');
|
|
48
|
-
*
|
|
49
|
-
* Sentry.init({
|
|
50
|
-
* integrations: [Sentry.fastifyIntegration()],
|
|
51
|
-
* })
|
|
52
|
-
* ```
|
|
53
|
-
*/
|
|
54
|
-
const fastifyIntegration = core.defineIntegration(_fastifyIntegration);
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Default function to determine if an error should be sent to Sentry
|
|
58
|
-
*
|
|
59
|
-
* 3xx and 4xx errors are not sent by default.
|
|
60
|
-
*/
|
|
61
|
-
function defaultShouldHandleError(_error, _request, reply) {
|
|
62
|
-
const statusCode = reply.statusCode;
|
|
63
|
-
// 3xx and 4xx errors are not sent by default.
|
|
64
|
-
return statusCode >= 500 || statusCode <= 299;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Add an Fastify error handler to capture errors to Sentry.
|
|
69
|
-
*
|
|
70
|
-
* @param fastify The Fastify instance to which to add the error handler
|
|
71
|
-
* @param options Configuration options for the handler
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* ```javascript
|
|
75
|
-
* const Sentry = require('@sentry/node');
|
|
76
|
-
* const Fastify = require("fastify");
|
|
77
|
-
*
|
|
78
|
-
* const app = Fastify();
|
|
79
|
-
*
|
|
80
|
-
* Sentry.setupFastifyErrorHandler(app);
|
|
81
|
-
*
|
|
82
|
-
* // Add your routes, etc.
|
|
83
|
-
*
|
|
84
|
-
* app.listen({ port: 3000 });
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
function setupFastifyErrorHandler(fastify, options) {
|
|
88
|
-
const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;
|
|
89
|
-
|
|
90
|
-
const plugin = Object.assign(
|
|
91
|
-
function (fastify, _options, done) {
|
|
92
|
-
fastify.addHook('onError', async (request, reply, error) => {
|
|
93
|
-
if (shouldHandleError(error, request, reply)) {
|
|
94
|
-
core.captureException(error);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// registering `onRequest` hook here instead of using Otel `onRequest` callback b/c `onRequest` hook
|
|
99
|
-
// is ironically called in the fastify `preHandler` hook which is called later in the lifecycle:
|
|
100
|
-
// https://fastify.dev/docs/latest/Reference/Lifecycle/
|
|
101
|
-
fastify.addHook('onRequest', async (request, _reply) => {
|
|
102
|
-
// Taken from Otel Fastify instrumentation:
|
|
103
|
-
// https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/plugins/node/opentelemetry-instrumentation-fastify/src/instrumentation.ts#L94-L96
|
|
104
|
-
const routeName = request.routeOptions?.url || request.routerPath;
|
|
105
|
-
const method = request.method || 'GET';
|
|
106
|
-
|
|
107
|
-
core.getIsolationScope().setTransactionName(`${method} ${routeName}`);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
done();
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
[Symbol.for('skip-override')]: true,
|
|
114
|
-
[Symbol.for('fastify.display-name')]: 'sentry-fastify-error-handler',
|
|
115
|
-
},
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
fastify.register(plugin);
|
|
119
|
-
|
|
120
|
-
// Sadly, middleware spans do not go through `requestHook`, so we handle those here
|
|
121
|
-
// We register this hook in this method, because if we register it in the integration `setup`,
|
|
122
|
-
// it would always run even for users that are not even using fastify
|
|
123
|
-
const client = core.getClient();
|
|
124
|
-
if (client) {
|
|
125
|
-
client.on('spanStart', span => {
|
|
126
|
-
addFastifySpanAttributes(span);
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
ensureIsWrapped.ensureIsWrapped(fastify.addHook, 'fastify');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function addFastifySpanAttributes(span) {
|
|
134
|
-
const attributes = core.spanToJSON(span).data;
|
|
135
|
-
|
|
136
|
-
// this is one of: middleware, request_handler
|
|
137
|
-
const type = attributes['fastify.type'];
|
|
138
|
-
|
|
139
|
-
// If this is already set, or we have no fastify span, no need to process again...
|
|
140
|
-
if (attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] || !type) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
span.setAttributes({
|
|
145
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.fastify',
|
|
146
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: `${type}.fastify`,
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Also update the name, we don't need to "middleware - " prefix
|
|
150
|
-
const name = attributes['fastify.name'] || attributes['plugin.name'] || attributes['hook.name'];
|
|
151
|
-
if (typeof name === 'string') {
|
|
152
|
-
// Also remove `fastify -> ` prefix
|
|
153
|
-
span.updateName(name.replace(/^fastify -> /, ''));
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
exports.fastifyIntegration = fastifyIntegration;
|
|
158
|
-
exports.instrumentFastify = instrumentFastify;
|
|
159
|
-
exports.setupFastifyErrorHandler = setupFastifyErrorHandler;
|
|
160
|
-
//# sourceMappingURL=fastify.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fastify.js","sources":["../../../../src/integrations/tracing/fastify.ts"],"sourcesContent":["import { FastifyInstrumentation } from '@opentelemetry/instrumentation-fastify';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n captureException,\n defineIntegration,\n getClient,\n getIsolationScope,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport { generateInstrumentOnce } from '../../otel/instrument';\nimport { ensureIsWrapped } from '../../utils/ensureIsWrapped';\n\n/**\n * Minimal request type containing properties around route information.\n * Works for Fastify 3, 4 and presumably 5.\n *\n * Based on https://github.com/fastify/fastify/blob/ce3811f5f718be278bbcd4392c615d64230065a6/types/request.d.ts\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ninterface MinimalFastifyRequest extends Record<string, any> {\n method?: string;\n // since fastify@4.10.0\n routeOptions?: {\n url?: string;\n };\n routerPath?: string;\n}\n\n/**\n * Minimal reply type containing properties needed for error handling.\n *\n * Based on https://github.com/fastify/fastify/blob/ce3811f5f718be278bbcd4392c615d64230065a6/types/reply.d.ts\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ninterface MinimalFastifyReply extends Record<string, any> {\n statusCode: number;\n}\n\n// We inline the types we care about here\ninterface Fastify {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n register: (plugin: any) => void;\n addHook: (hook: string, handler: (...params: unknown[]) => void) => void;\n}\n\ninterface FastifyWithHooks extends Omit<Fastify, 'addHook'> {\n addHook(\n hook: 'onError',\n handler: (request: MinimalFastifyRequest, reply: MinimalFastifyReply, error: Error) => void,\n ): void;\n addHook(hook: 'onRequest', handler: (request: MinimalFastifyRequest, reply: MinimalFastifyReply) => void): void;\n}\n\ninterface FastifyHandlerOptions {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n *\n * @param error Captured Fastify error\n * @param request Fastify request (or any object containing at least method, routeOptions.url, and routerPath)\n * @param reply Fastify reply (or any object containing at least statusCode)\n *\n * @example\n *\n * ```javascript\n * setupFastifyErrorHandler(app, {\n * shouldHandleError(_error, _request, reply) {\n * return reply.statusCode >= 400;\n * },\n * });\n * ```\n *\n * If using TypeScript, you can cast the request and reply to get full type safety.\n *\n * ```typescript\n * import type { FastifyRequest, FastifyReply } from 'fastify';\n *\n * setupFastifyErrorHandler(app, {\n * shouldHandleError(error, minimalRequest, minimalReply) {\n * const request = minimalRequest as FastifyRequest;\n * const reply = minimalReply as FastifyReply;\n * return reply.statusCode >= 500;\n * },\n * });\n * ```\n */\n shouldHandleError: (error: Error, request: MinimalFastifyRequest, reply: MinimalFastifyReply) => boolean;\n}\n\nconst INTEGRATION_NAME = 'Fastify';\n\nexport const instrumentFastify = generateInstrumentOnce(\n INTEGRATION_NAME,\n () =>\n // eslint-disable-next-line deprecation/deprecation\n new FastifyInstrumentation({\n requestHook(span) {\n addFastifySpanAttributes(span);\n },\n }),\n);\n\nconst _fastifyIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentFastify();\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for [Fastify](https://fastify.dev/).\n *\n * If you also want to capture errors, you need to call `setupFastifyErrorHandler(app)` after you set up your Fastify server.\n *\n * For more information, see the [fastify documentation](https://docs.sentry.io/platforms/javascript/guides/fastify/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.fastifyIntegration()],\n * })\n * ```\n */\nexport const fastifyIntegration = defineIntegration(_fastifyIntegration);\n\n/**\n * Default function to determine if an error should be sent to Sentry\n *\n * 3xx and 4xx errors are not sent by default.\n */\nfunction defaultShouldHandleError(_error: Error, _request: MinimalFastifyRequest, reply: MinimalFastifyReply): boolean {\n const statusCode = reply.statusCode;\n // 3xx and 4xx errors are not sent by default.\n return statusCode >= 500 || statusCode <= 299;\n}\n\n/**\n * Add an Fastify error handler to capture errors to Sentry.\n *\n * @param fastify The Fastify instance to which to add the error handler\n * @param options Configuration options for the handler\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n * const Fastify = require(\"fastify\");\n *\n * const app = Fastify();\n *\n * Sentry.setupFastifyErrorHandler(app);\n *\n * // Add your routes, etc.\n *\n * app.listen({ port: 3000 });\n * ```\n */\nexport function setupFastifyErrorHandler(fastify: Fastify, options?: Partial<FastifyHandlerOptions>): void {\n const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;\n\n const plugin = Object.assign(\n function (fastify: FastifyWithHooks, _options: unknown, done: () => void): void {\n fastify.addHook('onError', async (request, reply, error) => {\n if (shouldHandleError(error, request, reply)) {\n captureException(error);\n }\n });\n\n // registering `onRequest` hook here instead of using Otel `onRequest` callback b/c `onRequest` hook\n // is ironically called in the fastify `preHandler` hook which is called later in the lifecycle:\n // https://fastify.dev/docs/latest/Reference/Lifecycle/\n fastify.addHook('onRequest', async (request, _reply) => {\n // Taken from Otel Fastify instrumentation:\n // https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/plugins/node/opentelemetry-instrumentation-fastify/src/instrumentation.ts#L94-L96\n const routeName = request.routeOptions?.url || request.routerPath;\n const method = request.method || 'GET';\n\n getIsolationScope().setTransactionName(`${method} ${routeName}`);\n });\n\n done();\n },\n {\n [Symbol.for('skip-override')]: true,\n [Symbol.for('fastify.display-name')]: 'sentry-fastify-error-handler',\n },\n );\n\n fastify.register(plugin);\n\n // Sadly, middleware spans do not go through `requestHook`, so we handle those here\n // We register this hook in this method, because if we register it in the integration `setup`,\n // it would always run even for users that are not even using fastify\n const client = getClient();\n if (client) {\n client.on('spanStart', span => {\n addFastifySpanAttributes(span);\n });\n }\n\n ensureIsWrapped(fastify.addHook, 'fastify');\n}\n\nfunction addFastifySpanAttributes(span: Span): void {\n const attributes = spanToJSON(span).data;\n\n // this is one of: middleware, request_handler\n const type = attributes['fastify.type'];\n\n // If this is already set, or we have no fastify span, no need to process again...\n if (attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] || !type) {\n return;\n }\n\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.fastify',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `${type}.fastify`,\n });\n\n // Also update the name, we don't need to \"middleware - \" prefix\n const name = attributes['fastify.name'] || attributes['plugin.name'] || attributes['hook.name'];\n if (typeof name === 'string') {\n // Also remove `fastify -> ` prefix\n span.updateName(name.replace(/^fastify -> /, ''));\n }\n}\n"],"names":["generateInstrumentOnce","FastifyInstrumentation","defineIntegration","captureException","getIsolationScope","getClient","ensureIsWrapped","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN"],"mappings":"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"}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { VERSION } from '@opentelemetry/core';
|
|
2
|
-
import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
|
|
3
|
-
import { logger, vercelWaitUntil, flush } from '@sentry/core';
|
|
4
|
-
import { DEBUG_BUILD } from '../../debug-build.js';
|
|
5
|
-
import { stealthWrap } from './utils.js';
|
|
6
|
-
|
|
7
|
-
// The reason this "before OTEL" integration even exists is due to timing reasons. We need to be able to register a
|
|
8
|
-
// `res.on('close')` handler **after** OTEL registers its own handler (which it uses to end spans), so that we can do
|
|
9
|
-
// something (ie. flush) after OTEL has ended a span for a request. If you think about it like an onion:
|
|
10
|
-
//
|
|
11
|
-
// (Sentry after OTEL instrumentation
|
|
12
|
-
// (OTEL instrumentation
|
|
13
|
-
// (Sentry before OTEL instrumentation
|
|
14
|
-
// (orig HTTP request handler))))
|
|
15
|
-
//
|
|
16
|
-
// registering an instrumentation before OTEL allows us to do this for incoming requests.
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* A Sentry specific http instrumentation that is applied before the otel instrumentation.
|
|
20
|
-
*/
|
|
21
|
-
class SentryHttpInstrumentationBeforeOtel extends InstrumentationBase {
|
|
22
|
-
constructor() {
|
|
23
|
-
super('@sentry/instrumentation-http-before-otel', VERSION, {});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
27
|
-
init() {
|
|
28
|
-
return [this._getHttpsInstrumentation(), this._getHttpInstrumentation()];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** Get the instrumentation for the http module. */
|
|
32
|
-
_getHttpInstrumentation() {
|
|
33
|
-
return new InstrumentationNodeModuleDefinition('http', ['*'], (moduleExports) => {
|
|
34
|
-
// Patch incoming requests
|
|
35
|
-
stealthWrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction());
|
|
36
|
-
|
|
37
|
-
return moduleExports;
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** Get the instrumentation for the https module. */
|
|
42
|
-
_getHttpsInstrumentation() {
|
|
43
|
-
return new InstrumentationNodeModuleDefinition('https', ['*'], (moduleExports) => {
|
|
44
|
-
// Patch incoming requests
|
|
45
|
-
stealthWrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction());
|
|
46
|
-
|
|
47
|
-
return moduleExports;
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Patch the incoming request function for request isolation.
|
|
53
|
-
*/
|
|
54
|
-
_getPatchIncomingRequestFunction()
|
|
55
|
-
|
|
56
|
-
{
|
|
57
|
-
return (
|
|
58
|
-
original,
|
|
59
|
-
) => {
|
|
60
|
-
return function incomingRequest( ...args) {
|
|
61
|
-
// Only traces request events
|
|
62
|
-
if (args[0] !== 'request') {
|
|
63
|
-
return original.apply(this, args);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const response = args[2] ;
|
|
67
|
-
patchResponseToFlushOnServerlessPlatforms(response);
|
|
68
|
-
|
|
69
|
-
return original.apply(this, args);
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function patchResponseToFlushOnServerlessPlatforms(res) {
|
|
76
|
-
// Freely extend this function with other platforms if necessary
|
|
77
|
-
if (process.env.VERCEL) {
|
|
78
|
-
DEBUG_BUILD && logger.log('Patching response to flush on Vercel');
|
|
79
|
-
|
|
80
|
-
// In some cases res.end does not seem to be defined leading to errors if passed to Proxy
|
|
81
|
-
// https://github.com/getsentry/sentry-javascript/issues/15759
|
|
82
|
-
if (typeof res.end !== 'function') {
|
|
83
|
-
DEBUG_BUILD && logger.warn('res.end is not a function, skipping patch...');
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
let markOnEndDone = () => undefined;
|
|
88
|
-
const onEndDonePromise = new Promise(res => {
|
|
89
|
-
markOnEndDone = res;
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
res.on('close', () => {
|
|
93
|
-
markOnEndDone();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
logger.log('Patching res.end()');
|
|
97
|
-
|
|
98
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
99
|
-
res.end = new Proxy(res.end, {
|
|
100
|
-
apply(target, thisArg, argArray) {
|
|
101
|
-
vercelWaitUntil(
|
|
102
|
-
new Promise(finishWaitUntil => {
|
|
103
|
-
// Define a timeout that unblocks the lambda just to be safe so we're not indefinitely keeping it alive, exploding server bills
|
|
104
|
-
const timeout = setTimeout(() => {
|
|
105
|
-
finishWaitUntil();
|
|
106
|
-
}, 2000);
|
|
107
|
-
|
|
108
|
-
onEndDonePromise
|
|
109
|
-
.then(() => {
|
|
110
|
-
DEBUG_BUILD && logger.log('Flushing events before Vercel Lambda freeze');
|
|
111
|
-
return flush(2000);
|
|
112
|
-
})
|
|
113
|
-
.then(
|
|
114
|
-
() => {
|
|
115
|
-
clearTimeout(timeout);
|
|
116
|
-
finishWaitUntil();
|
|
117
|
-
},
|
|
118
|
-
e => {
|
|
119
|
-
clearTimeout(timeout);
|
|
120
|
-
DEBUG_BUILD && logger.log('Error while flushing events for Vercel:\n', e);
|
|
121
|
-
finishWaitUntil();
|
|
122
|
-
},
|
|
123
|
-
);
|
|
124
|
-
}),
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
return target.apply(thisArg, argArray);
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export { SentryHttpInstrumentationBeforeOtel };
|
|
134
|
-
//# sourceMappingURL=SentryHttpInstrumentationBeforeOtel.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SentryHttpInstrumentationBeforeOtel.js","sources":["../../../../src/integrations/http/SentryHttpInstrumentationBeforeOtel.ts"],"sourcesContent":["import type * as http from 'node:http';\nimport type * as https from 'node:https';\nimport { VERSION } from '@opentelemetry/core';\nimport { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';\nimport { flush, logger, vercelWaitUntil } from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { stealthWrap } from './utils';\n\ntype Http = typeof http;\ntype Https = typeof https;\n\n// The reason this \"before OTEL\" integration even exists is due to timing reasons. We need to be able to register a\n// `res.on('close')` handler **after** OTEL registers its own handler (which it uses to end spans), so that we can do\n// something (ie. flush) after OTEL has ended a span for a request. If you think about it like an onion:\n//\n// (Sentry after OTEL instrumentation\n// (OTEL instrumentation\n// (Sentry before OTEL instrumentation\n// (orig HTTP request handler))))\n//\n// registering an instrumentation before OTEL allows us to do this for incoming requests.\n\n/**\n * A Sentry specific http instrumentation that is applied before the otel instrumentation.\n */\nexport class SentryHttpInstrumentationBeforeOtel extends InstrumentationBase {\n public constructor() {\n super('@sentry/instrumentation-http-before-otel', VERSION, {});\n }\n\n // eslint-disable-next-line jsdoc/require-jsdoc\n public init(): [InstrumentationNodeModuleDefinition, InstrumentationNodeModuleDefinition] {\n return [this._getHttpsInstrumentation(), this._getHttpInstrumentation()];\n }\n\n /** Get the instrumentation for the http module. */\n private _getHttpInstrumentation(): InstrumentationNodeModuleDefinition {\n return new InstrumentationNodeModuleDefinition('http', ['*'], (moduleExports: Http): Http => {\n // Patch incoming requests\n stealthWrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction());\n\n return moduleExports;\n });\n }\n\n /** Get the instrumentation for the https module. */\n private _getHttpsInstrumentation(): InstrumentationNodeModuleDefinition {\n return new InstrumentationNodeModuleDefinition('https', ['*'], (moduleExports: Https): Https => {\n // Patch incoming requests\n stealthWrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction());\n\n return moduleExports;\n });\n }\n\n /**\n * Patch the incoming request function for request isolation.\n */\n private _getPatchIncomingRequestFunction(): (\n original: (event: string, ...args: unknown[]) => boolean,\n ) => (this: unknown, event: string, ...args: unknown[]) => boolean {\n return (\n original: (event: string, ...args: unknown[]) => boolean,\n ): ((this: unknown, event: string, ...args: unknown[]) => boolean) => {\n return function incomingRequest(this: unknown, ...args: [event: string, ...args: unknown[]]): boolean {\n // Only traces request events\n if (args[0] !== 'request') {\n return original.apply(this, args);\n }\n\n const response = args[2] as http.OutgoingMessage;\n patchResponseToFlushOnServerlessPlatforms(response);\n\n return original.apply(this, args);\n };\n };\n }\n}\n\nfunction patchResponseToFlushOnServerlessPlatforms(res: http.OutgoingMessage): void {\n // Freely extend this function with other platforms if necessary\n if (process.env.VERCEL) {\n DEBUG_BUILD && logger.log('Patching response to flush on Vercel');\n\n // In some cases res.end does not seem to be defined leading to errors if passed to Proxy\n // https://github.com/getsentry/sentry-javascript/issues/15759\n if (typeof res.end !== 'function') {\n DEBUG_BUILD && logger.warn('res.end is not a function, skipping patch...');\n return;\n }\n\n let markOnEndDone = (): void => undefined;\n const onEndDonePromise = new Promise<void>(res => {\n markOnEndDone = res;\n });\n\n res.on('close', () => {\n markOnEndDone();\n });\n\n logger.log('Patching res.end()');\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n res.end = new Proxy(res.end, {\n apply(target, thisArg, argArray) {\n vercelWaitUntil(\n new Promise<void>(finishWaitUntil => {\n // Define a timeout that unblocks the lambda just to be safe so we're not indefinitely keeping it alive, exploding server bills\n const timeout = setTimeout(() => {\n finishWaitUntil();\n }, 2000);\n\n onEndDonePromise\n .then(() => {\n DEBUG_BUILD && logger.log('Flushing events before Vercel Lambda freeze');\n return flush(2000);\n })\n .then(\n () => {\n clearTimeout(timeout);\n finishWaitUntil();\n },\n e => {\n clearTimeout(timeout);\n DEBUG_BUILD && logger.log('Error while flushing events for Vercel:\\n', e);\n finishWaitUntil();\n },\n );\n }),\n );\n\n return target.apply(thisArg, argArray);\n },\n });\n }\n}\n"],"names":[],"mappings":"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"}
|