Support typed (int/double/bool) values for tracing custom tags / OTel span attributes
- Dominant language
- C++
- Stars
- 28.9k
- Forks
- 5.6k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 428
Description
*Title*: Support typed (int/double/bool) values for tracing custom tags / OTel span attributes
*Description*:
Today all tracing custom tags are string-only. `Tracing::Span::setTag(absl::string_view name, absl::string_view value)` (in `envoy/tracing/trace_driver.h`) is the only value sink, and the `value` custom tag (`FormatterCustomTag::applySpan`) always calls `setTag()` with the formatted string. As a result, on the OpenTelemetry tracer every custom-tag attribute is emitted as an OTLP `stringValue`.
This is a problem for span attributes that the semantic conventions define as non-string. The concrete case we hit is GenAI token usage — `gen_ai.usage.input_tokens` / `gen_ai.usage.output_tokens` / `gen_ai.usage.total_tokens` are defined as integers, but a custom tag can only emit them as strings, so consumers that expect an `int` receive a quoted string.
Interestingly, the typed machinery already exists in the OTel tracer but is not reachable from config: `Span::setAttribute(absl::string_view, const OTelAttribute&)` together with `OtlpUtils::populateAnyValue` already emit `int_value` / `double_value` / `bool_value` (Envoy uses this internally, e.g. for the HTTP status code). Custom tags simply have no way to opt into it.
**Proposal:** let a custom tag declare the type its resolved value should be parsed into — e.g. a `value_type` enum `{ STRING (default), INT, DOUBLE, BOOL }` on the `CustomTag` proto (`api/envoy/type/tracing/v3/custom_tag.proto`). This mirrors the config-driven value typing that already exists in the Header-To-Metadata filter (`Config.KeyValuePair.ValueType`), so it is an established pattern rather than a name-based heuristic. Tracers that support typed span attributes would emit a native typed attribute; tracers without typed-attribute support (and values that fail to parse) fall back to the current string behavior. Defaulting to `STRING` keeps full backward compatibility.
This is scoped to the scalar attribute types that OTel allows for span attributes (`string` / `int64` / `double` / `bool`); `bytes` / `kvlist` are intentionally excluded since they aren't valid span-attribute types.
*Relevant Links*:
- Header-To-Metadata `ValueType` precedent: https://github.com/envoyproxy/envoy/blob/main/api/envoy/extensions/filters/http/header_to_metadata/v3/header_to_metadata.proto
- OTel GenAI semantic conventions (token usage): https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/
Contributor guide
Research direction
Start with envoy/tracing/trace_driver.h and api/envoy/type/tracing/v3/custom_tag.proto, then trace FormatterCustomTag::applySpan into the OTel Span::setAttribute and OtlpUtils::populateAnyValue paths. Use the Header-To-Metadata ValueType configuration as a precedent; done means string, int, double, and bool custom tags preserve compatibility and produce native typed OTel attributes when supported, with string fallback otherwise.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- observability-sre
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100