Skip to content

feat(spans): Equalize name and description for manual spans#6070

Open
loewenheim wants to merge 7 commits into
masterfrom
sebastian/name-description-manual
Open

feat(spans): Equalize name and description for manual spans#6070
loewenheim wants to merge 7 commits into
masterfrom
sebastian/name-description-manual

Conversation

@loewenheim

@loewenheim loewenheim commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

This ensures that for spans (V1 or V2) with an origin of "manual", name and description coincide. For V1 spans, this means copying the description to the name, and the reverse for V2 spans. Other spans behave as before.

  • For backfilling the name, the new logic is inserted just before the places we would create a name based on sentry-conventions.
  • For backfilling the description, there is a new processing step backfill_description that runs right after PII scrubbing. Unfortunately it can't simply be integrated into normalize_span because it's not safe to backfill the description before PII scrubbing—the description could end up containing a URL with PII, for example. Also, in the course of this, we move the (limited) functionality that existed for backfilling the description based on attributes out of write_legacy_attributes (where it was somewhat misplaced anyway) and centralize it in normalize_sentry_description.

Future work:

  • Flesh out description backfilling logic based on sentry-conventions
  • The concern about PII noted above also applies to the name backfilling that already exists. We'll have to find a solution for that.

Closes INGEST-955.

@loewenheim loewenheim requested a review from a team as a code owner June 10, 2026 14:55
@loewenheim loewenheim self-assigned this Jun 10, 2026
== Some("manual")
{
return name.value().cloned();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Manual origin skips query backfill

Medium Severity

derive_description_for_v2_span returns the span name whenever sentry.origin is "manual" before considering db.query.text or HTTP attributes. Child spans that inherit a manual trace origin but lack their own origin can keep a convention-derived name, so description backfill copies that label instead of the DB query or HTTP URL that used to be written via write_legacy_attributes.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 61a998e. Configure here.

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 legitimately don't understand what this is trying to say.

@elramen elramen Jun 11, 2026

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 think it is trying to say "A child span might have name derived based on convention rules. Do we really want to use this derived name, instead of looking at DB__QUERY__TEXT etc., when the child span wasn't really manually instrumented (it just inherited manual)?"

@linear-code

linear-code Bot commented Jun 10, 2026

Copy link
Copy Markdown

INGEST-955

continue;
};

attributes.insert(legacy_attribute, attr.value.clone());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Legacy action prefers DB over HTTP

Low Severity

In write_legacy_attributes, skipping when a legacy key already exists means sentry.action is filled from the first mapped conventional attribute and later mappings are ignored. When both db.operation.name and http.request.method are present, sentry.action stays on the DB value instead of being overwritten by the HTTP method as before.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 03de602. Configure here.

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.

The behavior for spans which have both db and http attributes (which should not happen in practice) was already arbitrary before, now it's arbitrary in the other direction.

.is_some_and(|attrs| attrs.contains_key(SENTRY__DESCRIPTION))
{
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Empty description blocks manual backfill

Medium Severity

normalize_sentry_description returns immediately when sentry.description is present, without treating an empty value as missing. For manual-origin spans with a non-empty name but an empty sentry.description attribute, description is never copied from name, so name and description can stay out of sync after processing.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 03de602. Configure here.

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.

It's intended that if someone manually sets a description it doesn't get clobbered by the name. This includes the case of an empty description.


if new_span.origin.value().is_none() {
new_span.origin = origin.clone();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Trace origin applied to child spans

Medium Severity

When extracting transaction child spans, missing span origin is filled from the trace context before V1→V2 conversion. If the trace origin is manual, children without their own origin inherit it and later use manual name/description rules instead of convention-based naming.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 03de602. Configure here.

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.

Correct.

Comment thread relay-server/src/processing/spans/process.rs Outdated
Comment thread relay-server/src/processing/spans/process.rs
if new_span.origin.value().is_none() {
new_span.origin = origin.clone();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Transaction spans skip description backfill

Medium Severity

normalize_sentry_description runs only in the standalone span pipeline after PII scrubbing. Transaction-extracted spans are converted with span_v1_to_span_v2 and never get that step, so manual spans (including children that inherit trace manual origin) can keep a convention-inferred name while sentry.description stays unset.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 18d7a6f. Configure here.

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.

Backfilling the description from the name is not a concern for transaction-extracted spans, they need to worry about the converse.

eap::normalize_sentry_description(&mut span.attributes, &span.name);
}
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Manual spans desync after scrub

Medium Severity

For manual-origin spans, backfill_description skips when sentry.description already exists, but PII scrubbing runs immediately before it and can change that attribute. Top-level span.name is not updated to match, so name and description can diverge after the step meant to equalize them.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e7c7306. Configure here.

Comment thread relay-spans/src/name.rs Outdated
Some(name_for_op_and_attributes(op, &AttributeGetter(attributes)))
}

fn name_for_origin_and_description(

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.

Suggested change
fn name_for_origin_and_description(
fn name_from_origin_and_description(

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.

Good call.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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.

There are 7 total unresolved issues (including 6 from previous reviews).

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 7dbff4a. Configure here.

== Some("manual")
{
return name.value().cloned();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Manual backfill skips PII scrub

Medium Severity

For "manual" origin, backfill_description runs after PII scrub and sets sentry.description from the top-level span.name. That value is not taken from already-scrubbed attributes, and the new attribute is never run through scrub again—unlike DB/HTTP backfill paths that read scrubbed attribute data.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7dbff4a. Configure here.

};

process::scrub(&mut spans, ctx);
process::backfill_description(&mut spans);

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 process::normalize_derived or something similar?

Comment on lines +63 to +64
.value()
.is_some_and(|attrs| attrs.contains_key(SENTRY__DESCRIPTION))

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.

This might need a check which doesn't just use value() but also considers meta, Empty trait might be able to do that for you.

Comment on lines +21 to +24
if attributes
.get_value(SENTRY__ORIGIN)
.and_then(|o| o.as_str())
== Some("manual")

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.

This formatting is weird af

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