fix(opentelemetry): preserve error.type under OTel semantics#5037
fix(opentelemetry): preserve error.type under OTel semantics#5037link04 wants to merge 2 commits into
Conversation
Config Audit |
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: c8a3fd5 | Docs | Datadog PR Page | Give us feedback! |
bd8417b to
953a2e6
Compare
BenchmarksBenchmark execution time: 2026-07-24 15:34:26 Comparing candidate commit c8a3fd5 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 326 metrics, 0 unstable metrics, 1 flaky benchmarks without significant changes.
|
zacharycmontoya
left a comment
There was a problem hiding this comment.
This change looks good to me. In OTel semantics mode, we will emit the span.type attribute if a user sets it, but we won't generate it ourselves when recording an error status
error.type is a stable OpenTelemetry attribute set by instrumentation. Under
DD_TRACE_OTEL_SEMANTICS_ENABLED the bridge overwrote it with the reflect type of
the status wrapper ("*errors.errorString") via WithError, and the OTLP converter
suppressed it as a Datadog-only key.
Mark the span errored without injecting DD error.* tags, and remove error.type
from ddOnlyMetaKeys so the instrumentation-set value passes through.
953a2e6 to
169942f
Compare
What does this PR do?
Under
DD_TRACE_OTEL_SEMANTICS_ENABLED, preserves the OpenTelemetryerror.typeattribute end-to-end instead of clobbering it and dropping it.ddtrace/opentelemetry/span.go): on an error-status span, the OTel semantics path now marks the span errored viaSetTag(ext.Error, true)instead oftracer.WithError(errors.New(description)).WithErrorruns after instrumentation attributes are flushed and overwroteerror.typewith the reflect type of the status wrapper ("*errors.errorString"), and also injectederror.stack. The non-semantics path is unchanged.ddtrace/tracer/span_to_otlp.go): removeserror.typefromddOnlyMetaKeys, so it is no longer suppressed from OTLP output under semantics.Net effect under semantics: an instrumentation-set
error.type(e.g."*net.OpError"from otelhttp client spans) survives to OTLP; when none is set,error.typeis simply absent (the error state is carried by the OTLP span status) rather than a meaningless"*errors.errorString".Motivation
error.typeis a Stable attribute in the OpenTelemetry semantic conventions (https://opentelemetry.io/docs/specs/semconv/registry/attributes/error/). Under OTel semantics we should emit the instrumentation-provided value, not a Datadog-internal reflect-type string, and we must not drop it. Follow-up to #4889.Behavior under APM export (intended)
The bridge change applies regardless of export format. Under semantics, an error span exported to the Datadog Agent (MessagePack, not OTLP) carries
error=1anderror.message, but noerror.stack, anderror.typeonly if instrumentation set one — previously it always receivederror.type="*errors.errorString"plus a stack. This is intended for the opt-in semantics mode: emit the instrumentation-providederror.type(or nothing), never a Datadog-internal reflect-type string.error.messageis still set unconditionally because it feeds the OTLP status message.Testing
ddtrace/tracer/span_to_otlp_test.go: updatedTestConvertSpanAttributesOtelSemanticsto asserterror.typepasses through (with a realistic"*net.OpError"value) whileerror.message/error.stack/span.kindremain suppressed.ddtrace/opentelemetry/span_test.go: addedTestSpanEndErrorTypeOtelSemanticscovering the bridgeEnd()branch under semantics — an instrumentation-seterror.typesurvives with noerror.stack, and when none is set no reflect-typeerror.typeis injected.TestSpanEndgains one assertion pinning the non-semanticsWithErrorpath (still injects"*errors.errorString").Reviewer's Checklist