1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-03-05 15:05:51 +02:00

Fix default merging of resource attributes from environment variable (#1785)

* updated controller to merge default resource with environment resource

* updated TracerProvider to merge default resource with environment resource

* Added Changelog entry

* Added resource.Environment(), modified resource.Default() for environment vairable and WithResource() configuration for TracerProvider and Controller

* Update CHANGELOG.md

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>

* Moved environment detector to defaultResource initialization, added test cases

* Changes to default resource initialization

* made changes to the test cases

* added merging of resource with environment resource

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
This commit is contained in:
Dhruv Vora 2021-04-21 11:53:12 -07:00 committed by GitHub
parent 96c5e4baac
commit 0032bd6499
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 13 deletions

View File

@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Added
- - Extract resource attributes from the `OTEL_RESOURCE_ATTRIBUTES` environment variable and merge them with the `resource.Default` resource as well as resources provided to the `TracerProvider` and metric `Controller`. (#1785)
- Added Jaeger Environment variables: `OTEL_EXPORTER_JAEGER_AGENT_HOST`, `OTEL_EXPORTER_JAEGER_AGENT_PORT`
These environment variables can be used to override Jaeger agent hostname and port (#1752)
- The OTLP exporter now has two new convenience functions, `NewExportPipeline` and `InstallNewPipeline`, setup and install the exporter in tracing and metrics pipelines. (#1373)

View File

@ -64,9 +64,11 @@ type Option interface {
Apply(*Config)
}
// WithResource sets the Resource configuration option of a Config.
// WithResource sets the Resource configuration option of a Config by merging it
// with the Resource configuration in the environment.
func WithResource(r *resource.Resource) Option {
return resourceOption{r}
res := resource.Merge(resource.Environment(), r)
return resourceOption{res}
}
type resourceOption struct{ *resource.Resource }

View File

@ -24,6 +24,7 @@ import (
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
ottest "go.opentelemetry.io/otel/internal/internaltest"
"go.opentelemetry.io/otel/metric"
export "go.opentelemetry.io/otel/sdk/export/metric"
"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
@ -34,6 +35,8 @@ import (
"go.opentelemetry.io/otel/sdk/resource"
)
const envVar = "OTEL_RESOURCE_ATTRIBUTES"
func getMap(t *testing.T, cont *controller.Controller) map[string]float64 {
out := processortest.NewOutput(attribute.DefaultEncoder())
@ -58,6 +61,12 @@ func checkTestContext(t *testing.T, ctx context.Context) {
}
func TestControllerUsesResource(t *testing.T) {
store, err := ottest.SetEnvVariables(map[string]string{
envVar: "key=value,T=U",
})
require.NoError(t, err)
defer func() { require.NoError(t, store.Restore()) }()
cases := []struct {
name string
options []controller.Option
@ -66,7 +75,7 @@ func TestControllerUsesResource(t *testing.T) {
{
name: "explicitly empty resource",
options: []controller.Option{controller.WithResource(resource.Empty())},
wanted: ""},
wanted: resource.Environment().Encoded(attribute.DefaultEncoder())},
{
name: "uses default if no resource option",
options: nil,
@ -74,15 +83,18 @@ func TestControllerUsesResource(t *testing.T) {
{
name: "explicit resource",
options: []controller.Option{controller.WithResource(resource.NewWithAttributes(attribute.String("R", "S")))},
wanted: "R=S"},
wanted: "R=S,T=U,key=value"},
{
name: "last resource wins",
options: []controller.Option{
controller.WithResource(resource.Default()),
controller.WithResource(resource.NewWithAttributes(attribute.String("R", "S"))),
},
wanted: "R=S",
},
wanted: "R=S,T=U,key=value"},
{
name: "overlapping attributes with environment resource",
options: []controller.Option{controller.WithResource(resource.NewWithAttributes(attribute.String("T", "V")))},
wanted: "T=V,key=value"},
}
for _, c := range cases {
t.Run(fmt.Sprintf("case-%s", c.name), func(t *testing.T) {

View File

@ -40,7 +40,7 @@ var (
otel.Handle(err)
}
return r
}(Detect(context.Background(), defaultServiceNameDetector{}, TelemetrySDK{}))
}(Detect(context.Background(), defaultServiceNameDetector{}, FromEnv{}, TelemetrySDK{}))
)
// NewWithAttributes creates a resource from attrs. If attrs contains
@ -144,6 +144,17 @@ func Default() *Resource {
return defaultResource
}
// Environment returns an instance of Resource with attributes
// extracted from the OTEL_RESOURCE_ATTRIBUTES environment variable.
func Environment() *Resource {
detector := &FromEnv{}
resource, err := detector.Detect(context.Background())
if err == nil {
otel.Handle(err)
}
return resource
}
// Equivalent returns an object that can be compared for equality
// between two resources. This value is suitable for use as a key in
// a map.

View File

@ -262,9 +262,7 @@ func WithSpanProcessor(sp SpanProcessor) TracerProviderOption {
// resource.Default() Resource by default.
func WithResource(r *resource.Resource) TracerProviderOption {
return func(opts *TracerProviderConfig) {
if r != nil {
opts.resource = r
}
opts.resource = resource.Merge(resource.Environment(), r)
}
}

View File

@ -43,6 +43,8 @@ import (
"go.opentelemetry.io/otel/sdk/resource"
)
const envVar = "OTEL_RESOURCE_ATTRIBUTES"
type storingHandler struct {
errs []error
}
@ -1203,6 +1205,12 @@ func TestWithSpanKind(t *testing.T) {
}
func TestWithResource(t *testing.T) {
store, err := ottest.SetEnvVariables(map[string]string{
envVar: "key=value,rk5=7",
})
require.NoError(t, err)
defer func() { require.NoError(t, store.Restore()) }()
cases := []struct {
name string
options []TracerProviderOption
@ -1212,7 +1220,7 @@ func TestWithResource(t *testing.T) {
{
name: "explicitly empty resource",
options: []TracerProviderOption{WithResource(resource.Empty())},
want: resource.Empty(),
want: resource.Environment(),
},
{
name: "uses default if no resource option",
@ -1222,14 +1230,19 @@ func TestWithResource(t *testing.T) {
{
name: "explicit resource",
options: []TracerProviderOption{WithResource(resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)))},
want: resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
want: resource.Merge(resource.Environment(), resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5))),
},
{
name: "last resource wins",
options: []TracerProviderOption{
WithResource(resource.NewWithAttributes(attribute.String("rk1", "vk1"), attribute.Int64("rk2", 5))),
WithResource(resource.NewWithAttributes(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10)))},
want: resource.NewWithAttributes(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10)),
want: resource.Merge(resource.Environment(), resource.NewWithAttributes(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10))),
},
{
name: "overlapping attributes with environment resource",
options: []TracerProviderOption{WithResource(resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10)))},
want: resource.Merge(resource.Environment(), resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10))),
},
}
for _, tc := range cases {