Conversation
BenchmarksBenchmark execution time: 2026-03-24 11:40:01 Comparing candidate commit 8a21358 in PR branch Found 7 performance improvements and 9 performance regressions! Performance is the same for 257 metrics, 15 unstable metrics.
|
…replacement
Introduces a new opt-in approach (DD_TRACE_OTEL_ACTIVITY_INTERCEPTION_ENABLED=true)
that intercepts System.Diagnostics.Activity methods via CallTarget instead of using
the managed ActivityListener. Goals: reduce memory usage by eliminating Activity's
internal tag storage duplication and the ConcurrentDictionary span lookup.
New CallTarget integrations:
- ActivityStartIntegration: intercepts Activity.Start() to create a Span and link
it to the Activity via GetCustomProperty/SetCustomProperty ('__dd_span__' key)
- ActivityStopIntegration: intercepts Activity.Stop() to finish the Span with
correct timing, extracting links/events/status at stop time
- ActivityAddTagStringIntegration: intercepts AddTag(string, string?) to write
directly to the Span and skip Activity's internal tag list
- ActivityAddTagObjectIntegration: intercepts AddTag(string, object?) similarly
- ActivitySetTagIntegration: intercepts SetTag(string, object?) similarly
- ActivitySetStatusIntegration: intercepts SetStatus() to map OTel status to
Datadog error tags, bypassing Activity's internal status field
- ActivityDisplayNameIntegration: intercepts set_DisplayName to set Span.ResourceName
Supporting infrastructure:
- ActivityCustomPropertyAccessor<TTarget>: zero-allocation cached delegates for
reading/writing the Scope via Activity's custom property API
- ActivitySourceFilter: shared filter for source names already handled by other
Datadog integrations (mirrors IgnoreActivityHandler.SourcesNames)
Configuration changes:
- Added DD_TRACE_OTEL_ACTIVITY_INTERCEPTION_ENABLED feature flag to TracerSettings,
supported-configurations.yaml, and generated ConfigurationKeys
- Instrumentation.cs: skips managed ActivityListener when interception is enabled
- MutableSettings.cs: keeps OpenTelemetry integration enabled under either mode
Other changes:
- IActivity5: added GetCustomProperty/SetCustomProperty to the duck type interface
- OtlpHelpers: added ExtractLinksAndEventsFromActivity helper for stop integration
- ResourceAttributeProcessorHelper: uses custom property lookup when interception
is enabled, falling back to ConcurrentDictionary for the legacy listener path
All integrations registered in InstrumentationDefinitions.g.cs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 1 — Fix IsAllDataRequested: ActivityStartIntegration.CreateAndLinkScope now sets activity5.IsAllDataRequested = true after linking the Span. The managed ActivityListener did this implicitly via its Sample callback returning AllData; since we skip the listener when interception is enabled, we must set it explicitly so user code guarded by `if (activity.IsAllDataRequested)` runs. Phase 2 — Getter interceptions (redirect reads to the Span): The setter integrations use skipMethodBody to bypass Activity's internal storage, which means reading from the Activity would return stale/empty values. Five new getter integrations restore correct observable state by reading from the linked Span: - ActivityDisplayNameGetterIntegration: get_DisplayName → span.ResourceName ?? span.OperationName - ActivityStatusGetterIntegration: get_Status → ActivityStatusCode reconstructed from span's "otel.status_code" tag (Enum.ToObject handles the foreign enum conversion) - ActivityStatusDescriptionGetterIntegration: get_StatusDescription → span's "otel.status_description" tag - ActivityTagsGetterIntegration: get_Tags → all span string tags enumerated via ITags.EnumerateTags into List<KVP<string,string?>> - ActivityTagObjectsGetterIntegration: get_TagObjects → same but boxed as object?, matching Activity.TagObjects' IEnumerable<KVP<string,object?>> contract Note on TagObjects: numeric tags set via SetMetric are not reflected since the Span stores them separately from string tags. This is an acceptable R&D limitation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add the 5 new Activity getter integration classes to the GetIntegrationId switch in the generated InstrumentationDefinitions file so they are correctly mapped to IntegrationId.OpenTelemetry at runtime. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add SubmitsTracesWithInterception to both NetActivitySdkTests and OpenTelemetrySdkTests. Each variant enables DD_TRACE_OTEL_ACTIVITY_INTERCEPTION_ENABLED instead of DD_TRACE_OTEL_ENABLED and shares the same snapshot file as the existing SubmitsTraces test, asserting that the CallTarget-based interception approach produces output identical to the managed ActivityListener approach. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8a21358 to
b35deb9
Compare
Summary of changes
Reason for change
Implementation details
Test coverage
Other details