Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sdk/resource: honor OTEL_SERVICE_NAME in fromEnv resource detector #1969

Merged
merged 3 commits into from Jun 4, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -33,6 +33,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
This method returns the number of list-members the `TraceState` holds. (#1937)
- Creates package `go.opentelemetry.io/otel/exporters/otlp/otlptrace` that defines a trace exporter that uses a `otlptrace.Client` to send data.
Creates package `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc` implementing a gRPC `otlptrace.Client` and offers convenience functions, `NewExportPipeline` and `InstallNewPipeline`, to setup and install a `otlptrace.Exporter` in tracing .(#1922)
- The `OTEL_SERVICE_NAME` environment variable is the preferred source for `service.name`, used by the environment resource detector if a service name is present both there and in `OTEL_RESOURCE_ATTRIBUTES`. (#1969)

### Changed

Expand Down
32 changes: 24 additions & 8 deletions sdk/resource/env.go
Expand Up @@ -21,10 +21,16 @@ import (
"strings"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/semconv"
)

// envVar is the environment variable name OpenTelemetry Resource information can be assigned to.
const envVar = "OTEL_RESOURCE_ATTRIBUTES"
const (
// resourceAttrKey is the environment variable name OpenTelemetry Resource information will be read from.
resourceAttrKey = "OTEL_RESOURCE_ATTRIBUTES"

// svcNameKey is the environment variable name that Service Name information will be read from.
svcNameKey = "OTEL_SERVICE_NAME"
)

var (
// errMissingValue is returned when a resource value is missing.
Expand All @@ -33,22 +39,32 @@ var (

// fromEnv is a Detector that implements the Detector and collects
// resources from environment. This Detector is included as a
// builtin. If these resource attributes are not wanted, use the
// WithFromEnv(nil) or WithoutBuiltin() options to explicitly disable
// them.
// builtin.
type fromEnv struct{}

// compile time assertion that FromEnv implements Detector interface
var _ Detector = fromEnv{}

// Detect collects resources from environment
func (fromEnv) Detect(context.Context) (*Resource, error) {
attrs := strings.TrimSpace(os.Getenv(envVar))
attrs := strings.TrimSpace(os.Getenv(resourceAttrKey))
svcName := strings.TrimSpace(os.Getenv(svcNameKey))

if attrs == "" {
if attrs == "" && svcName == "" {
return Empty(), nil
}
return constructOTResources(attrs)

var res *Resource

if svcName != "" {
res = NewWithAttributes(semconv.ServiceNameKey.String(svcName))
}

r2, err := constructOTResources(attrs)

// Ensure that the resource with the service name from OTEL_SERVICE_NAME
// takes precedence, if it was defined.
return Merge(r2, res), err
}

func constructOTResources(s string) (*Resource, error) {
Expand Down
28 changes: 23 additions & 5 deletions sdk/resource/env_test.go
Expand Up @@ -24,11 +24,12 @@ import (

"go.opentelemetry.io/otel/attribute"
ottest "go.opentelemetry.io/otel/internal/internaltest"
"go.opentelemetry.io/otel/semconv"
)

func TestDetectOnePair(t *testing.T) {
store, err := ottest.SetEnvVariables(map[string]string{
envVar: "key=value",
resourceAttrKey: "key=value",
})
require.NoError(t, err)
defer func() { require.NoError(t, store.Restore()) }()
Expand All @@ -41,8 +42,8 @@ func TestDetectOnePair(t *testing.T) {

func TestDetectMultiPairs(t *testing.T) {
store, err := ottest.SetEnvVariables(map[string]string{
"x": "1",
envVar: "key=value, k = v , a= x, a=z",
"x": "1",
resourceAttrKey: "key=value, k = v , a= x, a=z",
})
require.NoError(t, err)
defer func() { require.NoError(t, store.Restore()) }()
Expand All @@ -60,7 +61,7 @@ func TestDetectMultiPairs(t *testing.T) {

func TestEmpty(t *testing.T) {
store, err := ottest.SetEnvVariables(map[string]string{
envVar: " ",
resourceAttrKey: " ",
})
require.NoError(t, err)
defer func() { require.NoError(t, store.Restore()) }()
Expand All @@ -73,7 +74,7 @@ func TestEmpty(t *testing.T) {

func TestMissingKeyError(t *testing.T) {
store, err := ottest.SetEnvVariables(map[string]string{
envVar: "key=value,key",
resourceAttrKey: "key=value,key",
})
require.NoError(t, err)
defer func() { require.NoError(t, store.Restore()) }()
Expand All @@ -86,3 +87,20 @@ func TestMissingKeyError(t *testing.T) {
attribute.String("key", "value"),
))
}

func TestDetectServiceNameFromEnv(t *testing.T) {
store, err := ottest.SetEnvVariables(map[string]string{
resourceAttrKey: "key=value,service.name=foo",
svcNameKey: "bar",
})
require.NoError(t, err)
defer func() { require.NoError(t, store.Restore()) }()

detector := &fromEnv{}
res, err := detector.Detect(context.Background())
require.NoError(t, err)
assert.Equal(t, res, NewWithAttributes(
attribute.String("key", "value"),
semconv.ServiceNameKey.String("bar"),
))
}