Skip to content

Commit be92638

Browse files
committed
ref: Avoid sampling work for non-root spans
1 parent 05391d0 commit be92638

File tree

1 file changed

+59
-60
lines changed

1 file changed

+59
-60
lines changed

packages/opentelemetry/src/sampler.ts

+59-60
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,19 @@ export class SentrySampler implements Sampler {
6767
}
6868

6969
const parentSampled = parentSpan ? getParentSampled(parentSpan, traceId, spanName) : undefined;
70+
const isRootSpan = !parentSpan || parentContext?.isRemote;
71+
72+
// We only sample based on parameters (like tracesSampleRate or tracesSampler) for root spans (which is done in sampleSpan).
73+
// Non-root-spans simply inherit the sampling decision from their parent.
74+
if (!isRootSpan) {
75+
return {
76+
...wrapSamplingDecision({
77+
decision: parentSampled ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,
78+
context,
79+
spanAttributes,
80+
}),
81+
};
82+
}
7083

7184
// We want to pass the inferred name & attributes to the sampler method
7285
const {
@@ -99,76 +112,62 @@ export class SentrySampler implements Sampler {
99112
return wrapSamplingDecision({ decision: undefined, context, spanAttributes });
100113
}
101114

102-
const isRootSpan = !parentSpan || parentContext?.isRemote;
115+
const { isolationScope } = getScopesFromContext(context) ?? {};
103116

104-
// We only sample based on parameters (like tracesSampleRate or tracesSampler) for root spans (which is done in sampleSpan).
105-
// Non-root-spans simply inherit the sampling decision from their parent.
106-
if (isRootSpan) {
107-
const { isolationScope } = getScopesFromContext(context) ?? {};
108-
109-
const dscString = parentContext?.traceState ? parentContext.traceState.get(SENTRY_TRACE_STATE_DSC) : undefined;
110-
const dsc = dscString ? baggageHeaderToDynamicSamplingContext(dscString) : undefined;
111-
112-
const sampleRand = parseSampleRate(dsc?.sample_rand) ?? Math.random();
113-
114-
const [sampled, sampleRate, localSampleRateWasApplied] = sampleSpan(
115-
options,
116-
{
117-
name: inferredSpanName,
118-
attributes: mergedAttributes,
119-
normalizedRequest: isolationScope?.getScopeData().sdkProcessingMetadata.normalizedRequest,
120-
parentSampled,
121-
parentSampleRate: parseSampleRate(dsc?.sample_rate),
122-
},
123-
sampleRand,
124-
);
125-
126-
const method = `${maybeSpanHttpMethod}`.toUpperCase();
127-
if (method === 'OPTIONS' || method === 'HEAD') {
128-
DEBUG_BUILD && logger.log(`[Tracing] Not sampling span because HTTP method is '${method}' for ${spanName}`);
129-
130-
return {
131-
...wrapSamplingDecision({
132-
decision: SamplingDecision.NOT_RECORD,
133-
context,
134-
spanAttributes,
135-
sampleRand,
136-
downstreamTraceSampleRate: 0, // we don't want to sample anything in the downstream trace either
137-
}),
138-
};
139-
}
140-
141-
if (
142-
!sampled &&
143-
// We check for `parentSampled === undefined` because we only want to record client reports for spans that are trace roots (ie. when there was incoming trace)
144-
parentSampled === undefined
145-
) {
146-
DEBUG_BUILD && logger.log('[Tracing] Discarding root span because its trace was not chosen to be sampled.');
147-
this._client.recordDroppedEvent('sample_rate', 'transaction');
148-
}
117+
const dscString = parentContext?.traceState ? parentContext.traceState.get(SENTRY_TRACE_STATE_DSC) : undefined;
118+
const dsc = dscString ? baggageHeaderToDynamicSamplingContext(dscString) : undefined;
119+
120+
const sampleRand = parseSampleRate(dsc?.sample_rand) ?? Math.random();
121+
122+
const [sampled, sampleRate, localSampleRateWasApplied] = sampleSpan(
123+
options,
124+
{
125+
name: inferredSpanName,
126+
attributes: mergedAttributes,
127+
normalizedRequest: isolationScope?.getScopeData().sdkProcessingMetadata.normalizedRequest,
128+
parentSampled,
129+
parentSampleRate: parseSampleRate(dsc?.sample_rate),
130+
},
131+
sampleRand,
132+
);
133+
134+
const method = `${maybeSpanHttpMethod}`.toUpperCase();
135+
if (method === 'OPTIONS' || method === 'HEAD') {
136+
DEBUG_BUILD && logger.log(`[Tracing] Not sampling span because HTTP method is '${method}' for ${spanName}`);
149137

150138
return {
151139
...wrapSamplingDecision({
152-
decision: sampled ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,
140+
decision: SamplingDecision.NOT_RECORD,
153141
context,
154142
spanAttributes,
155143
sampleRand,
156-
downstreamTraceSampleRate: localSampleRateWasApplied ? sampleRate : undefined,
157-
}),
158-
attributes: {
159-
// We set the sample rate on the span when a local sample rate was applied to better understand how traces were sampled in Sentry
160-
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: localSampleRateWasApplied ? sampleRate : undefined,
161-
},
162-
};
163-
} else {
164-
return {
165-
...wrapSamplingDecision({
166-
decision: parentSampled ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,
167-
context,
168-
spanAttributes,
144+
downstreamTraceSampleRate: 0, // we don't want to sample anything in the downstream trace either
169145
}),
170146
};
171147
}
148+
149+
if (
150+
!sampled &&
151+
// We check for `parentSampled === undefined` because we only want to record client reports for spans that are trace roots (ie. when there was incoming trace)
152+
parentSampled === undefined
153+
) {
154+
DEBUG_BUILD && logger.log('[Tracing] Discarding root span because its trace was not chosen to be sampled.');
155+
this._client.recordDroppedEvent('sample_rate', 'transaction');
156+
}
157+
158+
return {
159+
...wrapSamplingDecision({
160+
decision: sampled ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,
161+
context,
162+
spanAttributes,
163+
sampleRand,
164+
downstreamTraceSampleRate: localSampleRateWasApplied ? sampleRate : undefined,
165+
}),
166+
attributes: {
167+
// We set the sample rate on the span when a local sample rate was applied to better understand how traces were sampled in Sentry
168+
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: localSampleRateWasApplied ? sampleRate : undefined,
169+
},
170+
};
172171
}
173172

174173
/** Returns the sampler name or short description with the configuration. */

0 commit comments

Comments
 (0)