Skip to content

Commit

Permalink
Add Schema URL support to Resource
Browse files Browse the repository at this point in the history
This implements specification requirement:
https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#resource-creation

- Changes `resource.NewWithAttributes` to require a schema URL. The old function
  is still available as `resource.NewSchemaless`. This is a breaking change.
  We want to encourage using schema URL and make it a conscious choice to have a
  resource without schema.

- Merge schema URLs acccording to the spec in resource.Merge.

- Several builtin resource detectors now correctly populate the schema URL.
  • Loading branch information
tigrannajaryan committed Jun 4, 2021
1 parent aed4580 commit 6782b74
Show file tree
Hide file tree
Showing 46 changed files with 410 additions and 137 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -33,6 +33,8 @@ 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)
- Changes `go.opentelemetry.io/otel/sdk/resource.NewWithAttributes` to require a schema URL. The old function is still available as `resource.NewSchemaless`. This is a breaking change. (#1938)
- Several builtin resource detectors now correctly populate the schema URL. (#1938)

### Changed

Expand Down
2 changes: 1 addition & 1 deletion bridge/opencensus/exporter.go
Expand Up @@ -126,7 +126,7 @@ func convertResource(res *ocresource.Resource) *resource.Resource {
for k, v := range res.Labels {
labels = append(labels, attribute.KeyValue{Key: attribute.Key(k), Value: attribute.StringValue(v)})
}
return resource.NewWithAttributes(labels...)
return resource.NewSchemaless(labels...)
}

// convertDescriptor converts an OpenCensus Descriptor to an OpenTelemetry Descriptor
Expand Down
10 changes: 5 additions & 5 deletions bridge/opencensus/exporter_test.go
Expand Up @@ -155,7 +155,7 @@ func TestExportMetrics(t *testing.T) {
export.NewRecord(
&basicDesc,
attribute.EmptySet(),
resource.NewWithAttributes(),
resource.NewSchemaless(),
&ocExactAggregator{
points: []aggregation.Point{
{
Expand Down Expand Up @@ -187,7 +187,7 @@ func TestExportMetrics(t *testing.T) {
export.NewRecord(
&basicDesc,
attribute.EmptySet(),
resource.NewWithAttributes(),
resource.NewSchemaless(),
&ocExactAggregator{
points: []aggregation.Point{
{
Expand Down Expand Up @@ -222,7 +222,7 @@ func TestExportMetrics(t *testing.T) {
export.NewRecord(
&basicDesc,
attribute.EmptySet(),
resource.NewWithAttributes(),
resource.NewSchemaless(),
&ocExactAggregator{
points: []aggregation.Point{
{
Expand Down Expand Up @@ -349,7 +349,7 @@ func TestConvertResource(t *testing.T) {
input: &ocresource.Resource{
Labels: map[string]string{},
},
expected: resource.NewWithAttributes(),
expected: resource.NewSchemaless(),
},
{
desc: "resource with labels",
Expand All @@ -359,7 +359,7 @@ func TestConvertResource(t *testing.T) {
"tick": "tock",
},
},
expected: resource.NewWithAttributes(
expected: resource.NewSchemaless(
attribute.KeyValue{Key: attribute.Key("foo"), Value: attribute.StringValue("bar")},
attribute.KeyValue{Key: attribute.Key("tick"), Value: attribute.StringValue("tock")},
),
Expand Down
1 change: 1 addition & 0 deletions example/jaeger/main.go
Expand Up @@ -51,6 +51,7 @@ func tracerProvider(url string) (*tracesdk.TracerProvider, error) {
tracesdk.WithBatcher(exp),
// Record information about this application in an Resource.
tracesdk.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(service),
attribute.String("environment", environment),
attribute.Int64("ID", id),
Expand Down
1 change: 1 addition & 0 deletions example/zipkin/main.go
Expand Up @@ -54,6 +54,7 @@ func initTracer(url string) func() {
tp := sdktrace.NewTracerProvider(
sdktrace.WithSpanProcessor(batcher),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("zipkin-test"),
)),
)
Expand Down
2 changes: 1 addition & 1 deletion exporters/metric/prometheus/prometheus_test.go
Expand Up @@ -84,7 +84,7 @@ func TestPrometheusExporter(t *testing.T) {
DefaultHistogramBoundaries: []float64{-0.5, 1},
},
controller.WithCollectPeriod(0),
controller.WithResource(resource.NewWithAttributes(attribute.String("R", "V"))),
controller.WithResource(resource.NewSchemaless(attribute.String("R", "V"))),
)
require.NoError(t, err)

Expand Down
4 changes: 2 additions & 2 deletions exporters/otlp/internal/otlptest/data.go
Expand Up @@ -67,7 +67,7 @@ func (OneRecordCheckpointSet) ForEach(kindSelector exportmetric.ExportKindSelect
metric.CounterInstrumentKind,
number.Int64Kind,
)
res := resource.NewWithAttributes(attribute.String("a", "b"))
res := resource.NewSchemaless(attribute.String("a", "b"))
agg := sum.New(1)
if err := agg[0].Update(context.Background(), number.NewInt64Number(42), &desc); err != nil {
return err
Expand Down Expand Up @@ -106,7 +106,7 @@ func SingleReadOnlySpan() []tracesdk.ReadOnlySpan {
DroppedEvents: 0,
DroppedLinks: 0,
ChildSpanCount: 0,
Resource: resource.NewWithAttributes(attribute.String("a", "b")),
Resource: resource.NewSchemaless(attribute.String("a", "b")),
InstrumentationLibrary: instrumentation.Library{
Name: "bar",
Version: "0.0.0",
Expand Down
4 changes: 2 additions & 2 deletions exporters/otlp/internal/otlptest/otlptest.go
Expand Up @@ -50,13 +50,13 @@ func RunEndToEndTest(ctx context.Context, t *testing.T, exp *otlp.Exporter, mcTr
),
}
tp1 := sdktrace.NewTracerProvider(append(pOpts,
sdktrace.WithResource(resource.NewWithAttributes(
sdktrace.WithResource(resource.NewSchemaless(
attribute.String("rk1", "rv11)"),
attribute.Int64("rk2", 5),
)))...)

tp2 := sdktrace.NewTracerProvider(append(pOpts,
sdktrace.WithResource(resource.NewWithAttributes(
sdktrace.WithResource(resource.NewSchemaless(
attribute.String("rk1", "rv12)"),
attribute.Float64("rk3", 6.5),
)))...)
Expand Down
5 changes: 5 additions & 0 deletions exporters/otlp/internal/transform/metric.go
Expand Up @@ -167,6 +167,7 @@ func sink(ctx context.Context, in <-chan result) ([]*metricpb.ResourceMetrics, e
Resource *resourcepb.Resource
// Group by instrumentation library name and then the MetricDescriptor.
InstrumentationLibraryBatches map[instrumentation.Library]map[string]*metricpb.Metric
SchemaURL string
}

// group by unique Resource string.
Expand All @@ -184,6 +185,9 @@ func sink(ctx context.Context, in <-chan result) ([]*metricpb.ResourceMetrics, e
Resource: Resource(res.Resource),
InstrumentationLibraryBatches: make(map[instrumentation.Library]map[string]*metricpb.Metric),
}
if res.Resource != nil {
rb.SchemaURL = res.Resource.SchemaURL()
}
grouped[rID] = rb
}

Expand Down Expand Up @@ -220,6 +224,7 @@ func sink(ctx context.Context, in <-chan result) ([]*metricpb.ResourceMetrics, e

var rms []*metricpb.ResourceMetrics
for _, rb := range grouped {
// TODO: populate ResourceMetrics.SchemaURL when the field is added to the Protobuf message.
rm := &metricpb.ResourceMetrics{Resource: rb.Resource}
for il, mb := range rb.InstrumentationLibraryBatches {
ilm := &metricpb.InstrumentationLibraryMetrics{
Expand Down
2 changes: 1 addition & 1 deletion exporters/otlp/internal/transform/resource_test.go
Expand Up @@ -40,7 +40,7 @@ func TestEmptyResource(t *testing.T) {
func TestResourceAttributes(t *testing.T) {
attrs := []attribute.KeyValue{attribute.Int("one", 1), attribute.Int("two", 2)}

got := Resource(resource.NewWithAttributes(attrs...)).GetAttributes()
got := Resource(resource.NewSchemaless(attrs...)).GetAttributes()
if !assert.Len(t, attrs, 2) {
return
}
Expand Down
1 change: 1 addition & 0 deletions exporters/otlp/internal/transform/span.go
Expand Up @@ -75,6 +75,7 @@ func Spans(sdl []tracesdk.ReadOnlySpan) []*tracepb.ResourceSpans {
Resource: Resource(sd.Resource()),
InstrumentationLibrarySpans: []*tracepb.InstrumentationLibrarySpans{ils},
}
// TODO: populate ResourceSpans.SchemaURL when the field is added to the Protobuf message.
rsm[rKey] = rs
continue
}
Expand Down
2 changes: 1 addition & 1 deletion exporters/otlp/internal/transform/span_test.go
Expand Up @@ -261,7 +261,7 @@ func TestSpanData(t *testing.T) {
DroppedAttributes: 1,
DroppedEvents: 2,
DroppedLinks: 3,
Resource: resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
Resource: resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
InstrumentationLibrary: instrumentation.Library{
Name: "go.opentelemetry.io/test/otel",
Version: "v0.0.1",
Expand Down
4 changes: 2 additions & 2 deletions exporters/otlp/otlp_metric_test.go
Expand Up @@ -80,8 +80,8 @@ var (
baseKeyValues = []attribute.KeyValue{attribute.String("host", "test.com")}
cpuKey = attribute.Key("CPU")

testInstA = resource.NewWithAttributes(attribute.String("instance", "tester-a"))
testInstB = resource.NewWithAttributes(attribute.String("instance", "tester-b"))
testInstA = resource.NewSchemaless(attribute.String("instance", "tester-a"))
testInstB = resource.NewSchemaless(attribute.String("instance", "tester-b"))

testHistogramBoundaries = []float64{2.0, 4.0, 8.0}

Expand Down
8 changes: 4 additions & 4 deletions exporters/otlp/otlp_span_test.go
Expand Up @@ -73,7 +73,7 @@ func TestExportSpans(t *testing.T) {
Code: codes.Ok,
Description: "Ok",
},
Resource: resource.NewWithAttributes(attribute.String("instance", "tester-a")),
Resource: resource.NewSchemaless(attribute.String("instance", "tester-a")),
InstrumentationLibrary: instrumentation.Library{
Name: "lib-a",
Version: "v0.1.0",
Expand All @@ -97,7 +97,7 @@ func TestExportSpans(t *testing.T) {
Code: codes.Ok,
Description: "Ok",
},
Resource: resource.NewWithAttributes(attribute.String("instance", "tester-a")),
Resource: resource.NewSchemaless(attribute.String("instance", "tester-a")),
InstrumentationLibrary: instrumentation.Library{
Name: "lib-b",
Version: "v0.1.0",
Expand Down Expand Up @@ -126,7 +126,7 @@ func TestExportSpans(t *testing.T) {
Code: codes.Ok,
Description: "Ok",
},
Resource: resource.NewWithAttributes(attribute.String("instance", "tester-a")),
Resource: resource.NewSchemaless(attribute.String("instance", "tester-a")),
InstrumentationLibrary: instrumentation.Library{
Name: "lib-a",
Version: "v0.1.0",
Expand All @@ -150,7 +150,7 @@ func TestExportSpans(t *testing.T) {
Code: codes.Error,
Description: "Unauthenticated",
},
Resource: resource.NewWithAttributes(attribute.String("instance", "tester-b")),
Resource: resource.NewSchemaless(attribute.String("instance", "tester-b")),
InstrumentationLibrary: instrumentation.Library{
Name: "lib-a",
Version: "v1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion exporters/otlp/otlptrace/internal/otlptracetest/data.go
Expand Up @@ -53,7 +53,7 @@ func SingleReadOnlySpan() []tracesdk.ReadOnlySpan {
DroppedEvents: 0,
DroppedLinks: 0,
ChildSpanCount: 0,
Resource: resource.NewWithAttributes(attribute.String("a", "b")),
Resource: resource.NewSchemaless(attribute.String("a", "b")),
InstrumentationLibrary: instrumentation.Library{
Name: "bar",
Version: "0.0.0",
Expand Down
4 changes: 2 additions & 2 deletions exporters/otlp/otlptrace/internal/otlptracetest/otlptest.go
Expand Up @@ -40,13 +40,13 @@ func RunEndToEndTest(ctx context.Context, t *testing.T, exp *otlptrace.Exporter,
),
}
tp1 := sdktrace.NewTracerProvider(append(pOpts,
sdktrace.WithResource(resource.NewWithAttributes(
sdktrace.WithResource(resource.NewSchemaless(
attribute.String("rk1", "rv11)"),
attribute.Int64("rk2", 5),
)))...)

tp2 := sdktrace.NewTracerProvider(append(pOpts,
sdktrace.WithResource(resource.NewWithAttributes(
sdktrace.WithResource(resource.NewSchemaless(
attribute.String("rk1", "rv12)"),
attribute.Float64("rk3", 6.5),
)))...)
Expand Down
Expand Up @@ -40,7 +40,7 @@ func TestEmptyResource(t *testing.T) {
func TestResourceAttributes(t *testing.T) {
attrs := []attribute.KeyValue{attribute.Int("one", 1), attribute.Int("two", 2)}

got := Resource(resource.NewWithAttributes(attrs...)).GetAttributes()
got := Resource(resource.NewSchemaless(attrs...)).GetAttributes()
if !assert.Len(t, attrs, 2) {
return
}
Expand Down
Expand Up @@ -262,7 +262,7 @@ func TestSpanData(t *testing.T) {
DroppedAttributes: 1,
DroppedEvents: 2,
DroppedLinks: 3,
Resource: resource.NewWithAttributes(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
Resource: resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
InstrumentationLibrary: instrumentation.Library{
Name: "go.opentelemetry.io/test/otel",
Version: "v0.0.1",
Expand Down
8 changes: 4 additions & 4 deletions exporters/stdout/metric_test.go
Expand Up @@ -46,7 +46,7 @@ type testFixture struct {
output *bytes.Buffer
}

var testResource = resource.NewWithAttributes(attribute.String("R", "V"))
var testResource = resource.NewSchemaless(attribute.String("R", "V"))

func newFixture(t *testing.T, opts ...stdout.Option) testFixture {
buf := &bytes.Buffer{}
Expand Down Expand Up @@ -270,11 +270,11 @@ func TestStdoutResource(t *testing.T) {
}
testCases := []testCase{
newCase("R1=V1,R2=V2,A=B,C=D",
resource.NewWithAttributes(attribute.String("R1", "V1"), attribute.String("R2", "V2")),
resource.NewSchemaless(attribute.String("R1", "V1"), attribute.String("R2", "V2")),
attribute.String("A", "B"),
attribute.String("C", "D")),
newCase("R1=V1,R2=V2",
resource.NewWithAttributes(attribute.String("R1", "V1"), attribute.String("R2", "V2")),
resource.NewSchemaless(attribute.String("R1", "V1"), attribute.String("R2", "V2")),
),
newCase("A=B,C=D",
nil,
Expand All @@ -284,7 +284,7 @@ func TestStdoutResource(t *testing.T) {
// We explicitly do not de-duplicate between resources
// and metric labels in this exporter.
newCase("R1=V1,R2=V2,R1=V3,R2=V4",
resource.NewWithAttributes(attribute.String("R1", "V1"), attribute.String("R2", "V2")),
resource.NewSchemaless(attribute.String("R1", "V1"), attribute.String("R2", "V2")),
attribute.String("R1", "V3"),
attribute.String("R2", "V4")),
}
Expand Down
2 changes: 1 addition & 1 deletion exporters/stdout/trace_test.go
Expand Up @@ -49,7 +49,7 @@ func TestExporter_ExportSpan(t *testing.T) {
traceState, _ := oteltest.TraceStateFromKeyValues(attribute.String("key", "val"))
keyValue := "value"
doubleValue := 123.456
resource := resource.NewWithAttributes(attribute.String("rk1", "rv11"))
resource := resource.NewSchemaless(attribute.String("rk1", "rv11"))

ro := tracetest.SpanStubs{
{
Expand Down

0 comments on commit 6782b74

Please sign in to comment.