diff --git a/CHANGELOG.md b/CHANGELOG.md index dbe91d2797e..1dbd7f1aca5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - The following struct types moved and are replaced with type aliases, since they are exposed to the user: `Observation`, `Measurement`. - The No-op implementations of sync and async instruments are no longer exported, new functions `sdkapi.NewNoopAsyncInstrument()` and `sdkapi.NewNoopSyncInstrument()` are provided instead. (#2271) - Update the SDK `BatchSpanProcessor` to export all queued spans when `ForceFlush` is called. (#2080, #2335) +- Change `resource.Default` to be evaluated the first time it is called, rather than on import. This allows the caller the option to update `OTEL_RESOURCE_ATTRIBUTES` first, such as with `os.Setenv`. (#2371) ### Added diff --git a/sdk/resource/resource.go b/sdk/resource/resource.go index 6bb2a2805aa..eb0ecd2cf91 100644 --- a/sdk/resource/resource.go +++ b/sdk/resource/resource.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "sync" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -36,26 +37,12 @@ type Resource struct { } var ( - emptyResource Resource - - defaultResource = func(r *Resource, err error) *Resource { - if err != nil { - otel.Handle(err) - } - return r - }( - Detect( - context.Background(), - defaultServiceNameDetector{}, - fromEnv{}, - telemetrySDK{}, - ), - ) + emptyResource Resource + defaultResource *Resource + defaultResourceOnce sync.Once ) -var ( - errMergeConflictSchemaURL = errors.New("cannot merge resource due to conflicting Schema URL") -) +var errMergeConflictSchemaURL = errors.New("cannot merge resource due to conflicting Schema URL") // New returns a Resource combined from the user-provided detectors. func New(ctx context.Context, opts ...Option) (*Resource, error) { @@ -211,6 +198,22 @@ func Empty() *Resource { // Default returns an instance of Resource with a default // "service.name" and OpenTelemetrySDK attributes. func Default() *Resource { + defaultResourceOnce.Do(func() { + var err error + defaultResource, err = Detect( + context.Background(), + defaultServiceNameDetector{}, + fromEnv{}, + telemetrySDK{}, + ) + if err != nil { + otel.Handle(err) + } + // If Detect did not return a valid resource, fall back to emptyResource. + if defaultResource == nil { + defaultResource = &emptyResource + } + }) return defaultResource }