Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/node-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ export {
type SentryHttpInstrumentationOptions,
} from './integrations/http/SentryHttpInstrumentation';
export { nativeNodeFetchIntegration } from './integrations/node-fetch';
export type { NodeFetchOptions } from './integrations/node-fetch/types';
export { instrumentUndici } from './integrations/node-fetch/undici-instrumentation';
export {
// oxlint-disable-next-line typescript/no-deprecated
SentryNodeFetchInstrumentation,
type SentryNodeFetchInstrumentationOptions,
} from './integrations/node-fetch/SentryNodeFetchInstrumentation';
export { addFetchRequestBreadcrumb, addTracePropagationHeadersToFetchRequest } from './utils/outgoingFetchRequest';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed public fetch helper exports

Medium Severity

This change drops addFetchRequestBreadcrumb and addTracePropagationHeadersToFetchRequest from the @sentry/node-core package entry without a deprecation period, which is a breaking public API removal for anyone importing those helpers from the main export.

Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit d4e9512. Configure here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was just added in the base-stack PR so should be fine


export { SentryContextManager } from './otel/contextManager';
export { setupOpenTelemetryLogger } from './otel/logger';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ interface ListenerRecord {
*
* This is heavily inspired & adapted from:
* https://github.com/open-telemetry/opentelemetry-js-contrib/blob/28e209a9da36bc4e1f8c2b0db7360170ed46cb80/plugins/node/instrumentation-undici/src/undici.ts
*
* @deprecated This class is no longer used internally and will be removed in a future major version. Use `nativeNodeFetchIntegration` instead.
*/
export class SentryNodeFetchInstrumentation extends InstrumentationBase<SentryNodeFetchInstrumentationOptions> {
// Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug and for
Expand Down
41 changes: 7 additions & 34 deletions packages/node-core/src/integrations/node-fetch/index.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,19 @@
import type { IntegrationFn } from '@sentry/core';
import { defineIntegration } from '@sentry/core';
import { generateInstrumentOnce } from '../../otel/instrument';
import { SentryNodeFetchInstrumentation } from './SentryNodeFetchInstrumentation';

const INTEGRATION_NAME = 'NodeFetch';

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

/**
* Whether to inject trace propagation headers (sentry-trace, baggage, traceparent) into outgoing fetch requests.
*
* @default `true`
*/
tracePropagation?: boolean;

/**
* Do not capture spans or breadcrumbs for outgoing fetch 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;
}

const instrumentSentryNodeFetch = generateInstrumentOnce(
`${INTEGRATION_NAME}.sentry`,
SentryNodeFetchInstrumentation,
(options: NodeFetchOptions) => {
return options;
},
);
import type { NodeFetchOptions } from './types';
import { instrumentUndici } from './undici-instrumentation';

const _nativeNodeFetchIntegration = ((options: NodeFetchOptions = {}) => {
return {
name: 'NodeFetch' as const,
setupOnce() {
instrumentSentryNodeFetch(options);
instrumentUndici(options);
Comment thread
cursor[bot] marked this conversation as resolved.
},
};
}) satisfies IntegrationFn;

/**
* Instrument outgoing fetch requests made through the native node `fetch` API.
* This emits (depending on the integration options) spans and breadcrumbs, as well as injecting trace propagation headers into the request.
*/
export const nativeNodeFetchIntegration = defineIntegration(_nativeNodeFetchIntegration);
106 changes: 89 additions & 17 deletions packages/node-core/src/integrations/node-fetch/types.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* NOTICE from the Sentry authors:
* - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/ed97091c9890dd18e52759f2ea98e9d7593b3ae4/packages/instrumentation-undici
* - Upstream version: @opentelemetry/instrumentation-undici@0.24.0
* - Tracking issue: https://github.com/getsentry/sentry-javascript/issues/20165
* - Dropped the `@opentelemetry/instrumentation` `InstrumentationConfig` base (its only field used
* here, `enabled`, is unused by the Sentry integration)
*/

/**
* Aligned with upstream Undici request shape; see `packages/node/.../node-fetch/vendored/types.ts`
* (vendored from `@opentelemetry/instrumentation-undici`).
*/
import type { Span } from '@sentry/core';

export interface UndiciRequest {
origin: string;
method: string;
path: string;
/**
* Serialized string of headers in the form `name: value\r\n` for v5
* Array of strings `[key1, value1, ...]` for v6 (values may be `string | string[]`)
* Array of strings `[key1, value1, key2, value2]`, where values are
* `string | string[]` for v6
*/
headers: string | (string | string[])[];
/**
Expand All @@ -38,11 +32,89 @@ export interface UndiciRequest {
idempotent: boolean;
contentLength: number | null;
contentType: string | null;
body: unknown;
// oxlint-disable-next-line typescript/no-explicit-any
body: any;
}

export interface UndiciResponse {
headers: Buffer[];
statusCode: number;
statusText: string;
}

export interface RequestHookFunction<T = UndiciRequest> {
(span: Span, request: T): void;
}

export interface ResponseHookFunction<RequestType = UndiciRequest, ResponseType = UndiciResponse> {
(span: Span, info: { request: RequestType; response: ResponseType }): void;
}

export interface RequestMessage {
request: UndiciRequest;
}

export interface RequestHeadersMessage {
request: UndiciRequest;
// oxlint-disable-next-line typescript/no-explicit-any
socket: any;
}

export interface ResponseHeadersMessage {
request: UndiciRequest;
response: UndiciResponse;
}

export interface RequestTrailersMessage {
request: UndiciRequest;
response: UndiciResponse;
}

export interface RequestErrorMessage {
request: UndiciRequest;
error: Error;
}

// This package will instrument HTTP requests made through `undici` or `fetch` global API
// so it seems logical to have similar options than the HTTP instrumentation
export interface UndiciInstrumentationConfig<RequestType = UndiciRequest, ResponseType = UndiciResponse> {
/**
* Do not capture spans or breadcrumbs for outgoing fetch 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;
/** Function for adding custom attributes before request is handled */
requestHook?: RequestHookFunction<RequestType>;
/** Function called once response headers have been received */
responseHook?: ResponseHookFunction<RequestType, ResponseType>;
/** Map the following HTTP headers to span attributes. */
headersToSpanAttributes?: {
requestHeaders?: string[];
responseHeaders?: string[];
};
}

export interface NodeFetchOptions extends UndiciInstrumentationConfig {
/**
* Whether breadcrumbs should be recorded for requests.
*
* @default `true`
*/
breadcrumbs?: boolean;

/**
* If set to false, do not emit any spans.
* Breadcrumbs and trace propagation for outgoing fetch requests are still applied.
*
* If `skipOpenTelemetrySetup: true` is configured, this defaults to `false`, otherwise it defaults to `true`.
*/
spans?: boolean;

/**
* This option only has an effect when `spans` is set to false. When spans are enabled, you cannot disable trace propagation here.
* Instead, configure `tracePropagationTargets` in the client options.
*
* @default `true`
*/
tracePropagation?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
startInactiveSpan,
stripDataUrlContent,
} from '@sentry/core';
import { addFetchRequestBreadcrumb, addTracePropagationHeadersToFetchRequest } from '@sentry/node-core';
import { addFetchRequestBreadcrumb, addTracePropagationHeadersToFetchRequest } from '../../utils/outgoingFetchRequest';
import {
HTTP_REQUEST_METHOD,
HTTP_RESPONSE_STATUS_CODE,
Expand Down Expand Up @@ -190,7 +190,7 @@ function onRequestCreated(config: NodeFetchOptions, { request }: RequestMessage)

// When spans are disabled we do not create a span, but we still inject trace propagation headers
// directly (unless disabled via `tracePropagation`).
if (config.spans === false) {
if (config.spans) {
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
if (config.tracePropagation !== false && !ignoreForBreadcrumbs) {
addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap);
}
Expand Down
33 changes: 33 additions & 0 deletions packages/node/src/integrations/node-fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { instrumentUndici, type NodeFetchOptions } from '@sentry/node-core';
import type { NodeClientOptions } from '../types';
import type { IntegrationFn } from '@sentry/core';
import { defineIntegration, getClient, hasSpansEnabled } from '@sentry/core';

/**
* This is a variant of the node-core integration where the default for spans is different.
* In v11, this will be the only implementation.
*/
const _nativeNodeFetchIntegration = ((options: NodeFetchOptions = {}) => {
return {
name: 'NodeFetch' as const,
setupOnce() {
const clientOptions = getClient()?.getOptions();
instrumentUndici({
...options,
spans: _shouldInstrumentSpans(options, clientOptions),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, in normal node setup we want to generally enable this, while in node-core it should always be opt-in to maintain the current behavior (where spans are never emitted)

});
},
};
}) satisfies IntegrationFn;

/**
* Instrument outgoing fetch requests made through the native node `fetch` API.
* This emits (depending on the integration options) spans and breadcrumbs, as well as injecting trace propagation headers into the request.
*/
export const nativeNodeFetchIntegration = defineIntegration(_nativeNodeFetchIntegration);

function _shouldInstrumentSpans(options: NodeFetchOptions, clientOptions: Partial<NodeClientOptions> = {}): boolean {
// If `spans` is passed in, it takes precedence
// Else, we by default emit spans, unless `skipOpenTelemetrySetup` is set to `true` or spans are not enabled
return options.spans ?? (!clientOptions.skipOpenTelemetrySetup && hasSpansEnabled(clientOptions));
}
29 changes: 0 additions & 29 deletions packages/node/src/integrations/node-fetch/index.ts

This file was deleted.

Loading
Loading