Motivation
I maintain a TraceProcessor that acts as an allowlist-based redaction filter: it walks each span's tags, keeps the ones on a known-safe allowlist, transforms a few (e.g. redacts message bodies while keeping the command name), and drops everything else. This is a common shape for teams that need to guarantee no unexpected tag ever ships to Datadog — a defense-in-depth layer against an integration or a well-meaning set_tag() call leaking PII/PHI.
Under ddtrace 2.x / 3.x this was straightforward: the processor read span._meta, computed the sanitized dict, and assigned it back. _meta was a single-underscore internal attribute, but the pattern was stable and widely used.
In 4.x the Span was restructured (data moved into a native SpanData base + context) and _meta is no longer accessible on the Span. The public API kept the additive tag operations — get_tag, set_tag, get_tags, set_tags — but there is no public tag removal. set_tag(k, None) doesn't remove; it stores None. The only working call I've found is span._remove_attribute(k), which is defined on the internal SpanData base.
Ask
A supported public method for tag removal on Span. Something like:
span.remove_tag(key: str) -> None
and matching remove_metric(key) / remove_struct_tag(key) for the parallel storage. Alternatively, blessing _remove_attribute (etc.) as stable via docs would achieve the same practical outcome for consumers.
Current workaround
Falling back to the private methods:
span._remove_attribute(key) — tag removal
span._has_meta_structs() / span._get_meta_structs() / span._remove_struct_tag(key) — the same, for struct-typed metadata
These work in 4.11.x. It's a code smell, and it puts consumers on a manual-review cadence for every ddtrace bump — which is the opposite of what a public API should require.
Alternatives considered
- Redact at write time (subclass
Span.set_tag) — inverts the design, wraps a hot path, and creates surface area for accidental bypass.
- Drop the whole trace when an unexpected tag appears — nuclear; auto-instrumentation adds runtime tags on every span, so this would drop most traces in practice.
- Skip 4.x — not viable long-term; 4.8.2 is the earliest release with the fix for CVE-2026-50271 (baggage-header DoS).
Happy to send a PR if there's alignment on the surface.
Motivation
I maintain a
TraceProcessorthat acts as an allowlist-based redaction filter: it walks each span's tags, keeps the ones on a known-safe allowlist, transforms a few (e.g. redacts message bodies while keeping the command name), and drops everything else. This is a common shape for teams that need to guarantee no unexpected tag ever ships to Datadog — a defense-in-depth layer against an integration or a well-meaningset_tag()call leaking PII/PHI.Under ddtrace 2.x / 3.x this was straightforward: the processor read
span._meta, computed the sanitized dict, and assigned it back._metawas a single-underscore internal attribute, but the pattern was stable and widely used.In 4.x the Span was restructured (data moved into a native
SpanDatabase +context) and_metais no longer accessible on the Span. The public API kept the additive tag operations —get_tag,set_tag,get_tags,set_tags— but there is no public tag removal.set_tag(k, None)doesn't remove; it storesNone. The only working call I've found isspan._remove_attribute(k), which is defined on the internalSpanDatabase.Ask
A supported public method for tag removal on
Span. Something like:and matching
remove_metric(key)/remove_struct_tag(key)for the parallel storage. Alternatively, blessing_remove_attribute(etc.) as stable via docs would achieve the same practical outcome for consumers.Current workaround
Falling back to the private methods:
span._remove_attribute(key)— tag removalspan._has_meta_structs()/span._get_meta_structs()/span._remove_struct_tag(key)— the same, for struct-typed metadataThese work in 4.11.x. It's a code smell, and it puts consumers on a manual-review cadence for every ddtrace bump — which is the opposite of what a public API should require.
Alternatives considered
Span.set_tag) — inverts the design, wraps a hot path, and creates surface area for accidental bypass.Happy to send a PR if there's alignment on the surface.