From 008040e852b964e622a6774dc615c6d429a0d8e1 Mon Sep 17 00:00:00 2001 From: Evan Torrie Date: Sat, 30 Jan 2021 12:45:52 -0800 Subject: [PATCH 1/3] Create resource.Default() with required attributes/default values Add metric controller and tracer provider tests for resources --- .../metric/prometheus/prometheus_test.go | 1 + sdk/metric/controller/basic/controller.go | 4 + .../controller/basic/controller_test.go | 59 +++++++++ sdk/metric/controller/basic/pull_test.go | 3 + sdk/resource/builtin.go | 18 +++ sdk/resource/resource.go | 16 ++- sdk/resource/resource_test.go | 18 +++ sdk/trace/provider.go | 5 +- sdk/trace/trace_test.go | 114 +++++++++++------- 9 files changed, 194 insertions(+), 44 deletions(-) diff --git a/exporters/metric/prometheus/prometheus_test.go b/exporters/metric/prometheus/prometheus_test.go index fec47e217ea..2bddf70b229 100644 --- a/exporters/metric/prometheus/prometheus_test.go +++ b/exporters/metric/prometheus/prometheus_test.go @@ -117,6 +117,7 @@ func TestPrometheusStatefulness(t *testing.T) { exporter, err := prometheus.NewExportPipeline( prometheus.Config{}, controller.WithCollectPeriod(0), + controller.WithResource(resource.Empty()), ) require.NoError(t, err) diff --git a/sdk/metric/controller/basic/controller.go b/sdk/metric/controller/basic/controller.go index 5227d9ba40e..38ed50219db 100644 --- a/sdk/metric/controller/basic/controller.go +++ b/sdk/metric/controller/basic/controller.go @@ -26,6 +26,7 @@ import ( export "go.opentelemetry.io/otel/sdk/export/metric" sdk "go.opentelemetry.io/otel/sdk/metric" controllerTime "go.opentelemetry.io/otel/sdk/metric/controller/time" + "go.opentelemetry.io/otel/sdk/resource" ) // DefaultPeriod is used for: @@ -85,6 +86,9 @@ func New(checkpointer export.Checkpointer, opts ...Option) *Controller { for _, opt := range opts { opt.Apply(c) } + if c.Resource == nil { + c.Resource = resource.Default() + } impl := sdk.NewAccumulator( checkpointer, diff --git a/sdk/metric/controller/basic/controller_test.go b/sdk/metric/controller/basic/controller_test.go index a1b3a7640b5..521d27b91fe 100644 --- a/sdk/metric/controller/basic/controller_test.go +++ b/sdk/metric/controller/basic/controller_test.go @@ -17,6 +17,7 @@ package basic_test import ( "context" "errors" + "fmt" "testing" "time" @@ -30,6 +31,7 @@ import ( "go.opentelemetry.io/otel/sdk/metric/controller/controllertest" processor "go.opentelemetry.io/otel/sdk/metric/processor/basic" "go.opentelemetry.io/otel/sdk/metric/processor/processortest" + "go.opentelemetry.io/otel/sdk/resource" ) func getMap(t *testing.T, cont *controller.Controller) map[string]float64 { @@ -55,6 +57,58 @@ func checkTestContext(t *testing.T, ctx context.Context) { require.Equal(t, "B", ctx.Value(testContextKey("A"))) } +func TestControllerUsesResource(t *testing.T) { + cases := []struct { + name string + options []controller.Option + wanted string + }{ + { + name: "explicitly empty resource", + options: []controller.Option{controller.WithResource(resource.Empty())}, + wanted: ""}, + { + name: "uses default if no resource option", + options: nil, + wanted: resource.Default().Encoded(label.DefaultEncoder())}, + { + name: "explicit resource", + options: []controller.Option{controller.WithResource(resource.NewWithAttributes(label.String("R", "S")))}, + wanted: "R=S"}, + { + name: "last resource wins", + options: []controller.Option{ + controller.WithResource(resource.Default()), + controller.WithResource(resource.NewWithAttributes(label.String("R", "S"))), + }, + wanted: "R=S", + }, + } + for _, c := range cases { + t.Run(fmt.Sprintf("case-%s", c.name), func(t *testing.T) { + cont := controller.New( + processor.New( + processortest.AggregatorSelector(), + export.CumulativeExportKindSelector(), + ), + c.options..., + ) + prov := cont.MeterProvider() + + ctr := metric.Must(prov.Meter("named")).NewFloat64Counter("calls.sum") + ctr.Add(context.Background(), 1.) + + // Collect once + require.NoError(t, cont.Collect(context.Background())) + + expect := map[string]float64{ + "calls.sum//" + c.wanted: 1., + } + require.EqualValues(t, expect, getMap(t, cont)) + }) + } +} + func TestStartNoExporter(t *testing.T) { cont := controller.New( processor.New( @@ -62,6 +116,7 @@ func TestStartNoExporter(t *testing.T) { export.CumulativeExportKindSelector(), ), controller.WithCollectPeriod(time.Second), + controller.WithResource(resource.Empty()), ) mock := controllertest.NewMockClock() cont.SetClock(mock) @@ -132,6 +187,7 @@ func TestObserverCanceled(t *testing.T) { ), controller.WithCollectPeriod(0), controller.WithCollectTimeout(time.Millisecond), + controller.WithResource(resource.Empty()), ) prov := cont.MeterProvider() @@ -163,6 +219,7 @@ func TestObserverContext(t *testing.T) { export.CumulativeExportKindSelector(), ), controller.WithCollectTimeout(0), + controller.WithResource(resource.Empty()), ) prov := cont.MeterProvider() @@ -228,6 +285,7 @@ func TestExportTimeout(t *testing.T) { controller.WithCollectPeriod(time.Second), controller.WithPushTimeout(time.Millisecond), controller.WithPusher(exporter), + controller.WithResource(resource.Empty()), ) mock := controllertest.NewMockClock() cont.SetClock(mock) @@ -283,6 +341,7 @@ func TestCollectAfterStopThenStartAgain(t *testing.T) { ), controller.WithCollectPeriod(time.Second), controller.WithPusher(exp), + controller.WithResource(resource.Empty()), ) mock := controllertest.NewMockClock() cont.SetClock(mock) diff --git a/sdk/metric/controller/basic/pull_test.go b/sdk/metric/controller/basic/pull_test.go index 1e08323565d..30c5ecef63e 100644 --- a/sdk/metric/controller/basic/pull_test.go +++ b/sdk/metric/controller/basic/pull_test.go @@ -29,6 +29,7 @@ import ( "go.opentelemetry.io/otel/sdk/metric/controller/controllertest" processor "go.opentelemetry.io/otel/sdk/metric/processor/basic" "go.opentelemetry.io/otel/sdk/metric/processor/processortest" + "go.opentelemetry.io/otel/sdk/resource" ) func TestPullNoCollect(t *testing.T) { @@ -39,6 +40,7 @@ func TestPullNoCollect(t *testing.T) { processor.WithMemory(true), ), controller.WithCollectPeriod(0), + controller.WithResource(resource.Empty()), ) ctx := context.Background() @@ -74,6 +76,7 @@ func TestPullWithCollect(t *testing.T) { processor.WithMemory(true), ), controller.WithCollectPeriod(time.Second), + controller.WithResource(resource.Empty()), ) mock := controllertest.NewMockClock() puller.SetClock(mock) diff --git a/sdk/resource/builtin.go b/sdk/resource/builtin.go index a9a0fc88990..f1d6fc49877 100644 --- a/sdk/resource/builtin.go +++ b/sdk/resource/builtin.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "os" + "path/filepath" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" @@ -43,12 +44,15 @@ type ( K label.Key F func() (string, error) } + + defaultServiceNameDetector struct{} ) var ( _ Detector = TelemetrySDK{} _ Detector = Host{} _ Detector = stringDetector{} + _ Detector = defaultServiceNameDetector{} ) // Detect returns a *Resource that describes the OpenTelemetry SDK used. @@ -79,3 +83,17 @@ func (sd stringDetector) Detect(ctx context.Context) (*Resource, error) { } return NewWithAttributes(sd.K.String(value)), nil } + +// Detect implements Detector +func (defaultServiceNameDetector) Detect(ctx context.Context) (*Resource, error) { + return StringDetector( + semconv.ServiceNameKey, + func() (string, error) { + executable, err := os.Executable() + if err != nil { + return "unknown_service", nil + } + return "unknown_service:" + filepath.Base(executable), nil + }, + ).Detect(ctx) +} diff --git a/sdk/resource/resource.go b/sdk/resource/resource.go index 0195bb27618..4ad721d8396 100644 --- a/sdk/resource/resource.go +++ b/sdk/resource/resource.go @@ -15,6 +15,8 @@ package resource // import "go.opentelemetry.io/otel/sdk/resource" import ( + "context" + "go.opentelemetry.io/otel/label" ) @@ -29,7 +31,13 @@ type Resource struct { labels label.Set } -var emptyResource Resource +var ( + emptyResource Resource + + defaultResource *Resource = func(r *Resource, err error) *Resource { return r }( + Detect(context.Background(), defaultServiceNameDetector{}, TelemetrySDK{}), + ) +) // NewWithAttributes creates a resource from a set of attributes. If there are // duplicate keys present in the list of attributes, then the last @@ -113,6 +121,12 @@ func Empty() *Resource { return &emptyResource } +// Default returns an instance of Resource with a default +// "service.name" and OpenTelemetrySDK attributes +func Default() *Resource { + return defaultResource +} + // 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. diff --git a/sdk/resource/resource_test.go b/sdk/resource/resource_test.go index 6457792c1fb..0ecf1150bba 100644 --- a/sdk/resource/resource_test.go +++ b/sdk/resource/resource_test.go @@ -17,13 +17,16 @@ package resource_test import ( "encoding/json" "fmt" + "strings" "testing" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/label" "go.opentelemetry.io/otel/sdk/resource" + "go.opentelemetry.io/otel/semconv" ) var ( @@ -162,6 +165,21 @@ func TestMerge(t *testing.T) { } } +func TestDefault(t *testing.T) { + res := resource.Default() + require.False(t, res.Equal(resource.Empty())) + require.True(t, res.LabelSet().HasValue(semconv.ServiceNameKey)) + + serviceName, _ := res.LabelSet().Value(semconv.ServiceNameKey) + require.True(t, strings.HasPrefix(serviceName.AsString(), "unknown_service:")) + require.Greaterf(t, len(serviceName.AsString()), len("unknown_service:"), + "default service.name should include executable name") + + require.Contains(t, res.Attributes(), semconv.TelemetrySDKLanguageGo) + require.Contains(t, res.Attributes(), semconv.TelemetrySDKVersionKey.String(otel.Version())) + require.Contains(t, res.Attributes(), semconv.TelemetrySDKNameKey.String("opentelemetry")) +} + func TestString(t *testing.T) { for _, test := range []struct { kvs []label.KeyValue diff --git a/sdk/trace/provider.go b/sdk/trace/provider.go index 901e8d4a76d..59792937b7a 100644 --- a/sdk/trace/provider.go +++ b/sdk/trace/provider.go @@ -179,8 +179,9 @@ func (p *TracerProvider) ApplyConfig(cfg Config) { if cfg.MaxLinksPerSpan > 0 { c.MaxLinksPerSpan = cfg.MaxLinksPerSpan } - if cfg.Resource != nil { - c.Resource = cfg.Resource + c.Resource = cfg.Resource + if c.Resource == nil { + c.Resource = resource.Default() } p.config.Store(&c) } diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go index fb73b2ef0f1..fe19a638e6c 100644 --- a/sdk/trace/trace_test.go +++ b/sdk/trace/trace_test.go @@ -354,7 +354,7 @@ func TestStartSpanWithParent(t *testing.T) { func TestSetSpanAttributesOnStart(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) span := startSpan(tp, "StartSpanAttribute", trace.WithAttributes(label.String("key1", "value1")), @@ -387,7 +387,7 @@ func TestSetSpanAttributesOnStart(t *testing.T) { func TestSetSpanAttributes(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) span := startSpan(tp, "SpanAttribute") span.SetAttributes(label.String("key1", "value1")) got, err := endSpan(te, span) @@ -419,7 +419,7 @@ func TestSetSpanAttributes(t *testing.T) { func TestSamplerAttributesLocalChildSpan(t *testing.T) { sampler := &testSampler{prefix: "span", t: t} te := NewTestExporter() - tp := NewTracerProvider(WithConfig(Config{DefaultSampler: sampler}), WithSyncer(te)) + tp := NewTracerProvider(WithConfig(Config{DefaultSampler: sampler}), WithSyncer(te), WithResource(resource.Empty())) ctx := context.Background() ctx, span := startLocalSpan(tp, ctx, "SpanOne", "span0") @@ -483,7 +483,7 @@ func TestSamplerAttributesLocalChildSpan(t *testing.T) { func TestSetSpanAttributesOverLimit(t *testing.T) { te := NewTestExporter() cfg := Config{MaxAttributesPerSpan: 2} - tp := NewTracerProvider(WithConfig(cfg), WithSyncer(te)) + tp := NewTracerProvider(WithConfig(cfg), WithSyncer(te), WithResource(resource.Empty())) span := startSpan(tp, "SpanAttributesOverLimit") span.SetAttributes( @@ -520,7 +520,7 @@ func TestSetSpanAttributesOverLimit(t *testing.T) { func TestEvents(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) span := startSpan(tp, "Events") k1v1 := label.String("key1", "value1") @@ -566,7 +566,7 @@ func TestEvents(t *testing.T) { func TestEventsOverLimit(t *testing.T) { te := NewTestExporter() cfg := Config{MaxEventsPerSpan: 2} - tp := NewTracerProvider(WithConfig(cfg), WithSyncer(te)) + tp := NewTracerProvider(WithConfig(cfg), WithSyncer(te), WithResource(resource.Empty())) span := startSpan(tp, "EventsOverLimit") k1v1 := label.String("key1", "value1") @@ -617,7 +617,7 @@ func TestEventsOverLimit(t *testing.T) { func TestLinks(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) k1v1 := label.String("key1", "value1") k2v2 := label.String("key2", "value2") @@ -662,7 +662,7 @@ func TestLinksOverLimit(t *testing.T) { sc2 := trace.SpanContext{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}} sc3 := trace.SpanContext{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}} - tp := NewTracerProvider(WithConfig(cfg), WithSyncer(te)) + tp := NewTracerProvider(WithConfig(cfg), WithSyncer(te), WithResource(resource.Empty())) span := startSpan(tp, "LinksOverLimit", trace.WithLinks( @@ -703,7 +703,7 @@ func TestLinksOverLimit(t *testing.T) { func TestSetSpanName(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) ctx := context.Background() want := "SpanName-1" @@ -725,7 +725,7 @@ func TestSetSpanName(t *testing.T) { func TestSetSpanStatus(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) span := startSpan(tp, "SpanStatus") span.SetStatus(codes.Error, "Error") @@ -1083,7 +1083,7 @@ func TestRecordError(t *testing.T) { for _, s := range scenarios { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) span := startSpan(tp, "RecordError") errTime := time.Now() @@ -1124,7 +1124,7 @@ func TestRecordError(t *testing.T) { func TestRecordErrorNil(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) span := startSpan(tp, "RecordErrorNil") span.RecordError(nil) @@ -1154,7 +1154,7 @@ func TestRecordErrorNil(t *testing.T) { func TestWithSpanKind(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te), WithConfig(Config{DefaultSampler: AlwaysSample()})) + tp := NewTracerProvider(WithSyncer(te), WithConfig(Config{DefaultSampler: AlwaysSample()}), WithResource(resource.Empty())) tr := tp.Tracer("withSpanKind") _, span := tr.Start(context.Background(), "WithoutSpanKind") @@ -1191,40 +1191,72 @@ func TestWithSpanKind(t *testing.T) { } func TestWithResource(t *testing.T) { - te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te), - WithConfig(Config{DefaultSampler: AlwaysSample()}), - WithResource(resource.NewWithAttributes(label.String("rk1", "rv1"), label.Int64("rk2", 5)))) - span := startSpan(tp, "WithResource") - span.SetAttributes(label.String("key1", "value1")) - got, err := endSpan(te, span) - if err != nil { - t.Error(err.Error()) - } - - want := &export.SpanSnapshot{ - SpanContext: trace.SpanContext{ - TraceID: tid, - TraceFlags: 0x1, + cases := []struct { + name string + options []TracerProviderOption + want *resource.Resource + msg string + }{ + { + name: "explicitly empty resource", + options: []TracerProviderOption{WithResource(resource.Empty())}, + want: resource.Empty(), }, - ParentSpanID: sid, - Name: "span0", - Attributes: []label.KeyValue{ - label.String("key1", "value1"), + { + name: "uses default if no resource option", + options: []TracerProviderOption{}, + want: resource.Default(), + }, + { + name: "explicit resource", + options: []TracerProviderOption{WithResource(resource.NewWithAttributes(label.String("rk1", "rv1"), label.Int64("rk2", 5)))}, + want: resource.NewWithAttributes(label.String("rk1", "rv1"), label.Int64("rk2", 5)), + }, + { + name: "last resource wins", + options: []TracerProviderOption{ + WithResource(resource.NewWithAttributes(label.String("rk1", "vk1"), label.Int64("rk2", 5))), + WithResource(resource.NewWithAttributes(label.String("rk3", "rv3"), label.Int64("rk4", 10)))}, + want: resource.NewWithAttributes(label.String("rk3", "rv3"), label.Int64("rk4", 10)), }, - SpanKind: trace.SpanKindInternal, - HasRemoteParent: true, - Resource: resource.NewWithAttributes(label.String("rk1", "rv1"), label.Int64("rk2", 5)), - InstrumentationLibrary: instrumentation.Library{Name: "WithResource"}, } - if diff := cmpDiff(got, want); diff != "" { - t.Errorf("WithResource:\n -got +want %s", diff) + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + te := NewTestExporter() + defaultOptions := []TracerProviderOption{WithSyncer(te), WithConfig(Config{DefaultSampler: AlwaysSample()})} + tp := NewTracerProvider(append(defaultOptions, tc.options...)...) + span := startSpan(tp, "WithResource") + span.SetAttributes(label.String("key1", "value1")) + got, err := endSpan(te, span) + if err != nil { + t.Error(err.Error()) + } + want := &export.SpanSnapshot{ + SpanContext: trace.SpanContext{ + TraceID: tid, + TraceFlags: 0x1, + }, + ParentSpanID: sid, + Name: "span0", + Attributes: []label.KeyValue{ + label.String("key1", "value1"), + }, + SpanKind: trace.SpanKindInternal, + HasRemoteParent: true, + Resource: tc.want, + InstrumentationLibrary: instrumentation.Library{Name: "WithResource"}, + } + if diff := cmpDiff(got, want); diff != "" { + t.Errorf("WithResource:\n -got +want %s", diff) + } + }) } } func TestWithInstrumentationVersion(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) ctx := context.Background() ctx = trace.ContextWithRemoteSpanContext(ctx, remoteSpanContext()) @@ -1258,7 +1290,7 @@ func TestWithInstrumentationVersion(t *testing.T) { func TestSpanCapturesPanic(t *testing.T) { te := NewTestExporter() - tp := NewTracerProvider(WithSyncer(te)) + tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty())) _, span := tp.Tracer("CatchPanic").Start( context.Background(), "span", @@ -1363,7 +1395,7 @@ func TestReadOnlySpan(t *testing.T) { } func TestReadWriteSpan(t *testing.T) { - tp := NewTracerProvider() + tp := NewTracerProvider(WithResource(resource.Empty())) cfg := tp.config.Load().(*Config) tr := tp.Tracer("ReadWriteSpan") From 249fcdd2c45f99de5c33736d051ae1b7508160c4 Mon Sep 17 00:00:00 2001 From: Evan Torrie Date: Sun, 31 Jan 2021 12:56:10 -0800 Subject: [PATCH 2/3] Updated CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 493c29c4251..1f9b2ff031b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Changed +- Create `resource.Default()` for use with meter and tracer providers. (#1507) - Reverse order in which `Resource` attributes are merged, per change in spec. (#1501) ## [0.16.0] - 2020-01-13 From 6ed813d0cd7d176f52e7c53603c749f5c4965949 Mon Sep 17 00:00:00 2001 From: Evan Torrie Date: Sat, 13 Feb 2021 22:04:46 -0800 Subject: [PATCH 3/3] PR comments + some small CHANGELOG PR addition, rewording + change default resource servicename to `unknown_service:go` (this matches the Java codebase which uses `unknown_service:java`) --- CHANGELOG.md | 4 ++-- sdk/resource/builtin.go | 2 +- sdk/resource/resource.go | 11 ++++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d6d25c86b6..69f6aa4f572 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,11 +10,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Added -- Create `resource.Default()` for use with meter and tracer providers. (#1507) +- Added `resource.Default()` for use with meter and tracer providers. (#1507) ### Changed -- Rename project default branch from `master` to `main`. +- Rename project default branch from `master` to `main`. (#1505) - Reverse order in which `Resource` attributes are merged, per change in spec. (#1501) - Add tooling to maintain "replace" directives in go.mod files automatically. (#1528) - Create new modules: otel/metric, otel/trace, otel/oteltest, otel/sdk/export/metric, otel/sdk/metric (#1528) diff --git a/sdk/resource/builtin.go b/sdk/resource/builtin.go index f1d6fc49877..f96148ed134 100644 --- a/sdk/resource/builtin.go +++ b/sdk/resource/builtin.go @@ -91,7 +91,7 @@ func (defaultServiceNameDetector) Detect(ctx context.Context) (*Resource, error) func() (string, error) { executable, err := os.Executable() if err != nil { - return "unknown_service", nil + return "unknown_service:go", nil } return "unknown_service:" + filepath.Base(executable), nil }, diff --git a/sdk/resource/resource.go b/sdk/resource/resource.go index 4ad721d8396..10b826e61a7 100644 --- a/sdk/resource/resource.go +++ b/sdk/resource/resource.go @@ -17,6 +17,8 @@ package resource // import "go.opentelemetry.io/otel/sdk/resource" import ( "context" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/label" ) @@ -34,9 +36,12 @@ type Resource struct { var ( emptyResource Resource - defaultResource *Resource = func(r *Resource, err error) *Resource { return r }( - Detect(context.Background(), defaultServiceNameDetector{}, TelemetrySDK{}), - ) + defaultResource *Resource = func(r *Resource, err error) *Resource { + if err != nil { + otel.Handle(err) + } + return r + }(Detect(context.Background(), defaultServiceNameDetector{}, TelemetrySDK{})) ) // NewWithAttributes creates a resource from a set of attributes. If there are