Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion tracer/src/Datadog.Trace/Activity/OtlpHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ private static void AgentConvertSpan<TInner>(TInner activity, Span span, bool op
// Fixup "env" tag
if (traceContext is not null
&& traceContext.Environment is null
&& span.GetTag("deployment.environment") is { Length: > 0 } otelServiceEnv)
&& (span.GetTag("deployment.environment.name") ?? span.GetTag("deployment.environment")) is { Length: > 0 } otelServiceEnv)
{
traceContext.Environment = otelServiceEnv;
}
Expand Down
5 changes: 4 additions & 1 deletion tracer/src/Datadog.Trace/Configuration/MutableSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1107,8 +1107,11 @@ private static ConfigurationBuilder.ClassConfigurationResultWithKey<IDictionary<
if (original.ConfigurationResult is { IsValid: true, Result: { } values })
{
// Update well-known service information resources
if (values.TryGetValue("deployment.environment", out var envValue))
// an empty "deployment.environment.name" falls back to the legacy "deployment.environment"
if ((values.TryGetValue("deployment.environment.name", out var envValue) && !string.IsNullOrEmpty(envValue)) ||
values.TryGetValue("deployment.environment", out envValue))
{
values.Remove("deployment.environment.name");
values.Remove("deployment.environment");
values[Tags.Env] = envValue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,20 +652,75 @@ public void DDTagsSetsServiceInformation()
mutable.GitCommitSha.Should().Be("42");
}

[Fact]
public void OTELTagsSetsServiceInformation()
[Theory]
[InlineData("deployment.environment.name=stable_env", "stable_env")]
[InlineData("deployment.environment=legacy_env", "legacy_env")]
[InlineData("deployment.environment.name=stable_env,deployment.environment=legacy_env", "stable_env")]
[InlineData("deployment.environment=legacy_env,deployment.environment.name=stable_env", "stable_env")]
public void OTELTagsSetServiceInformation(string environmentAttributes, string expectedEnvironment)
{
var source = new NameValueConfigurationSource(new()
{
{ "OTEL_RESOURCE_ATTRIBUTES", "deployment.environment=datadog_env,service.name=datadog_service,service.version=datadog_version" },
{ ConfigurationKeys.OpenTelemetry.ResourceAttributes, $"{environmentAttributes},service.name=datadog_service,service.version=datadog_version,custom.attribute=custom_value" },
});

var tracerSettings = new TracerSettings(source);
var mutable = GetMutableSettings(source, tracerSettings);

mutable.Environment.Should().Be("datadog_env");
mutable.Environment.Should().Be(expectedEnvironment);
mutable.ServiceVersion.Should().Be("datadog_version");
mutable.ServiceName.Should().Be("datadog_service");
mutable.GlobalTags.Should().NotContainKey("deployment.environment.name");
mutable.GlobalTags.Should().NotContainKey("deployment.environment");
mutable.GlobalTags.Should().Contain("custom.attribute", "custom_value");
}

[Fact]
public void EmptyStableEnvironmentNameFallsBackToLegacyEnvironment()
{
var source = new NameValueConfigurationSource(new()
{
{ ConfigurationKeys.OpenTelemetry.ResourceAttributes, "deployment.environment.name=,deployment.environment=legacy_env" },
});

var tracerSettings = new TracerSettings(source);
var mutable = GetMutableSettings(source, tracerSettings);

mutable.Environment.Should().Be("legacy_env");
mutable.GlobalTags.Should().NotContainKey("deployment.environment.name");
mutable.GlobalTags.Should().NotContainKey("deployment.environment");
}

[Fact]
public void EmptyStableEnvironmentNameWithNoLegacyEnvironmentIsUnset()
{
var source = new NameValueConfigurationSource(new()
{
{ ConfigurationKeys.OpenTelemetry.ResourceAttributes, "deployment.environment.name=" },
});

var tracerSettings = new TracerSettings(source);
var mutable = GetMutableSettings(source, tracerSettings);

mutable.Environment.Should().BeNullOrEmpty();
mutable.GlobalTags.Should().NotContainKey("deployment.environment.name");
}

[Fact]
public void DDEnvTakesPrecedenceOverOTELTags()
{
var source = new NameValueConfigurationSource(new()
{
{ ConfigurationKeys.Environment, "datadog_env" },
{ ConfigurationKeys.OpenTelemetry.ResourceAttributes, "deployment.environment=legacy_env,deployment.environment.name=stable_env" },
});

var tracerSettings = new TracerSettings(source);
var mutable = GetMutableSettings(source, tracerSettings);

mutable.Environment.Should().Be("datadog_env");
mutable.GlobalTags.Should().NotContainKey("deployment.environment.name");
mutable.GlobalTags.Should().NotContainKey("deployment.environment");
}

[Fact]
Expand Down
42 changes: 42 additions & 0 deletions tracer/test/Datadog.Trace.Tests/Tagging/ActivityTagsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,46 @@ public async Task ActivityLink_PreservesTraceStateWithoutParsingOtelTraceState()
spanLinkContext.AdditionalW3CTraceState.Should().Be("ot=rv:ef284ace7a91e1;th:e6666666666668");
spanLinkContext.OtelTraceState.Should().BeNull();
}

[Theory]
[InlineData("deployment.environment.name", "stable_env")]
[InlineData("deployment.environment", "legacy_env")]
public async Task Environment_ShouldBe_FixedUpFromActivityTag(string tagKey, string tagValue)
{
var activityMock = new Mock<IActivity5>();
activityMock.Setup(x => x.Kind).Returns(ActivityKind.Producer);

var tagObjects = new Dictionary<string, object> { { tagKey, tagValue } };
activityMock.Setup(x => x.TagObjects).Returns(tagObjects);

// UpdateSpanFromActivity implicitly accesses Tracer.Instance if there's no associated Tracer in the span
await using var tracer = TracerHelper.CreateWithFakeAgent();
using var span = tracer.StartSpan("operation", new OpenTelemetryTags());

OtlpHelpers.UpdateSpanFromActivity(activityMock.Object, span);

span.Context.TraceContext!.Environment.Should().Be(tagValue);
}

[Fact]
public async Task Environment_StableTagName_ShouldTakePrecedenceOverLegacyTagName()
{
var activityMock = new Mock<IActivity5>();
activityMock.Setup(x => x.Kind).Returns(ActivityKind.Producer);

var tagObjects = new Dictionary<string, object>
{
{ "deployment.environment", "legacy_env" },
{ "deployment.environment.name", "stable_env" }
};
activityMock.Setup(x => x.TagObjects).Returns(tagObjects);

// UpdateSpanFromActivity implicitly accesses Tracer.Instance if there's no associated Tracer in the span
await using var tracer = TracerHelper.CreateWithFakeAgent();
using var span = tracer.StartSpan("operation", new OpenTelemetryTags());

OtlpHelpers.UpdateSpanFromActivity(activityMock.Object, span);

span.Context.TraceContext!.Environment.Should().Be("stable_env");
}
}
Loading