diff --git a/sdk/trace.go b/sdk/trace.go index 495298ce5..c99851d58 100644 --- a/sdk/trace.go +++ b/sdk/trace.go @@ -153,7 +153,55 @@ func (s *span) SetAttributes(attrs ...attribute.KeyValue) { if s == nil || !s.sampled { return } - /* TODO: implement */ + + // TODO: handle attribute limits. + + setAttributes(s.span.Attributes(), attrs) +} + +func setAttributes(dest pcommon.Map, attrs []attribute.KeyValue) { + dest.EnsureCapacity(len(attrs)) + for _, attr := range attrs { + key := string(attr.Key) + switch attr.Value.Type() { + case attribute.BOOL: + dest.PutBool(key, attr.Value.AsBool()) + case attribute.INT64: + dest.PutInt(key, attr.Value.AsInt64()) + case attribute.FLOAT64: + dest.PutDouble(key, attr.Value.AsFloat64()) + case attribute.STRING: + dest.PutStr(key, attr.Value.AsString()) + case attribute.BOOLSLICE: + val := attr.Value.AsBoolSlice() + s := dest.PutEmptySlice(key) + s.EnsureCapacity(len(val)) + for _, v := range val { + s.AppendEmpty().SetBool(v) + } + case attribute.INT64SLICE: + val := attr.Value.AsInt64Slice() + s := dest.PutEmptySlice(key) + s.EnsureCapacity(len(val)) + for _, v := range val { + s.AppendEmpty().SetInt(v) + } + case attribute.FLOAT64SLICE: + val := attr.Value.AsFloat64Slice() + s := dest.PutEmptySlice(key) + s.EnsureCapacity(len(val)) + for _, v := range val { + s.AppendEmpty().SetDouble(v) + } + case attribute.STRINGSLICE: + val := attr.Value.AsStringSlice() + s := dest.PutEmptySlice(key) + s.EnsureCapacity(len(val)) + for _, v := range val { + s.AppendEmpty().SetStr(v) + } + } + } } func (s *span) End(opts ...trace.SpanEndOption) { diff --git a/sdk/trace_test.go b/sdk/trace_test.go index 5d9b0ab42..0c8cd3924 100644 --- a/sdk/trace_test.go +++ b/sdk/trace_test.go @@ -32,6 +32,39 @@ var ( attribute.StringSlice("string slice", []string{"one", "two"}), } + pAttrs = func() pcommon.Map { + m := pcommon.NewMap() + m.PutBool("bool", true) + m.PutInt("int", -1) + m.PutInt("int64", 43) + m.PutDouble("float64", 0.3) + m.PutStr("string", "value") + + s := m.PutEmptySlice("bool slice") + s.AppendEmpty().SetBool(true) + s.AppendEmpty().SetBool(false) + s.AppendEmpty().SetBool(true) + + s = m.PutEmptySlice("int slice") + s.AppendEmpty().SetInt(-1) + s.AppendEmpty().SetInt(-30) + s.AppendEmpty().SetInt(328) + + s = m.PutEmptySlice("int64 slice") + s.AppendEmpty().SetInt(1030) + s.AppendEmpty().SetInt(0) + s.AppendEmpty().SetInt(0) + + s = m.PutEmptySlice("float64 slice") + s.AppendEmpty().SetDouble(1e9) + + s = m.PutEmptySlice("string slice") + s.AppendEmpty().SetStr("one") + s.AppendEmpty().SetStr("two") + + return m + }() + spanContext0 = trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID{0x1}, SpanID: trace.SpanID{0x1}, @@ -259,6 +292,22 @@ func TestSpanIsRecording(t *testing.T) { assert.False(t, s.IsRecording(), "unsampled span should not be recorded") } +func TestSpanSetAttributes(t *testing.T) { + builder := spanBuilder{} + + s := builder.Build() + s.SetAttributes(attrs...) + assert.Equal(t, pAttrs, s.span.Attributes(), "span attributes not set") + + builder.Options = []trace.SpanStartOption{ + trace.WithAttributes(attrs[0].Key.Bool(!attrs[0].Value.AsBool())), + } + + s = builder.Build() + s.SetAttributes(attrs...) + assert.Equal(t, pAttrs, s.span.Attributes(), "SpanAttributes did not override") +} + func TestSpanTracerProvider(t *testing.T) { var s span