Skip to content

refactor(trace): Combine span decoration matching into one registry - #4254

Open
udita-0707 wants to merge 10 commits into
jaegertracing:mainfrom
udita-0707:chore/combine-span-decorations
Open

refactor(trace): Combine span decoration matching into one registry#4254
udita-0707 wants to merge 10 commits into
jaegertracing:mainfrom
udita-0707:chore/combine-span-decorations

Conversation

@udita-0707

Copy link
Copy Markdown
Contributor

Which problem is this PR solving?

  • Resolves [chore]: Combine span decoration mechanisms #4223
  • Span timeline icons and pills each maintained their own “which attributes matter” lists; adding a signal meant touching multiple files and risked redundant decorations (e.g. category pills that only repeat what an icon already shows)

Description of the changes

  • Add a shared spanDecorations.ts registry of decoration families (db / http / messaging / rpc) that owns both namespace→icon matching and value-bearing pill sources
  • Wire span-icons.ts and spanPills.tsx to that registry (lookup/render only; no matching lists of their own)
  • Encode the redundancy rule in the registry: icons = category presence; pills = attribute values the icon cannot show (no span.kind / category-only pills)
  • Keep GenAI classification in detect.ts / GenAISpanIcon (intentionally separate)
  • Keep spanPillsEnabled as a separate config toggle
  • No user-visible behavior change — same icons, same pills, same emission order

Out of scope (follow-up): messaging.system pill (icon exists today; pill TBD)

How was this change tested?

  1. Manual: uploaded a smoke trace with HTTP / DB / RPC / messaging / GenAI / 5xx spans; verified icons + pills match prior behavior (messaging icon-only; GenAI kind icon only; no duplicate icons)
  2. Unit: spanDecorations.test.ts, span-icons.test.ts, spanPills.test.ts, SpanBarRow.test.jsx
  3. pnpm run fmt, pnpm run tsc-lint, pnpm test, pnpm run build

Checklist

AI Usage in this PR (choose one)

  • None
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

Signed-off-by: udita-0707 <uditaa17644@gmail.com>
@udita-0707
udita-0707 requested a review from a team as a code owner July 24, 2026 04:13
@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.03%. Comparing base (74ea003) to head (fbe2e78).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4254   +/-   ##
=======================================
  Coverage   92.02%   92.03%           
=======================================
  Files         373      373           
  Lines       12056    12068   +12     
  Branches     3258     3262    +4     
=======================================
+ Hits        11095    11107   +12     
  Misses        839      839           
  Partials      122      122           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@udita-0707

Copy link
Copy Markdown
Contributor Author

@yurishkuro @swetalin-10 PTAL

@swetalin-10

swetalin-10 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Went through this — checked out the current head, ran it, and it renders correctly. Solid work on the consolidation itself.

Still the one open thing though — on the issue you'd asked about messaging.system and we agreed to add it there. It's not in this PR and there's been no explanation on the issue or the PR for why. What's the reason you dropped it? If it's a "do it after" call, that's fine. Otherwise happy to see it added here.

@udita-0707

udita-0707 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Thank you @swetalin-10 for taking a look.
Actually it is planned as a follow-up. I wanted to keep the consolidation work separate from the message.system pill changes.
I have mentioned that in the PR description already that it is out of scope for this PR.

udita-0707 and others added 3 commits July 27, 2026 06:32
Signed-off-by: Udita <153092248+udita-0707@users.noreply.github.com>
Signed-off-by: Udita <153092248+udita-0707@users.noreply.github.com>
Signed-off-by: udita-0707 <uditaa17644@gmail.com>
*
* Rules encoded here:
* - No pill for a pure category signal already covered by an icon (e.g. span.kind).
* - gen_ai has no namespace icon here: GenAISpanIcon + classifySpan handle that (#4217).

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.

what is the motivation for splitting out the GenAI mechanism?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

keeping classifySpan / GenAISpanIcon separate on purpose. Namespace icons are presence-only; GenAI picks a kind fromgen_ai.operation.name and that kind is also used outside the timeline (GenAI tab / isGenAITrace). A generic gen_ai namespace icon here is what caused the double-icon bug in #4217. The model name still belongs in PILL_SOURCES as a value pill.

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.

Namespace icons are presence-only

key+value check is just a generalization of "key exists" check. I am not convinced by the argument.

A generic gen_ai namespace icon here is what caused the double-icon bug in #4217

Even more reason to have a single mechanism instead of two.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I see your point. Presence-only vs key+value doesn't really feel like a meaningful distinction.
What I'm thinking is, if we're moving towards a single mechanism in spanDecorations.ts, we could structure it like this:

  1. Have a single ordered list of rules, where each rule defines both the match and the outcome (icon and/or pill):

    • anyKeyPrefix (db., http., etc.) → namespace icon
    • key + value (gen_ai.operation.namechat, invoke_agent, etc.) → GenAI-specific icon
    • gen_ai. prefix as a fallback → generic GenAI icon
    • specific keys → pills (http.status_code, db.system, gen_ai.request.model, etc.)
  2. Use a single icon resolver in SpanBarRow, with GenAI-specific rules taking priority over namespace rules. That way we avoid rendering getSpanIconComponent and GenAISpanIcon together.

  3. classifySpan can continue handling the GenAI tab and isGenAITrace, but instead of maintaining its own mapping, it can read the same operation → kind registry so there's only one source of truth.

here's what I plan:

  • In this PR, flatten things to NAMESPACE_ICONS + PILL_SOURCES and remove DECORATION_FAMILIES / PILL_ONLY_SOURCES.
  • Then either as an immediate follow-up (or in this PR if you'd prefer), fold the GenAI icon logic into the same matcher and remove the dual-render path entirely.

If you'd prefer, I can also include the GenAI unification in this PR so everything is reviewed together.

@yurishkuro ,would this align with what you had 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.

just include unification

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

okay noted!

@udita-0707
udita-0707 requested a review from yurishkuro July 30, 2026 15:19
@udita-0707

Copy link
Copy Markdown
Contributor Author

@yurishkuro this is up for review, please have a look

@yurishkuro yurishkuro changed the title chore(trace): Combine span decoration matching into one registry refactor(trace): Combine span decoration matching into one registry Aug 14, 2026
@yurishkuro yurishkuro added the changelog:refactoring Internal, non-functional code improvements label Aug 14, 2026

@yurishkuro yurishkuro left a comment

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.

Thanks for this, and sorry for the moving target — reviewing it made clear my issue text was too vague, so I have written an actual design into #4223. Two lists in one file was a fair reading of what I originally wrote.

The deltas from what you have: one entry per namespace owning both its icon and its pills (list position replaces the priority field and the separate PILL_SOURCES order), GEN_AI_OPERATION_TO_KIND back to being private in utils/genai/detect.ts, and span-icons.ts plus GenAISpanIcon.tsx collapsing into one presentational component. The reasoning for the middle one is worth a look: classifySpan runs in OtelSpanFacade's constructor at transform time, so that map is classification rather than decoration, and importing it from a component makes every trace transform depend on TraceTimelineViewer — and on three react-icons packages.

Worth keeping as-is: the resolver preferring GenAI kind over namespace icons is exactly right and is now written into the design, GEN_AI_KIND_META is in the right place, and the three getSpanDecorationIcon tests are the ones that earn their keep.

Two things the design does not cover, both from this diff:

  • The GenAI icon now renders before the error icon; on main it came after. I think that is an improvement, but it needs saying in the description and pinning with a test rather than shipping under "no user-visible behavior change".
  • Most of spanDecorations.test.ts restates the literals above it — priorities unique and ascending, pill labels in a fixed order, no category-only pill. Those pass through any real regression, and several stop meaning anything once the two lists merge. #4223 lists the behavior cases I would rather have.

Nits: title should be refactor(trace): … so it maps to changelog:refactoring; it needs a changelog: label, which I will add once the title settles; and if (bestPriority === 0) break; is unreachable now that priorities start at 1.


🤖 Drafted with Claude Code, reviewed by @yurishkuro

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

Labels

changelog:refactoring Internal, non-functional code improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[chore]: Combine span decoration mechanisms

3 participants