Skip to content
Merged
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
4 changes: 2 additions & 2 deletions packages/browser-utils/test/browser/metrics/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const originalLocation = WINDOW.location;
const resourceEntryName = 'https://example.com/assets/to/css';

describe('_addMeasureSpans', () => {
const span = new SentrySpan({ op: 'pageload', name: '/' });
const span = new SentrySpan({ op: 'pageload', name: '/', sampled: true });

beforeEach(() => {
getCurrentScope().clear();
Expand Down Expand Up @@ -86,7 +86,7 @@ describe('_addMeasureSpans', () => {
});

describe('_addResourceSpans', () => {
const span = new SentrySpan({ op: 'pageload', name: '/' });
const span = new SentrySpan({ op: 'pageload', name: '/', sampled: true });

beforeAll(() => {
setGlobalLocation(mockWindowLocation);
Expand Down
6 changes: 3 additions & 3 deletions packages/browser-utils/test/browser/metrics/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('startAndEndSpan()', () => {
});

it('creates a span with given properties', () => {
const parentSpan = new SentrySpan({ name: 'test' });
const parentSpan = new SentrySpan({ name: 'test', sampled: true });
const span = startAndEndSpan(parentSpan, 100, 200, {
name: 'evaluation',
op: 'script',
Expand All @@ -40,7 +40,7 @@ describe('startAndEndSpan()', () => {
});

it('adjusts the start timestamp if child span starts before transaction', () => {
const parentSpan = new SentrySpan({ name: 'test', startTimestamp: 123 });
const parentSpan = new SentrySpan({ name: 'test', startTimestamp: 123, sampled: true });
const span = startAndEndSpan(parentSpan, 100, 200, {
name: 'script.js',
op: 'resource',
Expand All @@ -52,7 +52,7 @@ describe('startAndEndSpan()', () => {
});

it('does not adjust start timestamp if child span starts after transaction', () => {
const parentSpan = new SentrySpan({ name: 'test', startTimestamp: 123 });
const parentSpan = new SentrySpan({ name: 'test', startTimestamp: 123, sampled: true });
const span = startAndEndSpan(parentSpan, 150, 200, {
name: 'script.js',
op: 'resource',
Expand Down
1 change: 1 addition & 0 deletions packages/bun/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"dependencies": {
"@sentry/core": "8.0.0-alpha.9",
"@sentry/node": "8.0.0-alpha.9",
"@sentry/opentelemetry": "8.0.0-alpha.9",
"@sentry/types": "8.0.0-alpha.9",
"@sentry/utils": "8.0.0-alpha.9"
},
Expand Down
20 changes: 11 additions & 9 deletions packages/bun/src/transports/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createTransport } from '@sentry/core';
import { createTransport, suppressTracing } from '@sentry/core';
import type { BaseTransportOptions, Transport, TransportMakeRequestResponse, TransportRequest } from '@sentry/types';
import { rejectedSyncPromise } from '@sentry/utils';

Expand All @@ -19,14 +19,16 @@ export function makeFetchTransport(options: BunTransportOptions): Transport {
};

try {
return fetch(options.url, requestOptions).then(response => {
return {
statusCode: response.status,
headers: {
'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),
'retry-after': response.headers.get('Retry-After'),
},
};
return suppressTracing(() => {
return fetch(options.url, requestOptions).then(response => {
return {
statusCode: response.status,
headers: {
'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),
'retry-after': response.headers.get('Retry-After'),
},
};
});
});
} catch (e) {
return rejectedSyncPromise(e);
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/asyncContext.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Hub, Integration } from '@sentry/types';
import type { Scope } from '@sentry/types';
import { GLOBAL_OBJ } from '@sentry/utils';
import type { startInactiveSpan, startSpan, startSpanManual, withActiveSpan } from './tracing/trace';
import type { startInactiveSpan, startSpan, startSpanManual, suppressTracing, withActiveSpan } from './tracing/trace';
import type { getActiveSpan } from './utils/spanUtils';

/**
Expand Down Expand Up @@ -62,6 +62,9 @@ export interface AsyncContextStrategy {

/** Make a span the active span in the context of the callback. */
withActiveSpan?: typeof withActiveSpan;

/** Suppress tracing in the given callback, ensuring no spans are generated inside of it. */
suppressTracing?: typeof suppressTracing;
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/tracing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export {
startSpanManual,
continueTrace,
withActiveSpan,
suppressTracing,
} from './trace';
export { getDynamicSamplingContextFromClient, getDynamicSamplingContextFromSpan } from './dynamicSamplingContext';
export { setMeasurement, timedEventsToMeasurements } from './measurement';
Expand Down
71 changes: 47 additions & 24 deletions packages/core/src/tracing/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ClientOptions, Scope, SentrySpanArguments, Span, SpanTimeInput, St
import { propagationContextFromHeaders } from '@sentry/utils';
import type { AsyncContextStrategy } from '../asyncContext';
import { getMainCarrier } from '../asyncContext';

import { getClient, getCurrentScope, getIsolationScope, withScope } from '../currentScopes';

import { getAsyncContextStrategy } from '../hub';
Expand All @@ -25,6 +26,8 @@ import { SentrySpan } from './sentrySpan';
import { SPAN_STATUS_ERROR } from './spanstatus';
import { setCapturedScopesOnSpan } from './utils';

const SUPPRESS_TRACING_KEY = '__SENTRY_SUPPRESS_TRACING__';

/**
* Wraps a function with a transaction/span and finishes the span after the function is done.
* The created span is the active span and will be used as parent by other spans created inside the function
Expand Down Expand Up @@ -204,6 +207,20 @@ export function withActiveSpan<T>(span: Span | null, callback: (scope: Scope) =>
});
}

/** Suppress tracing in the given callback, ensuring no spans are generated inside of it. */
export function suppressTracing<T>(callback: () => T): T {
const acs = getAcs();

if (acs.suppressTracing) {
return acs.suppressTracing(callback);
}

return withScope(scope => {
scope.setSDKProcessingMetadata({ [SUPPRESS_TRACING_KEY]: true });
return callback();
});
}

function createChildSpanOrTransaction({
parentSpan,
spanContext,
Expand All @@ -223,7 +240,7 @@ function createChildSpanOrTransaction({

let span: Span;
if (parentSpan && !forceTransaction) {
span = _startChildSpan(parentSpan, spanContext);
span = _startChildSpan(parentSpan, scope, spanContext);
addChildSpanToSpan(parentSpan, span);
} else if (parentSpan) {
// If we forced a transaction but have a parent span, make sure to continue from the parent span, not the scope
Expand All @@ -237,6 +254,7 @@ function createChildSpanOrTransaction({
parentSpanId,
...spanContext,
},
scope,
parentSampled,
);

Expand All @@ -258,6 +276,7 @@ function createChildSpanOrTransaction({
parentSpanId,
...spanContext,
},
scope,
parentSampled,
);

Expand Down Expand Up @@ -296,22 +315,24 @@ function getAcs(): AsyncContextStrategy {
return getAsyncContextStrategy(carrier);
}

function _startRootSpan(spanArguments: SentrySpanArguments, parentSampled?: boolean): SentrySpan {
function _startRootSpan(spanArguments: SentrySpanArguments, scope: Scope, parentSampled?: boolean): SentrySpan {
const client = getClient();
const options: Partial<ClientOptions> = (client && client.getOptions()) || {};

const { name = '', attributes } = spanArguments;
const [sampled, sampleRate] = sampleSpan(options, {
name,
parentSampled,
attributes,
transactionContext: {
name,
parentSampled,
},
});

const transaction = new SentrySpan({
const [sampled, sampleRate] = scope.getScopeData().sdkProcessingMetadata[SUPPRESS_TRACING_KEY]
? [false]
: sampleSpan(options, {
name,
parentSampled,
attributes,
transactionContext: {
name,
parentSampled,
},
});

const rootSpan = new SentrySpan({
...spanArguments,
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'custom',
Expand All @@ -320,30 +341,32 @@ function _startRootSpan(spanArguments: SentrySpanArguments, parentSampled?: bool
sampled,
});
if (sampleRate !== undefined) {
transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, sampleRate);
rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, sampleRate);
}

if (client) {
client.emit('spanStart', transaction);
client.emit('spanStart', rootSpan);
}

return transaction;
return rootSpan;
}

/**
* Creates a new `Span` while setting the current `Span.id` as `parentSpanId`.
* This inherits the sampling decision from the parent span.
*/
function _startChildSpan(parentSpan: Span, spanArguments: SentrySpanArguments): SentrySpan {
function _startChildSpan(parentSpan: Span, scope: Scope, spanArguments: SentrySpanArguments): Span {
const { spanId, traceId } = parentSpan.spanContext();
const sampled = spanIsSampled(parentSpan);
const sampled = scope.getScopeData().sdkProcessingMetadata[SUPPRESS_TRACING_KEY] ? false : spanIsSampled(parentSpan);

const childSpan = new SentrySpan({
...spanArguments,
parentSpanId: spanId,
traceId,
sampled,
});
const childSpan = sampled
? new SentrySpan({
...spanArguments,
parentSpanId: spanId,
traceId,
sampled,
})
: new SentryNonRecordingSpan();

addChildSpanToSpan(parentSpan, childSpan);

Expand Down
Loading