diff --git a/CHANGELOG.md b/CHANGELOG.md index a95103744..e13a86263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## Added - Added `Marshler` config option to `otlphttp` to enable otlp over json or protobufs. (#1586) +- Added non-empty string check for trace `Attribute` keys. (#1659) + ### Removed - Removed the exported `SimpleSpanProcessor` and `BatchSpanProcessor` structs. diff --git a/sdk/trace/span.go b/sdk/trace/span.go index 9f03f5d3b..e897d6770 100644 --- a/sdk/trace/span.go +++ b/sdk/trace/span.go @@ -491,7 +491,9 @@ func (s *span) copyToCappedAttributes(attributes ...attribute.KeyValue) { s.mu.Lock() defer s.mu.Unlock() for _, a := range attributes { - if a.Value.Type() != attribute.INVALID { + // Ensure attributes conform to the specification: + // https://github.com/open-telemetry/opentelemetry-specification/blob/v1.0.1/specification/common/common.md#attributes + if a.Value.Type() != attribute.INVALID && a.Key != "" { s.attributes.add(a) } } diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go index 4a3aeffbc..b844e4892 100644 --- a/sdk/trace/trace_test.go +++ b/sdk/trace/trace_test.go @@ -520,6 +520,41 @@ func TestSetSpanAttributesOverLimit(t *testing.T) { } } +func TestSetSpanAttributesWithInvalidKey(t *testing.T) { + te := NewTestExporter() + cfg := Config{SpanLimits: SpanLimits{}} + tp := NewTracerProvider(WithConfig(cfg), WithSyncer(te), WithResource(resource.Empty())) + + span := startSpan(tp, "SpanToSetInvalidKeyOrValue") + span.SetAttributes( + attribute.Bool("", true), + attribute.Bool("key1", false), + ) + got, err := endSpan(te, span) + if err != nil { + t.Fatal(err) + } + + want := &export.SpanSnapshot{ + SpanContext: trace.SpanContext{ + TraceID: tid, + TraceFlags: 0x1, + }, + ParentSpanID: sid, + Name: "span0", + Attributes: []attribute.KeyValue{ + attribute.Bool("key1", false), + }, + SpanKind: trace.SpanKindInternal, + HasRemoteParent: true, + DroppedAttributeCount: 0, + InstrumentationLibrary: instrumentation.Library{Name: "SpanToSetInvalidKeyOrValue"}, + } + if diff := cmpDiff(got, want); diff != "" { + t.Errorf("SetSpanAttributesWithInvalidKey: -got +want %s", diff) + } +} + func TestEvents(t *testing.T) { te := NewTestExporter() tp := NewTracerProvider(WithSyncer(te), WithResource(resource.Empty()))