Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ac471d9
Implement automatic instrumentation for OpenTelemetry Baggage, so tha…
zacharycmontoya Dec 2, 2025
d496e9f
Fix OpenTelemetry baggage interop. When the user calls the static Ope…
zacharycmontoya Feb 3, 2026
b52ef06
Add support for remaining static API methods:
zacharycmontoya Feb 4, 2026
3cda30c
Add snapshot tests for new AspNetCoreMinimalApisTests.OtelBaggageApiI…
zacharycmontoya Feb 5, 2026
6dc4e28
Optimization 1: In static OpenTelemetry.Baggage API calls, only updat…
zacharycmontoya Feb 5, 2026
61edb29
Update SetCurrent comments
zacharycmontoya Feb 5, 2026
7d6fce8
Merge branch 'master' into zach.montoya/otel-baggage-sync-APMAPI-1736
zacharycmontoya Feb 19, 2026
7993bf7
PR Feedback: Remove unnecessary code comments on OnMethodBegin / OnMe…
zacharycmontoya Mar 10, 2026
acfc98d
PR Feedback: Inline the IntegrationName into the InstrumentMethod att…
zacharycmontoya Mar 10, 2026
ae367aa
PR Feedback: Add 'exception is null' conditional to all of the OnMeth…
zacharycmontoya Mar 10, 2026
e9ef733
PR Feedback: Add links to the baggage implementation types
zacharycmontoya Mar 10, 2026
7a603e1
PR Feedback: Refactor OnMethodBegin methods to all use the 'TBaggage …
zacharycmontoya Mar 10, 2026
5d067d8
PR Feedback: Simplify duck typing for OpenTelemetry.Baggage.get_Curre…
zacharycmontoya Mar 10, 2026
4cf6920
Update OTel Baggage API integration to test to omit the 'otel-baggage…
zacharycmontoya Mar 11, 2026
6513124
Make the OTelBaggage_SetCurrentIntegration, more resilient by only up…
zacharycmontoya Mar 12, 2026
af30626
Add Datadog.Trace.Baggage.AsDictionary() method for getting the exist…
zacharycmontoya Mar 12, 2026
64ea7e4
Fix issue in TypeNameTests
zacharycmontoya Mar 12, 2026
f8b5443
Merge branch 'master' into zach.montoya/otel-baggage-sync-APMAPI-1736
zacharycmontoya Mar 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions tracer/build/supported_calltargets.g.json
Original file line number Diff line number Diff line change
Expand Up @@ -13771,6 +13771,152 @@
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "OpenTelemetry",
"AssemblyName": "OpenTelemetry.Api",
"TargetTypeName": "OpenTelemetry.Baggage",
"TargetMethodName": "ClearBaggage",
"TargetReturnType": "OpenTelemetry.Baggage",
"TargetParameterTypes": [
"OpenTelemetry.Baggage"
],
"MinimumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.OpenTelemetry.OTelBaggage_ClearBaggageIntegration",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "OpenTelemetry",
"AssemblyName": "OpenTelemetry.Api",
"TargetTypeName": "OpenTelemetry.Baggage",
"TargetMethodName": "get_Current",
"TargetReturnType": "OpenTelemetry.Baggage",
"TargetParameterTypes": [],
"MinimumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.OpenTelemetry.OTelBaggage_GetCurrentIntegration",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "OpenTelemetry",
"AssemblyName": "OpenTelemetry.Api",
"TargetTypeName": "OpenTelemetry.Baggage",
"TargetMethodName": "RemoveBaggage",
"TargetReturnType": "OpenTelemetry.Baggage",
"TargetParameterTypes": [
"System.String",
"OpenTelemetry.Baggage"
],
"MinimumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.OpenTelemetry.OTelBaggage_RemoveBaggageIntegration",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "OpenTelemetry",
"AssemblyName": "OpenTelemetry.Api",
"TargetTypeName": "OpenTelemetry.Baggage",
"TargetMethodName": "set_Current",
"TargetReturnType": "System.Void",
"TargetParameterTypes": [
"OpenTelemetry.Baggage"
],
"MinimumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.OpenTelemetry.OTelBaggage_SetCurrentIntegration",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "OpenTelemetry",
"AssemblyName": "OpenTelemetry.Api",
"TargetTypeName": "OpenTelemetry.Baggage",
"TargetMethodName": "SetBaggage",
"TargetReturnType": "OpenTelemetry.Baggage",
"TargetParameterTypes": [
"System.String",
"System.String",
"OpenTelemetry.Baggage"
],
"MinimumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.OpenTelemetry.OTelBaggage_SetBaggageIntegration",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "OpenTelemetry",
"AssemblyName": "OpenTelemetry.Api",
"TargetTypeName": "OpenTelemetry.Baggage",
"TargetMethodName": "SetBaggage",
"TargetReturnType": "OpenTelemetry.Baggage",
"TargetParameterTypes": [
"System.Collections.Generic.IEnumerable`1[System.Collections.Generic.KeyValuePair`2[System.String,System.String]]",
"OpenTelemetry.Baggage"
],
"MinimumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"MaximumVersion": {
"Item1": 1,
"Item2": 0,
"Item3": 0
},
"InstrumentationTypeName": "Datadog.Trace.ClrProfiler.AutoInstrumentation.OpenTelemetry.OTelBaggage_SetBaggageItemsIntegration",
"IntegrationKind": 0,
"IsAdoNetIntegration": false,
"InstrumentationCategory": 1
},
{
"IntegrationName": "OpenTelemetry",
"AssemblyName": "OpenTelemetry.Api",
Expand Down
24 changes: 23 additions & 1 deletion tracer/src/Datadog.Trace/Baggage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using Datadog.Trace.Util;
Expand Down Expand Up @@ -368,6 +369,27 @@ public void Clear()
}
}

/// <summary>
/// Converts the baggage items to a new dictionary.
/// </summary>
/// <returns>A dictionary of the baggage items, or an empty dictionary if there are no items.</returns>
public Dictionary<string, string?> AsDictionary()
{
if (_items is { } items)
{
lock (items)
{
#if NETCOREAPP3_1_OR_GREATER
return new(items);
#else
return new Dictionary<string, string?>(items.ToDictionary(kvp => kvp.Key, kvp => kvp.Value));
#endif
}
}

return [];
}

/// <summary>
/// Adds the baggage items from this baggage instance into <paramref name="destination"/>.
/// </summary>
Expand Down Expand Up @@ -446,7 +468,7 @@ public void Enumerate<T>(T processor)
}
}

private List<KeyValuePair<string, string?>>.Enumerator GetEnumerator() => _items?.GetEnumerator() ?? EmptyList.GetEnumerator();
public List<KeyValuePair<string, string?>>.Enumerator GetEnumerator() => _items?.GetEnumerator() ?? EmptyList.GetEnumerator();

IEnumerator<KeyValuePair<string, string?>> IEnumerable<KeyValuePair<string, string?>>.GetEnumerator() => GetEnumerator();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// <copyright file="IApiBaggage.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

using System.Collections.Generic;
using Datadog.Trace.DuckTyping;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.OpenTelemetry
{
/// <summary>
/// OpenTelemetry.Baggage interface for duck-typing
/// https://github.com/open-telemetry/opentelemetry-dotnet/blob/db429bf642c1a2c2f71b49f88d63e0a661018298/src/OpenTelemetry.Api/Baggage.cs#L16
/// </summary>
internal interface IApiBaggage
{
[DuckField(Name = "baggage")]
Dictionary<string, string> Baggage { get; }

IApiBaggage Create(Dictionary<string, string?>? baggageItems);

IReadOnlyDictionary<string, string?> GetBaggage();

string? GetBaggage(string name);

IBaggageHolder EnsureBaggageHolder();
}

/// <summary>
/// Baggage holder interface for duck-typing
/// https://github.com/open-telemetry/opentelemetry-dotnet/blob/db429bf642c1a2c2f71b49f88d63e0a661018298/src/OpenTelemetry.Api/Baggage.cs#L371
/// </summary>
internal interface IBaggageHolder
{
[DuckField(Name = "Baggage")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMG the casing inconsistency in this code base 😅

IApiBaggage Baggage { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// <copyright file="OTelBaggage_ClearBaggageIntegration.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

using System;
using System.ComponentModel;
using Datadog.Trace;
using Datadog.Trace.ClrProfiler.CallTarget;
using Datadog.Trace.Configuration;
using Datadog.Trace.DuckTyping;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.OpenTelemetry
{
/// <summary>
/// OpenTelemetry.Api Baggage.ClearBaggage calltarget instrumentation
/// </summary>
[InstrumentMethod(
AssemblyName = "OpenTelemetry.Api",
TypeName = "OpenTelemetry.Baggage",
MethodName = "ClearBaggage",
ReturnTypeName = "OpenTelemetry.Baggage",
ParameterTypeNames = new[] { "OpenTelemetry.Baggage" },
MinimumVersion = "1.0.0",
MaximumVersion = "1.0.0",
IntegrationName = nameof(Configuration.IntegrationId.OpenTelemetry))]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class OTelBaggage_ClearBaggageIntegration
{
internal const IntegrationId IntegrationId = Configuration.IntegrationId.OpenTelemetry;

internal static CallTargetReturn<TReturn> OnMethodEnd<TTarget, TReturn>(TTarget instance, TReturn returnValue, Exception exception, in CallTargetState state)
{
if (Tracer.Instance.CurrentTraceSettings.Settings.IsIntegrationEnabled(IntegrationId)
&& exception is null)
{
// Important: Before returning to the caller, the static OpenTelemetry.Baggage APIs set the to-be-returned baggage object as OpenTelemetry.Baggage.Current.
// However, this is not done through the public setter (which we instrument), but through the backing field, so we must manually update Datadog.Trace.Baggage.Current
// so it remains in-sync.
Baggage.Current.Clear();
}

return new CallTargetReturn<TReturn>(returnValue);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// <copyright file="OTelBaggage_GetCurrentIntegration.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

using System;
using System.ComponentModel;
using Datadog.Trace;
using Datadog.Trace.ClrProfiler.CallTarget;
using Datadog.Trace.Configuration;
using Datadog.Trace.DuckTyping;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.OpenTelemetry
{
/// <summary>
/// OpenTelemetry.Api Baggage.get_Current calltarget instrumentation
/// </summary>
[InstrumentMethod(
AssemblyName = "OpenTelemetry.Api",
TypeName = "OpenTelemetry.Baggage",
MethodName = "get_Current",
ReturnTypeName = "OpenTelemetry.Baggage",
ParameterTypeNames = new string[0],
MinimumVersion = "1.0.0",
MaximumVersion = "1.0.0",
IntegrationName = nameof(Configuration.IntegrationId.OpenTelemetry))]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class OTelBaggage_GetCurrentIntegration
{
internal const IntegrationId IntegrationId = Configuration.IntegrationId.OpenTelemetry;

internal static CallTargetState OnMethodBegin<TInstance>(TInstance apiBaggage)
where TInstance : IApiBaggage
{
if (Tracer.Instance.CurrentTraceSettings.Settings.IsIntegrationEnabled(IntegrationId))
{
// Since Datadog.Trace.Baggage.Current may have been updated since the last time OpenTelemetry.Baggage.Current was accessed,
// we must update the underlying OpenTelemetry.Baggage.Current store with the latest Datadog.Trace.Baggage.Current items.
// Note: When the user sets OpenTelemetry.Baggage.Current, those changes will override the contents of Datadog.Trace.Baggage.Current,
// so we can always consider Datadog.Trace.Baggage.Current as being up-to-date.
var baggageHolder = apiBaggage.EnsureBaggageHolder();
baggageHolder.Baggage = apiBaggage.Create(Baggage.Current.AsDictionary());
}

return CallTargetState.GetDefault();
}
}
}
Loading
Loading