diff --git a/src/OpenTelemetry/CHANGELOG.md b/src/OpenTelemetry/CHANGELOG.md
index 89595afcbd8..1749e7c1a0f 100644
--- a/src/OpenTelemetry/CHANGELOG.md
+++ b/src/OpenTelemetry/CHANGELOG.md
@@ -2,6 +2,9 @@
## Unreleased
+* `ResourceBuilder.AddEnvironmentVariableDetector` handles `OTEL_SERVICE_NAME`
+ environmental variable. ([#2209](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2209))
+
* Removes upper constraint for Microsoft.Extensions.Logging
dependencies. ([#2179](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2179))
diff --git a/src/OpenTelemetry/README.md b/src/OpenTelemetry/README.md
index 94744f5cadc..33a840986a0 100644
--- a/src/OpenTelemetry/README.md
+++ b/src/OpenTelemetry/README.md
@@ -5,10 +5,10 @@
* [Installation](#installation)
* [Introduction](#introduction)
-* [Getting started with Logs](#getting-started-with-logging)
-* [Getting started with Traces](#getting-started-with-tracing)
-* [Tracing Configuration](#tracing-configuration)
- * [ActivitySource](#activity-source)
+* [Getting started with Logging](#getting-started-with-logging)
+* [Getting started with Tracing](#getting-started-with-tracing)
+* [Tracing configuration](#tracing-configuration)
+ * [Activity Source](#activity-source)
* [Instrumentation](#instrumentation)
* [Processor](#processor)
* [Resource](#resource)
@@ -16,6 +16,8 @@
* [Advanced topics](#advanced-topics)
* [Propagators](#propagators)
* [Troubleshooting](#troubleshooting)
+ * [Configuration Parameters](#configuration-parameters)
+ * [Remarks](#remarks)
* [References](#references)
## Installation
@@ -243,6 +245,16 @@ using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.Build();
```
+It is also possible to configure the `Resource` by using `AddEnvironmentVariableDetector`
+together with following environmental variables:
+
+
+| Environment variable | Description |
+| -------------------------- | -------------------------------------------------- |
+| `OTEL_RESOURCE_ATTRIBUTES` | Key-value pairs to be used as resource attributes. See the [Resource SDK specification](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.5.0/specification/resource/sdk.md#specifying-resource-information-via-an-environment-variable) for more details. |
+| `OTEL_SERVICE_NAME` | Sets the value of the `service.name` resource attribute. If `service.name` is also provided in `OTEL_RESOURCE_ATTRIBUTES`, then `OTEL_SERVICE_NAME` takes precedence. |
+
+
### Sampler
[Samplers](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#sampler)
diff --git a/src/OpenTelemetry/Resources/OtelEnvResourceDetector.cs b/src/OpenTelemetry/Resources/OtelEnvResourceDetector.cs
index 236762ad098..cd424e2d034 100644
--- a/src/OpenTelemetry/Resources/OtelEnvResourceDetector.cs
+++ b/src/OpenTelemetry/Resources/OtelEnvResourceDetector.cs
@@ -16,13 +16,14 @@
using System;
using System.Collections.Generic;
+using System.Security;
using OpenTelemetry.Internal;
namespace OpenTelemetry.Resources
{
internal class OtelEnvResourceDetector : IResourceDetector
{
- private const string OTelResourceEnvVarKey = "OTEL_RESOURCE_ATTRIBUTES";
+ public const string EnvVarKey = "OTEL_RESOURCE_ATTRIBUTES";
private const char AttributeListSplitter = ',';
private const char AttributeKeyValueSplitter = '=';
@@ -32,16 +33,16 @@ public Resource Detect()
try
{
- string envResourceAttributeValue = Environment.GetEnvironmentVariable(OTelResourceEnvVarKey);
+ string envResourceAttributeValue = Environment.GetEnvironmentVariable(EnvVarKey);
if (!string.IsNullOrEmpty(envResourceAttributeValue))
{
var attributes = ParseResourceAttributes(envResourceAttributeValue);
resource = new Resource(attributes);
}
}
- catch (Exception ex)
+ catch (SecurityException ex)
{
- OpenTelemetrySdkEventSource.Log.ResourceDetectorFailed("OtelEnvResourceDetector", ex.Message);
+ OpenTelemetrySdkEventSource.Log.ResourceDetectorFailed(nameof(OtelEnvResourceDetector), ex.Message);
}
return resource;
diff --git a/src/OpenTelemetry/Resources/OtelServiceNameEnvVarDetector.cs b/src/OpenTelemetry/Resources/OtelServiceNameEnvVarDetector.cs
new file mode 100644
index 00000000000..806ced7c793
--- /dev/null
+++ b/src/OpenTelemetry/Resources/OtelServiceNameEnvVarDetector.cs
@@ -0,0 +1,51 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Security;
+using OpenTelemetry.Internal;
+
+namespace OpenTelemetry.Resources
+{
+ internal class OtelServiceNameEnvVarDetector : IResourceDetector
+ {
+ public const string EnvVarKey = "OTEL_SERVICE_NAME";
+
+ public Resource Detect()
+ {
+ var resource = Resource.Empty;
+
+ try
+ {
+ string envResourceAttributeValue = Environment.GetEnvironmentVariable(EnvVarKey);
+ if (!string.IsNullOrEmpty(envResourceAttributeValue))
+ {
+ resource = new Resource(new Dictionary
+ {
+ [ResourceSemanticConventions.AttributeServiceName] = envResourceAttributeValue,
+ });
+ }
+ }
+ catch (SecurityException ex)
+ {
+ OpenTelemetrySdkEventSource.Log.ResourceDetectorFailed(nameof(OtelServiceNameEnvVarDetector), ex.Message);
+ }
+
+ return resource;
+ }
+ }
+}
diff --git a/src/OpenTelemetry/Resources/ResourceBuilderExtensions.cs b/src/OpenTelemetry/Resources/ResourceBuilderExtensions.cs
index 8eb500597da..9dd30fc1236 100644
--- a/src/OpenTelemetry/Resources/ResourceBuilderExtensions.cs
+++ b/src/OpenTelemetry/Resources/ResourceBuilderExtensions.cs
@@ -110,8 +110,8 @@ public static ResourceBuilder AddAttributes(this ResourceBuilder resourceBuilder
}
///
- /// Adds resource attributes parsed from an environment variable to a
- /// following the following the Resource
/// SDK.
///
@@ -119,7 +119,7 @@ public static ResourceBuilder AddAttributes(this ResourceBuilder resourceBuilder
/// Returns for chaining.
public static ResourceBuilder AddEnvironmentVariableDetector(this ResourceBuilder resourceBuilder)
{
- return resourceBuilder.AddDetector(new OtelEnvResourceDetector());
+ return resourceBuilder.AddDetector(new OtelEnvResourceDetector()).AddDetector(new OtelServiceNameEnvVarDetector());
}
private static string GetFileVersion()
diff --git a/test/OpenTelemetry.Tests/Resources/OtelEnvResourceDetectorTest.cs b/test/OpenTelemetry.Tests/Resources/OtelEnvResourceDetectorTest.cs
index 8ca21cdb0b9..dc1a8a376e2 100644
--- a/test/OpenTelemetry.Tests/Resources/OtelEnvResourceDetectorTest.cs
+++ b/test/OpenTelemetry.Tests/Resources/OtelEnvResourceDetectorTest.cs
@@ -22,11 +22,24 @@ namespace OpenTelemetry.Resources.Tests
{
public class OtelEnvResourceDetectorTest : IDisposable
{
- private const string OtelEnvVarKey = "OTEL_RESOURCE_ATTRIBUTES";
-
public OtelEnvResourceDetectorTest()
{
- Environment.SetEnvironmentVariable(OtelEnvVarKey, null);
+ Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, null);
+ }
+
+ public void Dispose()
+ {
+ Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, null);
+ }
+
+ [Fact]
+ public void OtelEnvResource_EnvVarKey()
+ {
+ // Act
+ var resource = new OtelServiceNameEnvVarDetector().Detect();
+
+ // Assert
+ Assert.Equal("OTEL_RESOURCE_ATTRIBUTES", OtelEnvResourceDetector.EnvVarKey);
}
[Fact]
@@ -44,7 +57,7 @@ public void OtelEnvResource_WithEnvVar_1()
{
// Arrange
var envVarValue = "Key1=Val1,Key2=Val2";
- Environment.SetEnvironmentVariable(OtelEnvVarKey, envVarValue);
+ Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, envVarValue);
var resource = new OtelEnvResourceDetector().Detect();
// Assert
@@ -57,7 +70,7 @@ public void OtelEnvResource_WithEnvVar_2()
{
// Arrange
var envVarValue = "Key1,Key2=Val2";
- Environment.SetEnvironmentVariable(OtelEnvVarKey, envVarValue);
+ Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, envVarValue);
var resource = new OtelEnvResourceDetector().Detect();
// Assert
@@ -65,10 +78,5 @@ public void OtelEnvResource_WithEnvVar_2()
Assert.Single(resource.Attributes);
Assert.Contains(new KeyValuePair("Key2", "Val2"), resource.Attributes);
}
-
- public void Dispose()
- {
- Environment.SetEnvironmentVariable(OtelEnvVarKey, null);
- }
}
}
diff --git a/test/OpenTelemetry.Tests/Resources/OtelServiceNameEnvVarDetectorTests.cs b/test/OpenTelemetry.Tests/Resources/OtelServiceNameEnvVarDetectorTests.cs
new file mode 100644
index 00000000000..27ef814c3af
--- /dev/null
+++ b/test/OpenTelemetry.Tests/Resources/OtelServiceNameEnvVarDetectorTests.cs
@@ -0,0 +1,70 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+using System;
+using System.Collections.Generic;
+using Xunit;
+
+namespace OpenTelemetry.Resources.Tests
+{
+ public class OtelServiceNameEnvVarDetectorTests : IDisposable
+ {
+ public OtelServiceNameEnvVarDetectorTests()
+ {
+ Environment.SetEnvironmentVariable(OtelServiceNameEnvVarDetector.EnvVarKey, null);
+ }
+
+ public void Dispose()
+ {
+ Environment.SetEnvironmentVariable(OtelServiceNameEnvVarDetector.EnvVarKey, null);
+ }
+
+ [Fact]
+ public void OtelServiceNameEnvVar_EnvVarKey()
+ {
+ // Act
+ var resource = new OtelServiceNameEnvVarDetector().Detect();
+
+ // Assert
+ Assert.Equal("OTEL_SERVICE_NAME", OtelServiceNameEnvVarDetector.EnvVarKey);
+ }
+
+ [Fact]
+ public void OtelServiceNameEnvVar_Null()
+ {
+ // Act
+ var resource = new OtelServiceNameEnvVarDetector().Detect();
+
+ // Assert
+ Assert.Equal(Resource.Empty, resource);
+ }
+
+ [Fact]
+ public void OtelServiceNameEnvVar_WithValue()
+ {
+ // Arrange
+ var envVarValue = "my-service";
+ Environment.SetEnvironmentVariable(OtelServiceNameEnvVarDetector.EnvVarKey, envVarValue);
+
+ // Act
+ var resource = new OtelServiceNameEnvVarDetector().Detect();
+
+ // Assert
+ Assert.NotEqual(Resource.Empty, resource);
+ Assert.Contains(new KeyValuePair(ResourceSemanticConventions.AttributeServiceName, envVarValue), resource.Attributes);
+ }
+ }
+}
diff --git a/test/OpenTelemetry.Tests/Resources/ResourceTest.cs b/test/OpenTelemetry.Tests/Resources/ResourceTest.cs
index 624d0c3f404..12288630a65 100644
--- a/test/OpenTelemetry.Tests/Resources/ResourceTest.cs
+++ b/test/OpenTelemetry.Tests/Resources/ResourceTest.cs
@@ -25,15 +25,19 @@ public class ResourceTest : IDisposable
{
private const string KeyName = "key";
private const string ValueName = "value";
- private const string OtelEnvVarKey = "OTEL_RESOURCE_ATTRIBUTES";
public ResourceTest()
{
- Environment.SetEnvironmentVariable(OtelEnvVarKey, null);
+ ClearEnvVars();
+ }
+
+ public void Dispose()
+ {
+ ClearEnvVars();
}
[Fact]
- public static void CreateResource_NullAttributeCollection()
+ public void CreateResource_NullAttributeCollection()
{
// Act and Assert
var resource = new Resource(null);
@@ -421,10 +425,10 @@ public void GetResourceWithDefaultAttributes_ResourceWithAttrs()
}
[Fact]
- public void GetResourceWithDefaultAttributes_WithEnvVar()
+ public void GetResourceWithDefaultAttributes_WithResourceEnvVar()
{
// Arrange
- Environment.SetEnvironmentVariable(OtelEnvVarKey, "EVKey1=EVVal1,EVKey2=EVVal2");
+ Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, "EVKey1=EVVal1,EVKey2=EVVal2");
var resource = ResourceBuilder.CreateDefault().AddEnvironmentVariableDetector().AddAttributes(this.CreateAttributes(2)).Build();
// Assert
@@ -436,9 +440,54 @@ public void GetResourceWithDefaultAttributes_WithEnvVar()
Assert.Contains(new KeyValuePair("EVKey2", "EVVal2"), attributes);
}
- public void Dispose()
+ [Fact]
+ public void GetResource_WithServiceEnvVar()
+ {
+ // Arrange
+ Environment.SetEnvironmentVariable(OtelServiceNameEnvVarDetector.EnvVarKey, "some-service");
+ var resource = ResourceBuilder.CreateDefault().AddEnvironmentVariableDetector().AddAttributes(this.CreateAttributes(2)).Build();
+
+ // Assert
+ var attributes = resource.Attributes;
+ Assert.Equal(3, attributes.Count());
+ ValidateAttributes(attributes, 0, 1);
+ Assert.Contains(new KeyValuePair("service.name", "some-service"), attributes);
+ }
+
+ [Fact]
+ public void GetResource_WithServiceNameSetWithTwoEnvVars()
+ {
+ // Arrange
+ Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, "service.name=from-resource-attr");
+ Environment.SetEnvironmentVariable(OtelServiceNameEnvVarDetector.EnvVarKey, "from-service-name");
+ var resource = ResourceBuilder.CreateDefault().AddEnvironmentVariableDetector().AddAttributes(this.CreateAttributes(2)).Build();
+
+ // Assert
+ var attributes = resource.Attributes;
+ Assert.Equal(3, attributes.Count());
+ ValidateAttributes(attributes, 0, 1);
+ Assert.Contains(new KeyValuePair("service.name", "from-service-name"), attributes);
+ }
+
+ [Fact]
+ public void GetResource_WithServiceNameSetWithTwoEnvVarsAndCode()
+ {
+ // Arrange
+ Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, "service.name=from-resource-attr");
+ Environment.SetEnvironmentVariable(OtelServiceNameEnvVarDetector.EnvVarKey, "from-service-name");
+ var resource = ResourceBuilder.CreateDefault().AddEnvironmentVariableDetector().AddService("from-code").AddAttributes(this.CreateAttributes(2)).Build();
+
+ // Assert
+ var attributes = resource.Attributes;
+ Assert.Equal(4, attributes.Count());
+ ValidateAttributes(attributes, 0, 1);
+ Assert.Contains(new KeyValuePair("service.name", "from-code"), attributes);
+ }
+
+ private static void ClearEnvVars()
{
- Environment.SetEnvironmentVariable(OtelEnvVarKey, null);
+ Environment.SetEnvironmentVariable(OtelEnvResourceDetector.EnvVarKey, null);
+ Environment.SetEnvironmentVariable(OtelServiceNameEnvVarDetector.EnvVarKey, null);
}
private static void AddAttributes(Dictionary attributes, int attributeCount, int startIndex = 0)