Skip to content

Commit

Permalink
ref(vercel-edge): Replace WinterCGFetch with `winterCGFetchIntegrat…
Browse files Browse the repository at this point in the history
…ion` (#10436)

This has not been converted yet.
  • Loading branch information
mydea committed Jan 31, 2024
1 parent 5fd5c5d commit 8bcd136
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 108 deletions.
1 change: 1 addition & 0 deletions packages/nextjs/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export declare function init(
// eslint-disable-next-line deprecation/deprecation
export declare const Integrations: typeof clientSdk.Integrations &
typeof serverSdk.Integrations &
// eslint-disable-next-line deprecation/deprecation
typeof edgeSdk.Integrations;

export declare const linkedErrorsIntegration: typeof clientSdk.linkedErrorsIntegration;
Expand Down
6 changes: 3 additions & 3 deletions packages/vercel-edge/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ export {
import { Integrations as CoreIntegrations, RequestData } from '@sentry/core';

import { WinterCGFetch } from './integrations/wintercg-fetch';
export { winterCGFetchIntegration } from './integrations/wintercg-fetch';

const INTEGRATIONS = {
/** @deprecated Import the integration function directly, e.g. `inboundFiltersIntegration()` instead of `new Integrations.InboundFilter(). */
export const Integrations = {
// eslint-disable-next-line deprecation/deprecation
...CoreIntegrations,
WinterCGFetch,
RequestData,
};

export { INTEGRATIONS as Integrations };
154 changes: 91 additions & 63 deletions packages/vercel-edge/src/integrations/wintercg-fetch.ts
Original file line number Diff line number Diff line change
@@ -1,78 +1,52 @@
import { instrumentFetchRequest } from '@sentry-internal/tracing';
import { addBreadcrumb, getClient, isSentryRequestUrl } from '@sentry/core';
import type { FetchBreadcrumbData, FetchBreadcrumbHint, HandlerDataFetch, Integration, Span } from '@sentry/types';
import {
addBreadcrumb,
convertIntegrationFnToClass,
defineIntegration,
getClient,
isSentryRequestUrl,
} from '@sentry/core';
import type {
Client,
FetchBreadcrumbData,
FetchBreadcrumbHint,
HandlerDataFetch,
Integration,
IntegrationClass,
IntegrationFn,
Span,
} from '@sentry/types';
import { LRUMap, addFetchInstrumentationHandler, stringMatchesSomePattern } from '@sentry/utils';

const INTEGRATION_NAME = 'WinterCGFetch';

const HAS_CLIENT_MAP = new WeakMap<Client, boolean>();

export interface Options {
/**
* Whether breadcrumbs should be recorded for requests
* Defaults to true
*/
breadcrumbs: boolean;

/**
* Function determining whether or not to create spans to track outgoing requests to the given URL.
* By default, spans will be created for all outgoing requests.
*/
shouldCreateSpanForRequest?: (url: string) => boolean;
}

/**
* Creates spans and attaches tracing headers to fetch requests on WinterCG runtimes.
*/
export class WinterCGFetch implements Integration {
/**
* @inheritDoc
*/
public static id: string = 'WinterCGFetch';

/**
* @inheritDoc
*/
public name: string = WinterCGFetch.id;

private readonly _options: Options;
const _winterCGFetch = ((options: Partial<Options> = {}) => {
const breadcrumbs = options.breadcrumbs === undefined ? true : options.breadcrumbs;
const shouldCreateSpanForRequest = options.shouldCreateSpanForRequest;

private readonly _createSpanUrlMap: LRUMap<string, boolean> = new LRUMap(100);
private readonly _headersUrlMap: LRUMap<string, boolean> = new LRUMap(100);
const _createSpanUrlMap = new LRUMap<string, boolean>(100);
const _headersUrlMap = new LRUMap<string, boolean>(100);

public constructor(_options: Partial<Options> = {}) {
this._options = {
breadcrumbs: _options.breadcrumbs === undefined ? true : _options.breadcrumbs,
shouldCreateSpanForRequest: _options.shouldCreateSpanForRequest,
};
}

/**
* @inheritDoc
*/
public setupOnce(): void {
const spans: Record<string, Span> = {};

addFetchInstrumentationHandler(handlerData => {
if (!getClient()?.getIntegrationByName?.('WinterCGFetch')) {
return;
}

if (isSentryRequestUrl(handlerData.fetchData.url, getClient())) {
return;
}

instrumentFetchRequest(
handlerData,
this._shouldCreateSpan.bind(this),
this._shouldAttachTraceData.bind(this),
spans,
'auto.http.wintercg_fetch',
);

if (this._options.breadcrumbs) {
createBreadcrumb(handlerData);
}
});
}
const spans: Record<string, Span> = {};

/** Decides whether to attach trace data to the outgoing fetch request */
private _shouldAttachTraceData(url: string): boolean {
function _shouldAttachTraceData(url: string): boolean {
const client = getClient();

if (!client) {
Expand All @@ -85,32 +59,86 @@ export class WinterCGFetch implements Integration {
return true;
}

const cachedDecision = this._headersUrlMap.get(url);
const cachedDecision = _headersUrlMap.get(url);
if (cachedDecision !== undefined) {
return cachedDecision;
}

const decision = stringMatchesSomePattern(url, clientOptions.tracePropagationTargets);
this._headersUrlMap.set(url, decision);
_headersUrlMap.set(url, decision);
return decision;
}

/** Helper that wraps shouldCreateSpanForRequest option */
private _shouldCreateSpan(url: string): boolean {
if (this._options.shouldCreateSpanForRequest === undefined) {
function _shouldCreateSpan(url: string): boolean {
if (shouldCreateSpanForRequest === undefined) {
return true;
}

const cachedDecision = this._createSpanUrlMap.get(url);
const cachedDecision = _createSpanUrlMap.get(url);
if (cachedDecision !== undefined) {
return cachedDecision;
}

const decision = this._options.shouldCreateSpanForRequest(url);
this._createSpanUrlMap.set(url, decision);
const decision = shouldCreateSpanForRequest(url);
_createSpanUrlMap.set(url, decision);
return decision;
}
}

return {
name: INTEGRATION_NAME,
// TODO v8: Remove this again
// eslint-disable-next-line @typescript-eslint/no-empty-function
setupOnce() {
addFetchInstrumentationHandler(handlerData => {
const client = getClient();
if (!client || !HAS_CLIENT_MAP.get(client)) {
return;
}

if (isSentryRequestUrl(handlerData.fetchData.url, client)) {
return;
}

instrumentFetchRequest(
handlerData,
_shouldCreateSpan,
_shouldAttachTraceData,
spans,
'auto.http.wintercg_fetch',
);

if (breadcrumbs) {
createBreadcrumb(handlerData);
}
});
},
setup(client) {
HAS_CLIENT_MAP.set(client, true);
},
};
}) satisfies IntegrationFn;

export const winterCGFetchIntegration = defineIntegration(_winterCGFetch);

/**
* Creates spans and attaches tracing headers to fetch requests on WinterCG runtimes.
*
* @deprecated Use `winterCGFetchIntegration()` instead.
*/
// eslint-disable-next-line deprecation/deprecation
export const WinterCGFetch = convertIntegrationFnToClass(
INTEGRATION_NAME,
winterCGFetchIntegration,
) as IntegrationClass<Integration & { setupOnce: () => void }> & {
new (options?: {
breadcrumbs: boolean;
shouldCreateSpanForRequest?: (url: string) => boolean;
}): Integration;
};

// eslint-disable-next-line deprecation/deprecation
export type WinterCGFetch = typeof WinterCGFetch;

function createBreadcrumb(handlerData: HandlerDataFetch): void {
const { startTimestamp, endTimestamp } = handlerData;
Expand Down
23 changes: 10 additions & 13 deletions packages/vercel-edge/src/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import {
FunctionToString,
InboundFilters,
LinkedErrors,
RequestData,
functionToStringIntegration,
getIntegrationsToSetup,
inboundFiltersIntegration,
initAndBind,
linkedErrorsIntegration,
requestDataIntegration,
} from '@sentry/core';
import type { Integration, Options } from '@sentry/types';
import { GLOBAL_OBJ, createStackParser, nodeStackLineParser, stackParserFromStackParserOptions } from '@sentry/utils';

import { setAsyncLocalStorageAsyncContextStrategy } from './async';
import { VercelEdgeClient } from './client';
import { WinterCGFetch } from './integrations/wintercg-fetch';
import { winterCGFetchIntegration } from './integrations/wintercg-fetch';
import { makeEdgeTransport } from './transports';
import type { VercelEdgeClientOptions, VercelEdgeOptions } from './types';
import { getVercelEnv } from './utils/vercel';
Expand All @@ -24,21 +24,18 @@ const nodeStackParser = createStackParser(nodeStackLineParser());

/** @deprecated Use `getDefaultIntegrations(options)` instead. */
export const defaultIntegrations = [
/* eslint-disable deprecation/deprecation */
new InboundFilters(),
new FunctionToString(),
new LinkedErrors(),
/* eslint-enable deprecation/deprecation */
new WinterCGFetch(),
inboundFiltersIntegration(),
functionToStringIntegration(),
linkedErrorsIntegration(),
winterCGFetchIntegration(),
];

/** Get the default integrations for the browser SDK. */
export function getDefaultIntegrations(options: Options): Integration[] {
return [
// eslint-disable-next-line deprecation/deprecation
...defaultIntegrations,
// eslint-disable-next-line deprecation/deprecation
...(options.sendDefaultPii ? [new RequestData()] : []),
...(options.sendDefaultPii ? [requestDataIntegration()] : []),
];
}

Expand Down
Loading

0 comments on commit 8bcd136

Please sign in to comment.