Skip to content

Commit dc79c61

Browse files
khanayan123claude
andcommitted
feat: add DD-Session-ID and DD-Root-Session-ID telemetry headers
Implements the Stable Service Instance Identifier RFC for .NET telemetry. - DD-Session-ID (= runtime_id) added to every telemetry request - DD-Root-Session-ID added only when the process inherited _DD_ROOT_DOTNET_SESSION_ID from a parent (child process scenario) - Root session ID auto-propagates to child processes via Environment.SetEnvironmentVariable() - _DD_ROOT_DOTNET_SESSION_ID registered in supported-configurations.yaml as ConfigurationKeys.Telemetry.RootSessionId Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6f4edac commit dc79c61

File tree

12 files changed

+97
-3
lines changed

12 files changed

+97
-3
lines changed

tracer/src/Datadog.Trace/Configuration/supported-configurations.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,15 @@ supportedConfigurations:
15711571
documentation: |-
15721572
Configuration key for whether telemetry metrics should be sent.
15731573
<see cref="Datadog.Trace.Telemetry.TelemetrySettings.MetricsEnabled"/>
1574+
_DD_ROOT_DOTNET_SESSION_ID:
1575+
- implementation: A
1576+
type: string
1577+
default: null
1578+
product: Telemetry
1579+
const_name: RootSessionId
1580+
documentation: |-
1581+
Internal env var for propagating the root session ID to child processes.
1582+
Set automatically by the tracer at init time; not user-configurable.
15741583
DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES:
15751584
- implementation: A
15761585
type: int

tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/ConfigurationKeysGenerator/ConfigurationKeys.Telemetry.g.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ internal static partial class ConfigurationKeys
1717
{
1818
internal static class Telemetry
1919
{
20+
/// <summary>
21+
/// Internal env var for propagating the root session ID to child processes.
22+
/// Set automatically by the tracer at init time; not user-configurable.
23+
/// </summary>
24+
public const string RootSessionId = "_DD_ROOT_DOTNET_SESSION_ID";
25+
2026
/// <summary>
2127
/// SSI variable that provides a unique identifier for the instrumentation installation.
2228
/// Used for tracking and correlation purposes in telemetry.

tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/ConfigurationKeysGenerator/ConfigurationKeys.Telemetry.g.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ internal static partial class ConfigurationKeys
1717
{
1818
internal static class Telemetry
1919
{
20+
/// <summary>
21+
/// Internal env var for propagating the root session ID to child processes.
22+
/// Set automatically by the tracer at init time; not user-configurable.
23+
/// </summary>
24+
public const string RootSessionId = "_DD_ROOT_DOTNET_SESSION_ID";
25+
2026
/// <summary>
2127
/// SSI variable that provides a unique identifier for the instrumentation installation.
2228
/// Used for tracking and correlation purposes in telemetry.

tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/ConfigurationKeysGenerator/ConfigurationKeys.Telemetry.g.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ internal static partial class ConfigurationKeys
1717
{
1818
internal static class Telemetry
1919
{
20+
/// <summary>
21+
/// Internal env var for propagating the root session ID to child processes.
22+
/// Set automatically by the tracer at init time; not user-configurable.
23+
/// </summary>
24+
public const string RootSessionId = "_DD_ROOT_DOTNET_SESSION_ID";
25+
2026
/// <summary>
2127
/// SSI variable that provides a unique identifier for the instrumentation installation.
2228
/// Used for tracking and correlation purposes in telemetry.

tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/ConfigurationKeysGenerator/ConfigurationKeys.Telemetry.g.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ internal static partial class ConfigurationKeys
1717
{
1818
internal static class Telemetry
1919
{
20+
/// <summary>
21+
/// Internal env var for propagating the root session ID to child processes.
22+
/// Set automatically by the tracer at init time; not user-configurable.
23+
/// </summary>
24+
public const string RootSessionId = "_DD_ROOT_DOTNET_SESSION_ID";
25+
2026
/// <summary>
2127
/// SSI variable that provides a unique identifier for the instrumentation installation.
2228
/// Used for tracking and correlation purposes in telemetry.

tracer/src/Datadog.Trace/Telemetry/TelemetryConstants.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ internal static class TelemetryConstants
2121
public const string ClientLibraryLanguageHeader = "DD-Client-Library-Language";
2222
public const string ClientLibraryVersionHeader = "DD-Client-Library-Version";
2323

24+
public const string SessionIdHeader = "DD-Session-ID";
25+
public const string RootSessionIdHeader = "DD-Root-Session-ID";
26+
2427
public const string CloudProviderHeader = "DD-Cloud-Provider";
2528
public const string CloudResourceTypeHeader = "DD-Cloud-Resource-Type";
2629
public const string CloudResourceIdentifierHeader = "DD-Cloud-Resource-Identifier";

tracer/src/Datadog.Trace/Telemetry/Transports/JsonTelemetryTransport.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Datadog.Trace.Logging;
1414
using Datadog.Trace.PlatformHelpers;
1515
using Datadog.Trace.Telemetry.Metrics;
16+
using Datadog.Trace.Util;
1617
using Datadog.Trace.Util.Http;
1718
using Datadog.Trace.Vendors.Newtonsoft.Json;
1819
using Datadog.Trace.Vendors.Newtonsoft.Json.Serialization;
@@ -56,6 +57,14 @@ public async Task<TelemetryPushResult> PushTelemetry(TelemetryData data)
5657
request.AddHeader(TelemetryConstants.DebugHeader, "true");
5758
}
5859

60+
var sessionId = RuntimeId.Get();
61+
request.AddHeader(TelemetryConstants.SessionIdHeader, sessionId);
62+
var rootSessionId = RuntimeId.GetRootSessionId();
63+
if (rootSessionId != sessionId)
64+
{
65+
request.AddHeader(TelemetryConstants.RootSessionIdHeader, rootSessionId);
66+
}
67+
5968
request.AddContainerMetadataHeaders(_containerMetadata);
6069

6170
TelemetryFactory.Metrics.RecordCountTelemetryApiRequests(endpointMetricTag);

tracer/src/Datadog.Trace/Util/RuntimeId.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using System;
77
using System.Threading;
8+
using Datadog.Trace.Configuration;
89
using Datadog.Trace.Logging;
910

1011
namespace Datadog.Trace.Util
@@ -13,10 +14,13 @@ internal static class RuntimeId
1314
{
1415
private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor(typeof(RuntimeId));
1516
private static string _runtimeId;
17+
private static string _rootSessionId;
1618

17-
public static string Get() => LazyInitializer.EnsureInitialized(ref _runtimeId, () => GetImpl());
19+
public static string Get() => LazyInitializer.EnsureInitialized(ref _runtimeId, () => GetRuntimeIdImpl());
1820

19-
private static string GetImpl()
21+
public static string GetRootSessionId() => LazyInitializer.EnsureInitialized(ref _rootSessionId, () => GetRootSessionIdImpl());
22+
23+
private static string GetRuntimeIdImpl()
2024
{
2125
if (NativeLoader.TryGetRuntimeIdFromNative(out var runtimeId))
2226
{
@@ -29,5 +33,19 @@ private static string GetImpl()
2933

3034
return guid;
3135
}
36+
37+
private static string GetRootSessionIdImpl()
38+
{
39+
var inherited = EnvironmentHelpers.GetEnvironmentVariable(ConfigurationKeys.Telemetry.RootSessionId);
40+
if (!string.IsNullOrEmpty(inherited))
41+
{
42+
Log.Debug("Inherited root session ID from parent: {RootSessionId}", inherited);
43+
return inherited;
44+
}
45+
46+
var rootId = Get();
47+
EnvironmentHelpers.SetEnvironmentVariable(ConfigurationKeys.Telemetry.RootSessionId, rootId);
48+
return rootId;
49+
}
3250
}
3351
}

tracer/test/Datadog.Trace.IntegrationTests/TelemetryTransportTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Datadog.Trace.Telemetry;
1515
using Datadog.Trace.Telemetry.Transports;
1616
using Datadog.Trace.TestHelpers;
17+
using Datadog.Trace.Util;
1718
using FluentAssertions;
1819
using FluentAssertions.Execution;
1920
using Xunit;
@@ -116,6 +117,12 @@ public async Task SetsRequiredHeaders(bool agentless, bool useCloudAgentless)
116117
{ "DD-Client-Library-Version", TracerConstants.AssemblyVersion },
117118
};
118119

120+
// DD-Session-ID is always present and equals the runtime ID
121+
allExpected.Add(TelemetryConstants.SessionIdHeader, RuntimeId.Get());
122+
123+
// DD-Root-Session-ID is absent when rootSessionId == runtimeId (normal process)
124+
// We can't assert absence in the loop below, so we check it separately after
125+
119126
if (ContainerMetadata.Instance.ContainerId is { } containerId)
120127
{
121128
allExpected.Add(AgentHttpHeaderNames.ContainerId, containerId);
@@ -149,6 +156,12 @@ public async Task SetsRequiredHeaders(bool agentless, bool useCloudAgentless)
149156
}
150157
}
151158

159+
// DD-Root-Session-ID should be absent in a normal (non-child) process
160+
if (RuntimeId.GetRootSessionId() == RuntimeId.Get())
161+
{
162+
headers.AllKeys.Should().NotContain(TelemetryConstants.RootSessionIdHeader);
163+
}
164+
152165
// should have either content-length or chunked encoding
153166
headers.AllKeys.Should()
154167
.Contain(s => s.Equals("Content-Type", StringComparison.OrdinalIgnoreCase)

tracer/test/Datadog.Trace.Tests/Telemetry/ConfigurationTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class ConfigurationTests
5252
"DD_CIVISIBILITY_CODE_COVERAGE_MODE",
5353
"DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER",
5454
// Internal env vars that we only ever read from environment
55+
"_DD_ROOT_DOTNET_SESSION_ID",
5556
"DD_INTERNAL_TRACE_NATIVE_ENGINE_PATH",
5657
"DD_INTERNAL_PROFILING_NATIVE_ENGINE_PATH",
5758
"DD_DOTNET_TRACER_HOME",

0 commit comments

Comments
 (0)