Skip to content

feat(core): Emit no_parent_span client outcomes for discarded spans requiring a parent#20350

Merged
s1gr1d merged 7 commits intodevelopfrom
lms/feat-record-no_parent_span-client-outcome
Apr 20, 2026
Merged

feat(core): Emit no_parent_span client outcomes for discarded spans requiring a parent#20350
s1gr1d merged 7 commits intodevelopfrom
lms/feat-record-no_parent_span-client-outcome

Conversation

@Lms24
Copy link
Copy Markdown
Member

@Lms24 Lms24 commented Apr 16, 2026

This PR adds reporting a client discard outcome for spans we skip because they require a parent span to be active. This happens when onlyIfParent: true is set when starting spans, or in custom logic for http.client spans. With this PR, we should now get a much clearer picture of how many spans users are missing out on.

In span streaming, we'll always emit them (see #17932) spans.

closes https://linear.app/getsentry/issue/SDK-1123/add-client-report-outcome-for-dropped-spans-because-of-missing-parent

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 16, 2026

size-limit report 📦

Path Size % Change Change
@sentry/browser 25.88 kB - -
@sentry/browser - with treeshaking flags 24.35 kB - -
@sentry/browser (incl. Tracing) 43.81 kB +0.1% +40 B 🔺
@sentry/browser (incl. Tracing + Span Streaming) 45.5 kB +0.08% +35 B 🔺
@sentry/browser (incl. Tracing, Profiling) 48.73 kB +0.08% +36 B 🔺
@sentry/browser (incl. Tracing, Replay) 82.93 kB +0.05% +36 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 72.43 kB +0.05% +34 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 87.62 kB +0.04% +35 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 99.87 kB +0.04% +38 B 🔺
@sentry/browser (incl. Feedback) 42.7 kB - -
@sentry/browser (incl. sendFeedback) 30.55 kB - -
@sentry/browser (incl. FeedbackAsync) 35.55 kB - -
@sentry/browser (incl. Metrics) 27.16 kB - -
@sentry/browser (incl. Logs) 27.29 kB - -
@sentry/browser (incl. Metrics & Logs) 27.98 kB - -
@sentry/react 27.62 kB - -
@sentry/react (incl. Tracing) 46.05 kB +0.09% +41 B 🔺
@sentry/vue 30.71 kB +0.05% +15 B 🔺
@sentry/vue (incl. Tracing) 45.62 kB +0.09% +41 B 🔺
@sentry/svelte 25.89 kB - -
CDN Bundle 28.55 kB - -
CDN Bundle (incl. Tracing) 44.94 kB +0.25% +112 B 🔺
CDN Bundle (incl. Logs, Metrics) 29.93 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 46.03 kB +0.26% +118 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 68.83 kB - -
CDN Bundle (incl. Tracing, Replay) 81.9 kB +0.15% +116 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 82.97 kB +0.15% +121 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 87.41 kB +0.15% +124 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 88.49 kB +0.15% +125 B 🔺
CDN Bundle - uncompressed 83.4 kB - -
CDN Bundle (incl. Tracing) - uncompressed 134.3 kB +0.21% +270 B 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed 87.55 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 137.72 kB +0.2% +270 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 210.91 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 251.53 kB +0.11% +270 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 254.93 kB +0.11% +270 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 264.45 kB +0.11% +270 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 267.83 kB +0.11% +270 B 🔺
@sentry/nextjs (client) 48.58 kB +0.08% +37 B 🔺
@sentry/sveltekit (client) 44.22 kB +0.09% +39 B 🔺
@sentry/node-core 58.02 kB +0.1% +55 B 🔺
@sentry/node 174.89 kB +0.06% +90 B 🔺
@sentry/node - without tracing 97.98 kB +0.07% +66 B 🔺
@sentry/aws-serverless 115.21 kB +0.06% +58 B 🔺

View base workflow run

@linear-code
Copy link
Copy Markdown

linear-code bot commented Apr 16, 2026

@Lms24 Lms24 marked this pull request as ready for review April 16, 2026 15:28
@Lms24 Lms24 self-assigned this Apr 16, 2026
@Lms24 Lms24 requested review from chargome, nicohrubec and s1gr1d April 16, 2026 15:34
@s1gr1d s1gr1d self-assigned this Apr 17, 2026
Comment thread packages/opentelemetry/src/trace.ts Outdated
Comment on lines +51 to +56
const shouldSkipSpan = options.onlyIfParent && !trace.getSpan(activeCtx);
const ctx = shouldSkipSpan ? suppressTracing(activeCtx) : activeCtx;

if (shouldSkipSpan) {
getClient()?.recordDroppedEvent('no_parent_span', 'span');
}
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.

Maybe this could be made a bit more robust. Right now it's checking shouldSkipSpan but the value of the variable could depend on something else than onlyIfParent in the future. Then this would be wrong.

The test also only check for dropped events and not necessarily that this resulted because of a missing parent span.

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.

Yeah I guess we could inline the variable or name it a bit more precise, unless you had something else in mind?

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.

I added some additional tests and changed the variable name to a more descriptive one (missingRequiredParent) and not behaviorial one. shouldSkipSpan could include any condition why we skip spans.

It was not really possible to change the general structure here.

| 'ignored'
| 'invalid';
| 'invalid'
| 'no_parent_span';
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.

do we need a change in relay for this?

Comment thread packages/opentelemetry/src/trace.ts Outdated
Comment on lines +51 to +56
const shouldSkipSpan = options.onlyIfParent && !trace.getSpan(activeCtx);
const ctx = shouldSkipSpan ? suppressTracing(activeCtx) : activeCtx;

if (shouldSkipSpan) {
getClient()?.recordDroppedEvent('no_parent_span', 'span');
}
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.

Yeah I guess we could inline the variable or name it a bit more precise, unless you had something else in mind?

@s1gr1d s1gr1d enabled auto-merge (squash) April 20, 2026 09:20
@s1gr1d s1gr1d disabled auto-merge April 20, 2026 09:20
@s1gr1d s1gr1d enabled auto-merge (squash) April 20, 2026 09:21
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2b11222. Configure here.

Co-authored-by: Nicolas Hrubec <nicolas.hrubec@outlook.com>
Comment on lines +162 to 164
getClient()?.recordDroppedEvent('no_parent_span', 'span');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: http.client spans without a parent are counted as dropped twice: once in startInactiveSpan and again in the SentrySampler, leading to inflated metrics.
Severity: MEDIUM

Suggested Fix

Prevent the double-counting of dropped events. One approach is to remove the recordDroppedEvent('no_parent_span', 'span') call from startInactiveSpan for http.client spans, allowing the SentrySampler to handle this case exclusively as it did previously.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: packages/opentelemetry/src/trace.ts#L162-L164

Potential issue: When an `http.client` span is created with `onlyIfParent: true` and no
active parent span exists, the new logic in `startInactiveSpan` records a
`'no_parent_span'` dropped event. However, the span creation process continues, and the
`SentrySampler` is also invoked. The sampler contains separate logic to detect and
record a dropped event for `http.client` spans without a local parent. This results in
the same dropped span being counted twice, which will inflate the `no_parent_span`
outcome metrics.

Did we get this right? 👍 / 👎 to inform future reviews.

@s1gr1d s1gr1d merged commit be13537 into develop Apr 20, 2026
244 of 245 checks passed
@s1gr1d s1gr1d deleted the lms/feat-record-no_parent_span-client-outcome branch April 20, 2026 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants