Skip to content

Commit

Permalink
feat(nextjs): Instrument outgoing http requests
Browse files Browse the repository at this point in the history
  • Loading branch information
mydea committed Apr 18, 2024
1 parent c90048f commit f4f9ec1
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
},
"dependencies": {
"@opentelemetry/api": "1.7.0",
"@opentelemetry/instrumentation-http": "0.48.0",
"@rollup/plugin-commonjs": "24.0.0",
"@sentry/core": "8.0.0-beta.2",
"@sentry/node": "8.0.0-beta.2",
Expand Down
48 changes: 48 additions & 0 deletions packages/nextjs/src/server/httpIntegration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
import { httpIntegration as originalHttpIntegration } from '@sentry/node';
import type { IntegrationFn } from '@sentry/types';

/**
* Next.js handles incoming requests itself,
* but it does not handle outgoing requests.
* Today, it is not possible to use the HttpInstrumentation for only outgoing requests -
* until https://github.com/open-telemetry/opentelemetry-js/pull/4643 is merged & released.
* So in the meanwhile, we extend the base HttpInstrumentation to not wrap incoming requests.
*/
class CustomNextjsHttpIntegration extends HttpInstrumentation {
// Instead of the default behavior, we just don't do any wrapping for incoming requests
protected _getPatchIncomingRequestFunction(_component: 'http' | 'https') {
return (
original: (event: string, ...args: unknown[]) => boolean,
): ((this: unknown, event: string, ...args: unknown[]) => boolean) => {
return function incomingRequest(this: unknown, event: string, ...args: unknown[]): boolean {
return original.apply(this, [event, ...args]);
};
};
}
}

interface HttpOptions {
/**
* Whether breadcrumbs should be recorded for requests.
* Defaults to true
*/
breadcrumbs?: boolean;

/**
* Do not capture spans or breadcrumbs for outgoing HTTP requests to URLs where the given callback returns `true`.
* This controls both span & breadcrumb creation - spans will be non recording if tracing is disabled.
*/
ignoreOutgoingRequests?: (url: string) => boolean;
}

/**
* The http integration instruments Node's internal http and https modules.
* It creates breadcrumbs and spans for outgoing HTTP requests which will be attached to the currently active span.
*/
export const httpIntegration = ((options: HttpOptions = {}) => {
return originalHttpIntegration({
...options,
_instrumentation: CustomNextjsHttpIntegration,
});
}) satisfies IntegrationFn;
6 changes: 5 additions & 1 deletion packages/node/src/integrations/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,22 @@ interface HttpOptions {
* This controls both span & breadcrumb creation - spans will be non recording if tracing is disabled.
*/
ignoreIncomingRequests?: (url: string) => boolean;

/** Allows to pass a custom version of HttpInstrumentation. We use this for Next.js. */
_instrumentation?: typeof HttpInstrumentation;
}

const _httpIntegration = ((options: HttpOptions = {}) => {
const _breadcrumbs = typeof options.breadcrumbs === 'undefined' ? true : options.breadcrumbs;
const _ignoreOutgoingRequests = options.ignoreOutgoingRequests;
const _ignoreIncomingRequests = options.ignoreIncomingRequests;
const _InstrumentationClass = options._instrumentation || HttpInstrumentation;

return {
name: 'Http',
setupOnce() {
addOpenTelemetryInstrumentation(
new HttpInstrumentation({
new _InstrumentationClass({
ignoreOutgoingRequestHook: request => {
const url = getRequestUrl(request);

Expand Down

0 comments on commit f4f9ec1

Please sign in to comment.