-
Notifications
You must be signed in to change notification settings - Fork 365
Description
Tracer Version(s)
latest
Node.js Version(s)
lts
Bug Report
When using the Datadog SDK with the OTel Bridge, attributes set on a span retrieved via otel.trace.getActiveSpan() are ignored and do not appear in Datadog.
In our testing, we found that the OpenTelemetry "Active Span" and the Datadog internal "Active Scope" had drifted apart. Calls to the OTel object succeeded (no error thrown) but resulted in no data change, whereas calls to the Datadog scope in the exact same function worked immediately.
Reproduce
We observed this in a standard utility function used to enrich spans.
import ddTrace from 'dd-trace';
import { trace } from '@opentelemetry/api';
function enrichSpan(attributes) {
const otelSpan = trace.getActiveSpan();
const ddSpan = ddTrace.scope().active();
// 1. OTel Attempt: SILENT FAILURE
// This executes without error, but 'my.otel.attr' NEVER appears in the Datadog UI.
otelSpan?.setAttribute('my.otel.attr', 'failed');
// 2. Datadog Attempt: SUCCESS
// This works perfectly, and 'my.dd.attr' appears on the trace.
ddSpan?.addTags({ 'my.dd.attr': 'success' });
}Expected behavior
trace.getActiveSpan() should return a proxy to the currently active Datadog span (ddTrace.scope().active()). Setting attributes on one should be identical to adding tags to the other.
Actual behavior
-
trace.getActiveSpan()returns a span object (it is not undefined). -
No errors are thrown when calling
.setAttribute(). -
The attributes set via OTel are discarded and do not appear in Datadog.
-
The attributes set via ddTrace in the exact same function are saved and appear correctly.
Root Cause Analysis
This indicates a desynchronization between the Datadog ScopeManager and the OpenTelemetry ContextManager.
The Datadog SDK appears to be maintaining the "real" active span in its own internal storage (AsyncLocalStorage for DD). The OTel Bridge is supposed to mirror this state into the OTel context, but it fails to keep them in sync. As a result, getActiveSpan() returns a "Ghost Object"—a wrapper around a span that is no longer connected to the active trace context in the engine.
Reproduction Code
No response
Error Logs
No response
Tracer Config
No response
Operating System
No response
Bundling
Unsure