Skip to content

fix: show spans referencing the current span (#2828) - #2868

Open
Vansh98789 wants to merge 7 commits into
hyperdxio:mainfrom
Vansh98789:fix/2828-reverse-span-links
Open

fix: show spans referencing the current span (#2828)#2868
Vansh98789 wants to merge 7 commits into
hyperdxio:mainfrom
Vansh98789:fix/2828-reverse-span-links

Conversation

@Vansh98789

Copy link
Copy Markdown
Contributor

Fix #2828 — Add Reverse Span Links ("Referenced By")

Summary

When inspecting a span in the trace span detail panel, users can see spans it links to through Span Links, but there was no way to see which other spans link back to it.

This made it difficult to trace producer → consumer relationships and follow-up span relationships.

This change adds a Referenced By section to show all spans that link to the currently selected span.

Approach

The fix is split into three changes:

1. New file — SpansReverseLinksSubpanel.tsx

  • Exports getReverseSpanLinks(rows, currentSpanId), a pure function that iterates over all rows in the same trace.

  • Extracts __hdx_span_links from each row.

  • Uses the existing getValidSpanLinks helper to parse and validate span links, gracefully handling malformed or missing data.

  • When a valid link's SpanId matches currentSpanId, the source row is recorded as a reverse link.

  • Each reverse link is enriched with:

    • TraceId

    • SpanId

    • SpanName

    • ServiceName

    • SpanKind

  • Exports SpansReverseLinksSubpanel, a React component that:

    • Wraps the reverse-link calculation in useMemo.

    • Shows "No spans reference this span" when there are no matching links.

    • Reuses the existing SpanLinksSubpanel for rendering.

    • Keeps the existing card layout and onOpenTrace click behavior.

2. Modified — DBRowOverviewPanel.tsx

  • Added hasReverseSpanLinks using useMemo.

  • It scans data.data for rows whose span links contain the current SpanId.

  • Short-circuits when:

    • No SpanId is available.

    • data.data is not an array.

  • Added a new Referenced By accordion section:

    • Accordion.Item value="reverseSpanLinks"

    • Positioned immediately after the existing Span Links section.

  • The section is conditionally rendered only when reverse links exist.

  • Uses the same two-space inset and onOpenLinkedTrace callback as the existing forward-links section.

  • Because the accordion supports multiple open panels, Span Links and Referenced By can be expanded simultaneously for easy comparison.

3. Test file — SpansReverseLinksSubpanel.test.tsx

Tests focus on the getReverseSpanLinks pure function rather than the React component, keeping the tests fast and focused.

Covered cases:

  • null / undefined rows → returns []

  • undefined currentSpanId → returns []

  • No spans link to the given SpanId → returns []

  • Multiple spans link to the same SpanId → returns all matching spans with the correct attributes

  • Spans with missing __hdx_span_links → skipped gracefully

Why This Works

  • Reuses the existing getValidSpanLinks validation logic, avoiding duplication.

  • Reuses the existing SpanLinksSubpanel rendering, so there is no new UI pattern to maintain.

  • The required data is already loaded in memory through data.data from useRowData, so scanning for reverse links does not introduce an additional network request.

  • The accordion remains collapsed/hidden when there are no reverse links, keeping the span detail panel uncluttered.

  • Users can compare forward and reverse relationships by opening Span Links and Referenced By at the same time.

Screenshots / Video

Before | After -- | -- The Referenced By section did not exist. | A new Referenced By accordion section shows spans referencing the current span.

How to Test on Vercel Preview

Preview route:

/traces/[id]

Steps

  1. Open a trace containing spans with __hdx_span_links pointing to other spans.

  2. Select a span that is referenced by one or more other spans.

  3. In the span detail panel, scroll to the Referenced By accordion section.

  4. Verify that it lists all spans whose span links include the current span's SpanId.

  5. Click a reverse-link entry.

  6. Confirm that it navigates to the referencing span's panel.

References

@changeset-bot

changeset-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6a73354

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@hyperdx/app Patch
@hyperdx/api Patch
@hyperdx/otel-collector Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

@Vansh98789 is attempting to deploy a commit to the HyperDX Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps

greptile-apps Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This follow-up wires the waterfall’s full trace rows into the span detail panel and projects the fields needed to discover reverse span links. It also adds release metadata and tests for the reverse-link extraction helper.

  • Adds a Referenced By accordion backed by full-trace waterfall rows.
  • Projects span-link, trace, service, name, and kind data for reverse-link rendering and navigation.
  • Adds a patch changeset and focused reverse-link extraction tests.

Confidence Score: 4/5

The PR should not merge until the Referenced By visibility check uses the same validation contract as its renderer.

Malformed span-link entries can make the new accordion appear even though its renderer rejects every matching entry and displays an empty result.

Files Needing Attention: packages/app/src/components/DBRowOverviewPanel.tsx, packages/app/src/components/SpansReverseLinksSubpanel.tsx

Important Files Changed

Filename Overview
packages/app/src/components/DBTraceWaterfallChart.tsx Projects reverse-link source fields and exposes the fetched trace rows to the parent panel.
packages/app/src/components/DBTracePanel.tsx Stores waterfall trace rows and passes them into the selected span overview.
packages/app/src/components/DBRowOverviewPanel.tsx Adds the Referenced By accordion, but its visibility predicate is less strict than the renderer’s validation.
packages/app/src/components/SpansReverseLinksSubpanel.tsx Extracts referencing spans through the existing span-link validator and reuses the forward-link renderer.
packages/app/src/components/tests/SpansReverseLinksSubpanel.test.tsx Covers basic extraction and missing-link cases but not malformed links that expose the visibility mismatch.
.changeset/reverse-span-links.md Records the user-visible reverse-span-link feature as an application patch.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Q[Waterfall trace query] --> R[Full trace rows]
  R --> P[DBTracePanel state]
  P --> O[RowOverviewPanel]
  O --> V{Matching reverse link?}
  V -->|Yes| A[Referenced By accordion]
  A --> S[SpansReverseLinksSubpanel]
  S --> N[Open referencing span]
Loading

Fix All in Greploop

Fix All in Claude Code Fix All in Conductor Fix All in Cursor Fix All in Codex

Reviews (7): Last reviewed commit: "fix: select TraceId/SpanKind/SpanLinks i..." | Re-trigger Greptile

Comment thread packages/app/src/components/DBRowOverviewPanel.tsx
Comment on lines 367 to +384
</Accordion.Panel>
</Accordion.Item>
)}
{hasReverseSpanLinks && (
<Accordion.Item value="reverseSpanLinks">
<Accordion.Control>
<Text size="sm" ps="md">
Referenced By
</Text>
</Accordion.Control>
<Accordion.Panel>
<Box px="md">
<SpansReverseLinksSubpanel
rows={data?.data}
currentSpanId={firstRow?.SpanId as string | undefined}
onOpenTrace={onOpenLinkedTrace}
/>
</Box>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 User-facing changeset is missing

This adds the user-visible Referenced By panel to the published application package without a corresponding .changeset/ entry, so the release metadata omits this behavior change.

Context Used: CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

Comment thread packages/app/src/components/DBRowOverviewPanel.tsx
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview Aug 12, 2026 1:52pm
hyperdx-storybook Ready Ready Preview Aug 12, 2026 1:52pm

Request Review

Comment thread packages/app/src/components/DBTracePanel.tsx Outdated
@Vansh98789

Copy link
Copy Markdown
Contributor Author

Hi @pulpdrew
Deep review is failing due to pull_request_target fork-checkout restrictions since this is from a fork -might need maintainer approval or a workflow tweak.
Thanks

@karl-power

Copy link
Copy Markdown
Contributor

Thanks for the PR @Vansh98789. There are some issues with the approach:

  1. The feature never renders: span links aren't in the query projection:
    The design hinges on allTraceRows containing __hdx_span_links, but those rows come from useFilteredEventsAroundFocusgetConfig in DBTraceWaterfallChart.tsx, which builds an explicit select list: Body, Timestamp, SpanId, ServiceName, and for trace sources Duration, ParentSpanId, StatusCode, SpanAttributes, SpanEvents. The span-links expression is never added to it. (__hdx_span_links only exists on rows from useRowData, a different hook that queries the single selected row.)

    As a result, every row in allTraceRows has row.__hdx_span_links === undefined, the scan in hasReverseSpanLinks never matches, and the "Referenced By" accordion is unreachable in production. The last two commits changed where the rows come from (data.data → allTraceRows) but not what the query selects, so the underlying issue Greptile flagged is still there.

  2. Even with links present, entries would render empty:
    getReverseSpanLinks enriches each match from row.SpanName, row.SpanKind, and row.TraceId, but none of these exist on the query results either: the span name is aliased as Body in this query, SpanKind isn't selected at all, and TraceId only appears in the WHERE clause.

  3. Duplicate full-trace queries on every trace panel open:
    DBTraceWaterfallChartContainer already calls useFilteredEventsAroundFocus internally to fetch the trace's rows. The new call in DBTracePanel runs in parallel with it, and each invocation issues two ClickHouse queries (before/after the focus date). They won't dedupe in the query cache because the waterfall passes hiddenRowExpression when filters are active, so the configs differ.

Also, even with all the blockers fixed, the approach can't address the issue it's linked to. The scan only looks at rows within the currently loaded trace, but the producer→consumer pattern described in #2828 typically crosses trace boundaries: the consumer starts its own trace and links back to the producer's span.

@Vansh98789

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review @karl-power. Fixed all three:

  • Added TraceId, SpanKind, and SpanLinks to the getConfig select list in DBTraceWaterfallChart.tsx
  • Fixed getReverseSpanLinks to read row.Body instead of row.SpanName
  • Removed the duplicate useFilteredEventsAroundFocus call in DBTracePanel.tsx - now reusing the rows the waterfall already fetches via a new onTraceRowsChange callback

On the cross-trace point - agreed that's the fuller version of what #2828 asks for. Want me to scope this PR to same-trace only for now and file a follow-up for cross-trace, or would you rather I take that on here?

Comment on lines +216 to +227
const sl = row.__hdx_span_links;
if (!Array.isArray(sl)) continue;
for (const link of sl) {
if (
link &&
typeof link === 'object' &&
'SpanId' in link &&
link.SpanId === currentSpanId
) {
return true;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Visibility accepts invalid span links

When a trace row has the selected SpanId but lacks a string TraceId or an Attributes value, hasReverseSpanLinks displays the Referenced By accordion even though getValidSpanLinks rejects that entry, causing the expanded panel to report that no spans reference the selected span.

Suggested change
const sl = row.__hdx_span_links;
if (!Array.isArray(sl)) continue;
for (const link of sl) {
if (
link &&
typeof link === 'object' &&
'SpanId' in link &&
link.SpanId === currentSpanId
) {
return true;
}
}
const validLinks = getValidSpanLinks(row.__hdx_span_links);
if (validLinks.some(link => link.SpanId === currentSpanId)) {
return true;
}

Knowledge Base Used: App Components and Charts

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

@karl-power

Copy link
Copy Markdown
Contributor

@Vansh98789

On the cross-trace point - agreed that's the fuller version of what #2828 asks for. Want me to scope this PR to same-trace only for now and file a follow-up for cross-trace, or would you rather I take that on here?

Yes please. In practice, a span link is more likely to point to a span of another trace as it exists to model a relationship that doesn't work for same-trace spans.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Show span links from the producer side too

2 participants