Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
10 changes: 8 additions & 2 deletions packages/angular/src/tracing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ import {
import { CODE_FUNCTION_NAME, SENTRY_OP, URL_FULL, URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';
import { GENERAL_FUNCTION_SPAN_OP } from '@sentry/conventions/op';
import type { Integration, Span } from '@sentry/core';
import { debug, parseStringToURLObject, stripUrlQueryAndFragment, timestampInSeconds } from '@sentry/core';
import {
debug,
parseStringToURLObject,
stripUrlQueryAndFragment,
timestampInSeconds,
filterCollectedUrl,
} from '@sentry/core';
import type { Observable } from 'rxjs';
import { Subscription } from 'rxjs';
import { filter, tap } from 'rxjs/operators';
Expand Down Expand Up @@ -72,7 +78,7 @@ export function _updateSpanAttributesForParametrizedUrl(route: string, url: stri
span.setAttributes({
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.${op}.angular`,
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
[URL_FULL]: absoluteUrl,
[URL_FULL]: filterCollectedUrl(absoluteUrl),
[URL_PATH]: parseStringToURLObject(absoluteUrl)?.pathname,
[URL_TEMPLATE]: route,
});
Expand Down
6 changes: 4 additions & 2 deletions packages/astro/src/server/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,
spanToJSON,
winterCGRequestToRequestData,
filterCollectedUrl,
filterCollectedUrlQuery,
} from '@sentry/core';
import {
captureException,
Expand Down Expand Up @@ -214,7 +216,7 @@ async function instrumentRequestStartHttpServerSpan(
[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: method,
// This is here for backwards compatibility, we used to set this here before
method,
[URL_FULL]: ctx.url.href,
[URL_FULL]: filterCollectedUrl(ctx.url.href),
[URL_PATH]: ctx.url.pathname,
...httpHeadersToSpanAttributes(winterCGHeadersToDict(request.headers), client.getDataCollectionOptions()),
};
Expand All @@ -223,7 +225,7 @@ async function instrumentRequestStartHttpServerSpan(
attributes[HTTP_ROUTE] = parametrizedRoute;
}

attributes[URL_QUERY] = getUrlQuery(ctx.url.search);
attributes[URL_QUERY] = filterCollectedUrlQuery(getUrlQuery(ctx.url.search));
attributes[URL_FRAGMENT] = getUrlFragment(ctx.url.hash);

const name = `${method} ${parametrizedRoute || ctx.url.pathname}`;
Expand Down
4 changes: 2 additions & 2 deletions packages/aws-serverless/src/requestSpanOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
} from '@sentry/conventions/attributes';
import { FAAS_FUNCTION_AWS_SPAN_OP } from '@sentry/conventions/op';
import type { SpanAttributes, StartSpanOptions } from '@sentry/core';
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, filterCollectedUrl } from '@sentry/core';
import type { Context } from 'aws-lambda';
import { ATTR_FAAS_EXECUTION, ATTR_FAAS_ID } from './semconv';

Expand Down Expand Up @@ -75,7 +75,7 @@ function extractOtherEventFields(event: unknown): SpanAttributes {
const answer: SpanAttributes = {};
const fullUrl = extractFullUrl(event as ApiGatewayLikeEvent);
if (fullUrl) {
answer[URL_FULL] = fullUrl;
answer[URL_FULL] = filterCollectedUrl(fullUrl);
}
return answer;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/browser-utils/src/metrics/browserMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
setMeasurement,
spanToJSON,
filterCollectedUrl,
} from '@sentry/core';
import { htmlTreeAsString } from '../htmlTreeAsString';
import { WINDOW } from '../types';
Expand Down Expand Up @@ -627,7 +628,7 @@ export function _addResourceSpans(

attributes['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin);

attributes[URL_FULL] = resourceUrl;
attributes[URL_FULL] = filterCollectedUrl(resourceUrl);

_setResourceRequestAttributes(entry, attributes, [
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
startInactiveSpan,
stripDataUrlContent,
filterCollectedUrl,
} from '@sentry/core';

const responseToStreamSpan = new WeakMap<object, Span>();
Expand Down Expand Up @@ -81,7 +82,7 @@ export const fetchStreamPerformanceIntegration = defineIntegration(() => {
name: `${method} ${sanitizedUrl}`,
startTime: handlerData.endTimestamp,
attributes: {
[URL_FULL]: stripDataUrlContent(url),
[URL_FULL]: filterCollectedUrl(stripDataUrlContent(url)),
'http.method': method,
type: 'fetch',
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client.stream',
Expand Down
3 changes: 2 additions & 1 deletion packages/browser/src/integrations/httpcontext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
SEMANTIC_ATTRIBUTE_SENTRY_OP,
} from '@sentry/core/browser';
import { getHttpRequestData, WINDOW } from '../helpers';
import { filterCollectedUrl } from '@sentry/core';
import { URL_FULL } from '@sentry/conventions/attributes';

/**
Expand Down Expand Up @@ -59,7 +60,7 @@ export const httpContextIntegration = defineIntegration(() => {
safeSetSpanJSONAttributes(span, {
// Coerce empty string to undefined so the helper's nullish check drops it,
// rather than writing an empty `url.full` attribute onto the span.
[URL_FULL]: spanOp !== 'http.client' ? reqData.url : undefined,
[URL_FULL]: spanOp !== 'http.client' ? filterCollectedUrl(reqData.url) : undefined,
'http.request.header.user_agent': headers['User-Agent'],
'http.request.header.referer': headers['Referer'],
});
Expand Down
3 changes: 2 additions & 1 deletion packages/browser/src/tracing/browserTracingIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
startTrackingLongTasks,
} from '@sentry/browser-utils';
import { DEBUG_BUILD } from '../debug-build';
import { filterCollectedUrl } from '@sentry/core';
import { getHttpRequestData, WINDOW } from '../helpers';
import { fetchStreamPerformanceIntegration } from '../integrations/fetchStreamPerformance';
import { WEB_VITALS_INTEGRATION_NAME, webVitalsIntegration } from '../integrations/webVitals';
Expand Down Expand Up @@ -392,7 +393,7 @@ export const browserTracingIntegration = ((options: Partial<BrowserTracingOption

const attributes = {
...(urlObject?.pathname && { [URL_PATH]: urlObject.pathname }),
...(urlObject && !isURLObjectRelative(urlObject) && { [URL_FULL]: urlObject.href }),
...(urlObject && !isURLObjectRelative(urlObject) && { [URL_FULL]: filterCollectedUrl(urlObject.href) }),
...finalStartSpanOptions.attributes,
};

Expand Down
7 changes: 4 additions & 3 deletions packages/browser/src/tracing/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
timestampInSeconds,
} from '@sentry/core/browser';
import type { XhrHint } from '@sentry/browser-utils';
import { filterCollectedUrl, filterCollectedUrlQuery } from '@sentry/core';
import {
addPerformanceInstrumentationHandler,
addXhrInstrumentationHandler,
Expand Down Expand Up @@ -176,7 +177,7 @@ export function instrumentOutgoingRequests(client: Client, _options?: Partial<Re
const host = fullUrl ? parseUrl(fullUrl).host : undefined;
const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;
createdSpan.setAttributes({
[URL_FULL]: sanitizedFullUrl,
[URL_FULL]: filterCollectedUrl(sanitizedFullUrl),
'server.address': host,
});

Expand Down Expand Up @@ -391,11 +392,11 @@ function xhrCallback(
type: 'xhr',
// eslint-disable-next-line typescript/no-deprecated
[HTTP_METHOD]: method,
[URL_FULL]: sanitizedFullUrl,
[URL_FULL]: filterCollectedUrl(sanitizedFullUrl),
[SERVER_ADDRESS]: parsedUrl?.host,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser',
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',
[URL_QUERY]: getUrlQuery(parsedUrl?.search),
[URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(parsedUrl?.search)),
[URL_FRAGMENT]: getUrlFragment(parsedUrl?.hash),
},
})
Expand Down
6 changes: 4 additions & 2 deletions packages/bun/src/integrations/bunserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
setHttpStatus,
startSpan,
withIsolationScope,
filterCollectedUrl,
filterCollectedUrlQuery,
} from '@sentry/core';
import type { ServeOptions } from 'bun';
import {
Expand Down Expand Up @@ -289,13 +291,13 @@ function getSpanAttributesFromParsedUrl(
};

if (parsedUrl) {
attributes[URL_QUERY] = getUrlQuery(parsedUrl.search);
attributes[URL_QUERY] = filterCollectedUrlQuery(getUrlQuery(parsedUrl.search));
attributes[URL_FRAGMENT] = getUrlFragment(parsedUrl.hash);
if (parsedUrl.pathname) {
attributes[URL_PATH] = parsedUrl.pathname;
}
if (!isURLObjectRelative(parsedUrl)) {
attributes[URL_FULL] = parsedUrl.href;
attributes[URL_FULL] = filterCollectedUrl(parsedUrl.href);
if (parsedUrl.port) {
attributes[URL_PORT] = parsedUrl.port;
}
Expand Down
7 changes: 4 additions & 3 deletions packages/core/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { HandlerDataFetch } from './types/instrument';
import type { ResponseHookInfo } from './types/request';
import type { Span, SpanAttributes, SpanOrigin } from './types/span';
import { SENTRY_BAGGAGE_KEY_PREFIX } from './utils/baggage';
import { filterCollectedUrl, filterCollectedUrlQuery } from './utils/data-collection/filterCollectedUrl';
import { hasSpansEnabled } from './utils/hasSpansEnabled';
import { isInstanceOf, isRequest } from './utils/is';
import { getActiveSpan } from './utils/spanUtils';
Expand Down Expand Up @@ -388,7 +389,7 @@ function getFetchSpanAttributes(
spanOrigin: SpanOrigin,
): SpanAttributes {
const attributes: SpanAttributes = {
[URL_FULL]: stripDataUrlContent(url),
[URL_FULL]: filterCollectedUrl(stripDataUrlContent(url)),
type: 'fetch',
// oxlint-disable-next-line typescript/no-deprecated
[HTTP_METHOD]: method,
Expand All @@ -397,10 +398,10 @@ function getFetchSpanAttributes(
};
if (parsedUrl) {
if (!isURLObjectRelative(parsedUrl)) {
attributes[URL_FULL] = stripDataUrlContent(parsedUrl.href);
attributes[URL_FULL] = filterCollectedUrl(stripDataUrlContent(parsedUrl.href));
attributes[SERVER_ADDRESS] = parsedUrl.host;
}
attributes[URL_QUERY] = getUrlQuery(parsedUrl.search);
attributes[URL_QUERY] = filterCollectedUrlQuery(getUrlQuery(parsedUrl.search));
attributes[URL_FRAGMENT] = getUrlFragment(parsedUrl.hash);
}
return attributes;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HTTP_METHOD, URL_FRAGMENT, URL_QUERY } from '@sentry/conventions/attributes';
import { addBreadcrumb } from '../../breadcrumbs';
import { getBreadcrumbLogLevelFromHttpStatusCode } from '../../utils/breadcrumb-log-level';
import { filterCollectedUrlQuery } from '../../utils/data-collection/filterCollectedUrl';
import { getSanitizedUrlString, getUrlFragment, getUrlQuery, parseUrl } from '../../utils/url';
import { getRequestUrlFromClientRequest } from './get-request-url';
import type { HttpClientRequest, HttpIncomingMessage } from './types';
Expand All @@ -26,7 +27,7 @@ export function addOutgoingRequestBreadcrumb(
url: getSanitizedUrlString(parsedUrl),
// eslint-disable-next-line typescript/no-deprecated
[HTTP_METHOD]: request.method || 'GET',
[URL_QUERY]: getUrlQuery(parsedUrl.search),
[URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(parsedUrl.search)),
[URL_FRAGMENT]: getUrlFragment(parsedUrl.hash),
},
type: 'http',
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/integrations/http/get-outgoing-span-data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Span, SpanAttributes } from '../../types/span';
import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '../../semanticAttributes';
import { filterCollectedUrl } from '../../utils/data-collection/filterCollectedUrl';
import { getHttpSpanDetailsFromUrlObject, parseStringToURLObject } from '../../utils/url';
import type { HttpClientRequest, HttpIncomingMessage } from './types';
import { getRequestUrlFromClientRequest } from './get-request-url';
Expand Down Expand Up @@ -36,10 +37,10 @@ export function getOutgoingRequestSpanData(request: HttpClientRequest): StartSpa
// https://getsentry.github.io/sentry-conventions/attributes/
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',
[SENTRY_KIND]: 'client',
[URL_FULL]: url,
[URL_FULL]: filterCollectedUrl(url),
/* eslint-disable typescript/no-deprecated */
[HTTP_METHOD]: request.method,
[HTTP_TARGET]: request.path || '/',
[HTTP_TARGET]: filterCollectedUrl(request.path || '/'),
[NET_PEER_NAME]: request.host,
[HTTP_HOST]: request.getHeader('host') as string | undefined,
/* eslint-enable typescript/no-deprecated */
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/integrations/http/server-subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { safeMathRandom } from '../../utils/randomSafeContext';
import type { SpanAttributes } from '../../types/span';
import type { SpanStatus } from '../../types/spanStatus';
import { URL_FULL, URL_PATH, SENTRY_KIND } from '@sentry/conventions/attributes';
import { filterCollectedUrl } from '../../utils/data-collection/filterCollectedUrl';

// Tree-shakable guard to remove all code related to tracing
declare const __SENTRY_TRACING__: boolean;
Expand Down Expand Up @@ -298,10 +299,12 @@ function buildServerSpanWrap(
'net.peer.port': remotePort,
'sentry.http.prefetch': isKnownPrefetchRequest(request) || undefined,
// Old Semantic Conventions attributes for compatibility
[URL_FULL]: fullUrl,
[URL_FULL]: filterCollectedUrl(fullUrl),
[URL_PATH]: urlObj?.pathname ?? httpTargetWithoutQueryFragment,
'http.method': method,
Comment thread
chargome marked this conversation as resolved.
'http.target': urlObj ? `${urlObj.pathname}${urlObj.search}` : httpTargetWithoutQueryFragment,
'http.target': filterCollectedUrl(
urlObj ? `${urlObj.pathname}${urlObj.search}` : httpTargetWithoutQueryFragment,
),
'http.host': host,
'net.host.name': hostname,
'http.client_ip': typeof ips === 'string' ? ips.split(',')[0] : undefined,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/shared-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export {
export { filterKeyValueData as _INTERNAL_filterKeyValueData } from './utils/data-collection/filterKeyValueData';
export { filterCookies as _INTERNAL_filterCookies } from './utils/data-collection/filterCookies';
export { filterQueryParams as _INTERNAL_filterQueryParams } from './utils/data-collection/filterQueryParams';
export { filterCollectedUrl, filterCollectedUrlQuery } from './utils/data-collection/filterCollectedUrl';
export { envToBool } from './utils/envToBool';
export { applyScopeDataToEvent, mergeScopeData, getCombinedScopeData } from './utils/scopeData';
export { prepareEvent } from './utils/prepareEvent';
Expand Down
32 changes: 32 additions & 0 deletions packages/core/src/utils/data-collection/filterCollectedUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { getClient } from '../../currentScopes';
import type { CollectBehavior } from '../../types/datacollection';
import { filterQueryParams } from './filterQueryParams';
import { filterUrlQuery } from './filterUrlQuery';

function urlQueryParamsBehavior(): CollectBehavior {
// Instrumentation can run before a client exists; the denylist default is the safe fallback.
return getClient()?.getDataCollectionOptions().urlQueryParams ?? true;
}

/**
* Applies `dataCollection.urlQueryParams` to a URL the SDK collected itself, for use as `url.full`.
*
* Call this at every site where instrumentation records a URL. Routing the SDK's own URLs through a
* helper is what makes the filtering provenance-correct: a URL a user attaches themselves never passes
* through here, and `dataCollection` is only meant to gate automatically collected data.
*/
export function filterCollectedUrl(url: string): string;
export function filterCollectedUrl(url: string | undefined): string | undefined;
export function filterCollectedUrl(url: string | undefined): string | undefined {
return url === undefined ? undefined : filterUrlQuery(url, urlQueryParamsBehavior());
}

/**
* Applies `dataCollection.urlQueryParams` to a query string the SDK collected itself, for use as
* `url.query`. Returns `undefined` when the query must not be collected at all.
*
* See {@link filterCollectedUrl} for why this is a helper rather than a central pass.
*/
export function filterCollectedUrlQuery(query: string | undefined): string | undefined {
return query ? filterQueryParams(query, urlQueryParamsBehavior()) : undefined;
}
9 changes: 5 additions & 4 deletions packages/core/src/utils/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
} from '../semanticAttributes';
import type { SpanAttributes } from '../types/span';
import { filterCollectedUrl, filterCollectedUrlQuery } from './data-collection/filterCollectedUrl';

type PartialURL = {
host?: string;
Expand Down Expand Up @@ -208,11 +209,11 @@ export function getHttpSpanDetailsFromUrlObject(

if (urlObject) {
// Relative URLs have no meaningful `href`, so fall back to the sanitized path.
attributes[URL_FULL] = isURLObjectRelative(urlObject)
? getSanitizedUrlStringFromUrlObject(urlObject)
: urlObject.href;
attributes[URL_FULL] = filterCollectedUrl(
isURLObjectRelative(urlObject) ? getSanitizedUrlStringFromUrlObject(urlObject) : urlObject.href,
);

attributes[URL_QUERY] = getUrlQuery(urlObject.search);
attributes[URL_QUERY] = filterCollectedUrlQuery(getUrlQuery(urlObject.search));
attributes[URL_FRAGMENT] = getUrlFragment(urlObject.hash);
if (urlObject.pathname) {
attributes[URL_PATH] = urlObject.pathname;
Expand Down
Loading
Loading