diff --git a/internal/storage/v2/clickhouse/tracestore/assert_test.go b/internal/storage/v2/clickhouse/tracestore/assert_test.go index 5160edf7816..593d9b3b067 100644 --- a/internal/storage/v2/clickhouse/tracestore/assert_test.go +++ b/internal/storage/v2/clickhouse/tracestore/assert_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" + "go.opentelemetry.io/collector/pdata/xpdata" "github.com/jaegertracing/jaeger/internal/jptrace" "github.com/jaegertracing/jaeger/internal/storage/v2/clickhouse/tracestore/dbmodel" @@ -126,6 +127,24 @@ func requireComplexAttrs(t *testing.T, expectedKeys []string, expectedVals []str decoded, err := base64.StdEncoding.DecodeString(expectedVals[i]) require.NoError(t, err) require.Equal(t, decoded, val.Bytes().AsRaw()) + case strings.HasPrefix(k, "@map@"): + key := strings.TrimPrefix(expectedKeys[i], "@map@") + val, ok := attrs.Get(key) + require.True(t, ok) + + m := &xpdata.JSONUnmarshaler{} + expectedVal, err := m.UnmarshalValue([]byte(expectedVals[i])) + require.NoError(t, err) + require.True(t, expectedVal.Map().Equal(val.Map())) + case strings.HasPrefix(k, "@slice@"): + key := strings.TrimPrefix(expectedKeys[i], "@slice@") + val, ok := attrs.Get(key) + require.True(t, ok) + + m := &xpdata.JSONUnmarshaler{} + expectedVal, err := m.UnmarshalValue([]byte(expectedVals[i])) + require.NoError(t, err) + require.True(t, expectedVal.Slice().Equal(val.Slice())) default: t.Fatalf("unsupported complex attribute key: %s", k) } diff --git a/internal/storage/v2/clickhouse/tracestore/dbmodel/dbmodel_test.go b/internal/storage/v2/clickhouse/tracestore/dbmodel/dbmodel_test.go index da5676d7b97..fb12098fe51 100644 --- a/internal/storage/v2/clickhouse/tracestore/dbmodel/dbmodel_test.go +++ b/internal/storage/v2/clickhouse/tracestore/dbmodel/dbmodel_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" + "go.opentelemetry.io/collector/pdata/xpdata" "github.com/jaegertracing/jaeger/internal/telemetry/otelsemconv" ) @@ -32,7 +33,7 @@ func TestRoundTrip(t *testing.T) { }) t.Run("FromRow->ToRow", func(t *testing.T) { - spanRow := createTestSpanRow(now, duration) + spanRow := createTestSpanRow(t, now, duration) trace := FromRow(spanRow) rs := trace.ResourceSpans().At(0).Resource() @@ -114,10 +115,27 @@ func addTestAttributes(attrs pcommon.Map) { attrs.PutInt("int_attr", 42) attrs.PutStr("string_attr", "string_value") attrs.PutEmptyBytes("bytes_attr").FromRaw([]byte("bytes_value")) + attrs.PutEmptyMap("map_attr").FromRaw(map[string]any{"key": "value"}) + attrs.PutEmptySlice("slice_attr").FromRaw([]any{1, 2, 3}) } -func createTestSpanRow(now time.Time, duration time.Duration) *SpanRow { +func createTestSpanRow(t *testing.T, now time.Time, duration time.Duration) *SpanRow { + t.Helper() encodedBytes := base64.StdEncoding.EncodeToString([]byte("bytes_value")) + + vm := pcommon.NewValueMap() + vm.Map().PutStr("key", "value") + m := &xpdata.JSONMarshaler{} + vmJSON, err := m.MarshalValue(vm) + require.NoError(t, err) + + vs := pcommon.NewValueSlice() + vs.Slice().AppendEmpty().SetInt(1) + vs.Slice().AppendEmpty().SetInt(2) + vs.Slice().AppendEmpty().SetInt(3) + vsJSON, err := m.MarshalValue(vs) + require.NoError(t, err) + return &SpanRow{ ID: "0000000000000001", TraceID: "00000000000000000000000000000001", @@ -138,8 +156,8 @@ func createTestSpanRow(now time.Time, duration time.Duration) *SpanRow { IntValues: []int64{42}, StrKeys: []string{"string_attr"}, StrValues: []string{"string_value"}, - ComplexKeys: []string{"@bytes@bytes_attr"}, - ComplexValues: []string{encodedBytes}, + ComplexKeys: []string{"@bytes@bytes_attr", "@map@map_attr", "@slice@slice_attr"}, + ComplexValues: []string{encodedBytes, string(vmJSON), string(vsJSON)}, }, EventNames: []string{"test-event"}, EventTimestamps: []time.Time{now}, @@ -152,8 +170,8 @@ func createTestSpanRow(now time.Time, duration time.Duration) *SpanRow { IntValues: [][]int64{{42}}, StrKeys: [][]string{{"string_attr"}}, StrValues: [][]string{{"string_value"}}, - ComplexKeys: [][]string{{"@bytes@bytes_attr"}}, - ComplexValues: [][]string{{encodedBytes}}, + ComplexKeys: [][]string{{"@bytes@bytes_attr", "@map@map_attr", "@slice@slice_attr"}}, + ComplexValues: [][]string{{encodedBytes, string(vmJSON), string(vsJSON)}}, }, LinkTraceIDs: []string{"00000000000000000000000000000003"}, LinkSpanIDs: []string{"0000000000000004"}, @@ -167,8 +185,8 @@ func createTestSpanRow(now time.Time, duration time.Duration) *SpanRow { IntValues: [][]int64{{42}}, StrKeys: [][]string{{"string_attr"}}, StrValues: [][]string{{"string_value"}}, - ComplexKeys: [][]string{{"@bytes@bytes_attr"}}, - ComplexValues: [][]string{{encodedBytes}}, + ComplexKeys: [][]string{{"@bytes@bytes_attr", "@map@map_attr", "@slice@slice_attr"}}, + ComplexValues: [][]string{{encodedBytes, string(vmJSON), string(vsJSON)}}, }, ServiceName: "test-service", ResourceAttributes: Attributes{ @@ -180,8 +198,8 @@ func createTestSpanRow(now time.Time, duration time.Duration) *SpanRow { IntValues: []int64{42}, StrKeys: []string{"service.name", "string_attr"}, StrValues: []string{"test-service", "string_value"}, - ComplexKeys: []string{"@bytes@bytes_attr"}, - ComplexValues: []string{encodedBytes}, + ComplexKeys: []string{"@bytes@bytes_attr", "@map@map_attr", "@slice@slice_attr"}, + ComplexValues: []string{encodedBytes, string(vmJSON), string(vsJSON)}, }, ScopeName: "test-scope", ScopeVersion: "v1.0.0", @@ -194,8 +212,8 @@ func createTestSpanRow(now time.Time, duration time.Duration) *SpanRow { IntValues: []int64{42}, StrKeys: []string{"string_attr"}, StrValues: []string{"string_value"}, - ComplexKeys: []string{"@bytes@bytes_attr"}, - ComplexValues: []string{encodedBytes}, + ComplexKeys: []string{"@bytes@bytes_attr", "@map@map_attr", "@slice@slice_attr"}, + ComplexValues: []string{encodedBytes, string(vmJSON), string(vsJSON)}, }, } } diff --git a/internal/storage/v2/clickhouse/tracestore/dbmodel/from.go b/internal/storage/v2/clickhouse/tracestore/dbmodel/from.go index 1758261f172..df2a760319d 100644 --- a/internal/storage/v2/clickhouse/tracestore/dbmodel/from.go +++ b/internal/storage/v2/clickhouse/tracestore/dbmodel/from.go @@ -12,6 +12,7 @@ import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" + "go.opentelemetry.io/collector/pdata/xpdata" "github.com/jaegertracing/jaeger/internal/jptrace" "github.com/jaegertracing/jaeger/internal/telemetry/otelsemconv" @@ -169,7 +170,8 @@ func putAttributes( attrs.PutStr(storedAttrs.StrKeys[i], storedAttrs.StrValues[i]) } for i := 0; i < len(storedAttrs.ComplexKeys); i++ { - if strings.HasPrefix(storedAttrs.ComplexKeys[i], "@bytes@") { + switch { + case strings.HasPrefix(storedAttrs.ComplexKeys[i], "@bytes@"): decoded, err := base64.StdEncoding.DecodeString(storedAttrs.ComplexValues[i]) if err != nil { jptrace.AddWarnings(spanForWarnings, fmt.Sprintf("failed to decode bytes attribute %q: %s", storedAttrs.ComplexKeys[i], err.Error())) @@ -177,6 +179,42 @@ func putAttributes( } k := strings.TrimPrefix(storedAttrs.ComplexKeys[i], "@bytes@") attrs.PutEmptyBytes(k).FromRaw(decoded) + case strings.HasPrefix(storedAttrs.ComplexKeys[i], "@slice@"): + k := strings.TrimPrefix(storedAttrs.ComplexKeys[i], "@slice@") + m := &xpdata.JSONUnmarshaler{} + val, err := m.UnmarshalValue([]byte(storedAttrs.ComplexValues[i])) + if err != nil { + jptrace.AddWarnings( + spanForWarnings, + fmt.Sprintf( + "failed to unmarshal slice attribute %q: %s", + storedAttrs.ComplexKeys[i], + err.Error(), + ), + ) + continue + } + attrs.PutEmptySlice(k).FromRaw(val.Slice().AsRaw()) + case strings.HasPrefix(storedAttrs.ComplexKeys[i], "@map@"): + k := strings.TrimPrefix(storedAttrs.ComplexKeys[i], "@map@") + m := &xpdata.JSONUnmarshaler{} + val, err := m.UnmarshalValue([]byte(storedAttrs.ComplexValues[i])) + if err != nil { + jptrace.AddWarnings( + spanForWarnings, + fmt.Sprintf("failed to unmarshal map attribute %q: %s", + storedAttrs.ComplexKeys[i], + err.Error(), + ), + ) + continue + } + attrs.PutEmptyMap(k).FromRaw(val.Map().AsRaw()) + default: + jptrace.AddWarnings( + spanForWarnings, + fmt.Sprintf("unsupported complex attribute key: %q", storedAttrs.ComplexKeys[i]), + ) } } } diff --git a/internal/storage/v2/clickhouse/tracestore/dbmodel/from_test.go b/internal/storage/v2/clickhouse/tracestore/dbmodel/from_test.go index 25e0097bca0..30dca0d718c 100644 --- a/internal/storage/v2/clickhouse/tracestore/dbmodel/from_test.go +++ b/internal/storage/v2/clickhouse/tracestore/dbmodel/from_test.go @@ -18,7 +18,7 @@ func TestFromRow(t *testing.T) { now := time.Now().UTC() duration := 2 * time.Second - spanRow := createTestSpanRow(now, duration) + spanRow := createTestSpanRow(t, now, duration) expected := createTestTrace(now, duration) @@ -89,23 +89,55 @@ func TestFromRow_DecodeID(t *testing.T) { } func TestPutAttributes_Warnings(t *testing.T) { - t.Run("bytes attribute with invalid base64", func(t *testing.T) { - span := ptrace.NewSpan() - attributes := pcommon.NewMap() + tests := []struct { + name string + complexKeys []string + complexValues []string + expectedWarnContains string + }{ + { + name: "bytes attribute with invalid base64", + complexKeys: []string{"@bytes@bytes-key"}, + complexValues: []string{"invalid-base64"}, + expectedWarnContains: "failed to decode bytes attribute \"@bytes@bytes-key\"", + }, + { + name: "failed to unmarshal slice attribute", + complexKeys: []string{"@slice@slice-key"}, + complexValues: []string{"notjson"}, + expectedWarnContains: "failed to unmarshal slice attribute \"@slice@slice-key\"", + }, + { + name: "failed to unmarshal map attribute", + complexKeys: []string{"@map@map-key"}, + complexValues: []string{"notjson"}, + expectedWarnContains: "failed to unmarshal map attribute \"@map@map-key\"", + }, + { + name: "unsupported complex attribute key", + complexKeys: []string{"unsupported"}, + complexValues: []string{"{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}"}, + expectedWarnContains: "unsupported complex attribute key: \"unsupported\"", + }, + } - putAttributes( - attributes, - &Attributes{ - ComplexKeys: []string{"@bytes@bytes-key"}, - ComplexValues: []string{"invalid-base64"}, - }, - span, - ) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + span := ptrace.NewSpan() + attributes := pcommon.NewMap() + + putAttributes( + attributes, + &Attributes{ + ComplexKeys: tt.complexKeys, + ComplexValues: tt.complexValues, + }, + span, + ) - _, ok := attributes.Get("bytes-key") - require.False(t, ok) - warnings := jptrace.GetWarnings(span) - require.Len(t, warnings, 1) - require.Contains(t, warnings[0], "failed to decode bytes attribute \"@bytes@bytes-key\"") - }) + warnings := jptrace.GetWarnings(span) + require.Len(t, warnings, 1) + require.Contains(t, warnings[0], tt.expectedWarnContains) + }) + } } diff --git a/internal/storage/v2/clickhouse/tracestore/dbmodel/spanrow.go b/internal/storage/v2/clickhouse/tracestore/dbmodel/spanrow.go index 134b66802c2..d9d7832323e 100644 --- a/internal/storage/v2/clickhouse/tracestore/dbmodel/spanrow.go +++ b/internal/storage/v2/clickhouse/tracestore/dbmodel/spanrow.go @@ -9,16 +9,22 @@ import ( "github.com/ClickHouse/clickhouse-go/v2/lib/driver" ) -// SpanRow represents a single row in the ClickHouse `spans` table. +// SpanRow represents a single record in the ClickHouse `spans` table. // -// Complex attributes are attributes that are not of a primitive type and hence need special handling. -// The following OTLP types are stored in the complex attributes fields: -// - AnyValue_BytesValue: This OTLP type is stored as a base64-encoded string. The key -// for this type will begin with `@bytes@`. -// - AnyValue_ArrayValue: This OTLP type is stored as a JSON-encoded string. -// The key for this type will begin with `@array@`. -// - AnyValue_KVListValue: This OTLP type is stored as a JSON-encoded string. -// The key for this type will begin with `@kvlist@`. +// Complex attributes are non-primitive OTLP types that require special serialization +// before being stored. These types are encoded as follows: +// +// - pcommon.ValueTypeBytes: +// Represents raw byte data. The value is Base64-encoded and stored as a string. +// Keys for this type are prefixed with `@bytes@`. +// +// - pcommon.ValueTypeSlice: +// Represents an OTLP slice (array). The value is serialized to JSON and stored +// as a string. Keys for this type are prefixed with `@slice@`. +// +// - pcommon.ValueTypeMap: +// Represents an OTLP map. The value is serialized to JSON and stored +// as a string. Keys for this type are prefixed with `@map@`. type SpanRow struct { // --- Span --- ID string diff --git a/internal/storage/v2/clickhouse/tracestore/dbmodel/to.go b/internal/storage/v2/clickhouse/tracestore/dbmodel/to.go index ae2dbc1e45c..cca04695fae 100644 --- a/internal/storage/v2/clickhouse/tracestore/dbmodel/to.go +++ b/internal/storage/v2/clickhouse/tracestore/dbmodel/to.go @@ -5,9 +5,11 @@ package dbmodel import ( "encoding/base64" + "fmt" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" + "go.opentelemetry.io/collector/pdata/xpdata" "github.com/jaegertracing/jaeger/internal/jptrace" "github.com/jaegertracing/jaeger/internal/telemetry/otelsemconv" @@ -53,30 +55,30 @@ func ToRow( func appendAttributes(dest *Attributes, attrs pcommon.Map) { a := extractAttributes(attrs) - dest.BoolKeys = append(dest.BoolKeys, a.boolKeys...) - dest.BoolValues = append(dest.BoolValues, a.boolValues...) - dest.DoubleKeys = append(dest.DoubleKeys, a.doubleKeys...) - dest.DoubleValues = append(dest.DoubleValues, a.doubleValues...) - dest.IntKeys = append(dest.IntKeys, a.intKeys...) - dest.IntValues = append(dest.IntValues, a.intValues...) - dest.StrKeys = append(dest.StrKeys, a.strKeys...) - dest.StrValues = append(dest.StrValues, a.strValues...) - dest.ComplexKeys = append(dest.ComplexKeys, a.complexKeys...) - dest.ComplexValues = append(dest.ComplexValues, a.complexValues...) + dest.BoolKeys = append(dest.BoolKeys, a.BoolKeys...) + dest.BoolValues = append(dest.BoolValues, a.BoolValues...) + dest.DoubleKeys = append(dest.DoubleKeys, a.DoubleKeys...) + dest.DoubleValues = append(dest.DoubleValues, a.DoubleValues...) + dest.IntKeys = append(dest.IntKeys, a.IntKeys...) + dest.IntValues = append(dest.IntValues, a.IntValues...) + dest.StrKeys = append(dest.StrKeys, a.StrKeys...) + dest.StrValues = append(dest.StrValues, a.StrValues...) + dest.ComplexKeys = append(dest.ComplexKeys, a.ComplexKeys...) + dest.ComplexValues = append(dest.ComplexValues, a.ComplexValues...) } func appendAttributes2D(dest *Attributes2D, attrs pcommon.Map) { a := extractAttributes(attrs) - dest.BoolKeys = append(dest.BoolKeys, a.boolKeys) - dest.BoolValues = append(dest.BoolValues, a.boolValues) - dest.DoubleKeys = append(dest.DoubleKeys, a.doubleKeys) - dest.DoubleValues = append(dest.DoubleValues, a.doubleValues) - dest.IntKeys = append(dest.IntKeys, a.intKeys) - dest.IntValues = append(dest.IntValues, a.intValues) - dest.StrKeys = append(dest.StrKeys, a.strKeys) - dest.StrValues = append(dest.StrValues, a.strValues) - dest.ComplexKeys = append(dest.ComplexKeys, a.complexKeys) - dest.ComplexValues = append(dest.ComplexValues, a.complexValues) + dest.BoolKeys = append(dest.BoolKeys, a.BoolKeys) + dest.BoolValues = append(dest.BoolValues, a.BoolValues) + dest.DoubleKeys = append(dest.DoubleKeys, a.DoubleKeys) + dest.DoubleValues = append(dest.DoubleValues, a.DoubleValues) + dest.IntKeys = append(dest.IntKeys, a.IntKeys) + dest.IntValues = append(dest.IntValues, a.IntValues) + dest.StrKeys = append(dest.StrKeys, a.StrKeys) + dest.StrValues = append(dest.StrValues, a.StrValues) + dest.ComplexKeys = append(dest.ComplexKeys, a.ComplexKeys) + dest.ComplexValues = append(dest.ComplexValues, a.ComplexValues) } func (sr *SpanRow) appendEvent(event ptrace.SpanEvent) { @@ -92,39 +94,53 @@ func (sr *SpanRow) appendLink(link ptrace.SpanLink) { appendAttributes2D(&sr.LinkAttributes, link.Attributes()) } -func extractAttributes(attrs pcommon.Map) (out struct { - boolKeys []string - boolValues []bool - doubleKeys []string - doubleValues []float64 - intKeys []string - intValues []int64 - strKeys []string - strValues []string - complexKeys []string - complexValues []string -}, -) { +func extractAttributes(attrs pcommon.Map) *Attributes { + out := &Attributes{} attrs.Range(func(k string, v pcommon.Value) bool { switch v.Type() { case pcommon.ValueTypeBool: - out.boolKeys = append(out.boolKeys, k) - out.boolValues = append(out.boolValues, v.Bool()) + out.BoolKeys = append(out.BoolKeys, k) + out.BoolValues = append(out.BoolValues, v.Bool()) case pcommon.ValueTypeDouble: - out.doubleKeys = append(out.doubleKeys, k) - out.doubleValues = append(out.doubleValues, v.Double()) + out.DoubleKeys = append(out.DoubleKeys, k) + out.DoubleValues = append(out.DoubleValues, v.Double()) case pcommon.ValueTypeInt: - out.intKeys = append(out.intKeys, k) - out.intValues = append(out.intValues, v.Int()) + out.IntKeys = append(out.IntKeys, k) + out.IntValues = append(out.IntValues, v.Int()) case pcommon.ValueTypeStr: - out.strKeys = append(out.strKeys, k) - out.strValues = append(out.strValues, v.Str()) + out.StrKeys = append(out.StrKeys, k) + out.StrValues = append(out.StrValues, v.Str()) case pcommon.ValueTypeBytes: key := "@bytes@" + k encoded := base64.StdEncoding.EncodeToString(v.Bytes().AsRaw()) - out.complexKeys = append(out.complexKeys, key) - out.complexValues = append(out.complexValues, encoded) - // TODO: support array and map types + out.ComplexKeys = append(out.ComplexKeys, key) + out.ComplexValues = append(out.ComplexValues, encoded) + case pcommon.ValueTypeSlice: + key := "@slice@" + k + m := &xpdata.JSONMarshaler{} + b, err := m.MarshalValue(v) + if err != nil { + out.StrKeys = append(out.StrKeys, jptrace.WarningsAttribute) + out.StrValues = append( + out.StrValues, + fmt.Sprintf("failed to marshal slice attribute %q: %v", k, err)) + break + } + out.ComplexKeys = append(out.ComplexKeys, key) + out.ComplexValues = append(out.ComplexValues, string(b)) + case pcommon.ValueTypeMap: + key := "@map@" + k + m := &xpdata.JSONMarshaler{} + b, err := m.MarshalValue(v) + if err != nil { + out.StrKeys = append(out.StrKeys, jptrace.WarningsAttribute) + out.StrValues = append( + out.StrValues, + fmt.Sprintf("failed to marshal map attribute %q: %v", k, err)) + break + } + out.ComplexKeys = append(out.ComplexKeys, key) + out.ComplexValues = append(out.ComplexValues, string(b)) default: } return true diff --git a/internal/storage/v2/clickhouse/tracestore/dbmodel/to_test.go b/internal/storage/v2/clickhouse/tracestore/dbmodel/to_test.go index 192bc96aa4e..6055f124137 100644 --- a/internal/storage/v2/clickhouse/tracestore/dbmodel/to_test.go +++ b/internal/storage/v2/clickhouse/tracestore/dbmodel/to_test.go @@ -18,7 +18,7 @@ func TestToRow(t *testing.T) { sc := createTestScope() span := createTestSpan(now, duration) - expected := createTestSpanRow(now, duration) + expected := createTestSpanRow(t, now, duration) row := ToRow(rs, sc, span) require.Equal(t, expected, row) diff --git a/internal/storage/v2/clickhouse/tracestore/spans_test.go b/internal/storage/v2/clickhouse/tracestore/spans_test.go index 4dfc1109afc..b1d1ffee1d1 100644 --- a/internal/storage/v2/clickhouse/tracestore/spans_test.go +++ b/internal/storage/v2/clickhouse/tracestore/spans_test.go @@ -27,72 +27,120 @@ var singleSpan = []*dbmodel.SpanRow{ StatusMessage: "success", Duration: 1_000_000_000, Attributes: dbmodel.Attributes{ - BoolKeys: []string{"authenticated", "cache_hit"}, - BoolValues: []bool{true, false}, - DoubleKeys: []string{"response_time", "cpu_usage"}, - DoubleValues: []float64{0.123, 45.67}, - IntKeys: []string{"user_id", "request_size"}, - IntValues: []int64{12345, 1024}, - StrKeys: []string{"http.method", "http.url"}, - StrValues: []string{"GET", "/api/user"}, - ComplexKeys: []string{"@bytes@request_body"}, - ComplexValues: []string{"eyJuYW1lIjoidGVzdCJ9"}, + BoolKeys: []string{"authenticated", "cache_hit"}, + BoolValues: []bool{true, false}, + DoubleKeys: []string{"response_time", "cpu_usage"}, + DoubleValues: []float64{0.123, 45.67}, + IntKeys: []string{"user_id", "request_size"}, + IntValues: []int64{12345, 1024}, + StrKeys: []string{"http.method", "http.url"}, + StrValues: []string{"GET", "/api/user"}, + ComplexKeys: []string{ + "@bytes@request_body", + "@map@metadata", + "@slice@tags", + }, + ComplexValues: []string{ + "eyJuYW1lIjoidGVzdCJ9", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, }, EventNames: []string{"login"}, EventTimestamps: []time.Time{now}, EventAttributes: dbmodel.Attributes2D{ - BoolKeys: [][]string{{"event.authenticated", "event.cached"}}, - BoolValues: [][]bool{{true, false}}, - DoubleKeys: [][]string{{"event.response_time"}}, - DoubleValues: [][]float64{{0.001}}, - IntKeys: [][]string{{"event.sequence"}}, - IntValues: [][]int64{{1}}, - StrKeys: [][]string{{"event.message"}}, - StrValues: [][]string{{"user login successful"}}, - ComplexKeys: [][]string{{"@bytes@event.payload"}}, - ComplexValues: [][]string{{"eyJ1c2VyX2lkIjoxMjM0NX0="}}, + BoolKeys: [][]string{{"event.authenticated", "event.cached"}}, + BoolValues: [][]bool{{true, false}}, + DoubleKeys: [][]string{{"event.response_time"}}, + DoubleValues: [][]float64{{0.001}}, + IntKeys: [][]string{{"event.sequence"}}, + IntValues: [][]int64{{1}}, + StrKeys: [][]string{{"event.message"}}, + StrValues: [][]string{{"user login successful"}}, + ComplexKeys: [][]string{ + { + "@bytes@event.payload", + "@map@metadata", + "@slice@tags", + }, + }, + ComplexValues: [][]string{ + { + "eyJ1c2VyX2lkIjoxMjM0NX0=", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, + }, }, LinkTraceIDs: []string{"00000000000000000000000000000002"}, LinkSpanIDs: []string{"0000000000000002"}, LinkTraceStates: []string{"state2"}, LinkAttributes: dbmodel.Attributes2D{ - BoolKeys: [][]string{{"link.validated", "link.active"}}, - BoolValues: [][]bool{{true, true}}, - DoubleKeys: [][]string{{"link.weight"}}, - DoubleValues: [][]float64{{0.8}}, - IntKeys: [][]string{{"link.priority"}}, - IntValues: [][]int64{{1}}, - StrKeys: [][]string{{"link.type"}}, - StrValues: [][]string{{"follows_from"}}, - ComplexKeys: [][]string{{"@bytes@link.metadata"}}, - ComplexValues: [][]string{{"eyJsaW5rX2lkIjoxfQ=="}}, + BoolKeys: [][]string{{"link.validated", "link.active"}}, + BoolValues: [][]bool{{true, true}}, + DoubleKeys: [][]string{{"link.weight"}}, + DoubleValues: [][]float64{{0.8}}, + IntKeys: [][]string{{"link.priority"}}, + IntValues: [][]int64{{1}}, + StrKeys: [][]string{{"link.type"}}, + StrValues: [][]string{{"follows_from"}}, + ComplexKeys: [][]string{ + { + "@bytes@link.metadata", + "@map@metadata", + "@slice@tags", + }, + }, + ComplexValues: [][]string{ + { + "eyJsaW5rX2lkIjoxfQ==", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, + }, }, ServiceName: "user-service", ResourceAttributes: dbmodel.Attributes{ - BoolKeys: []string{"resource.available", "resource.active"}, - BoolValues: []bool{true, true}, - DoubleKeys: []string{"resource.cpu_limit", "resource.memory_usage"}, - DoubleValues: []float64{2.5, 80.5}, - IntKeys: []string{"resource.instance_id", "resource.port"}, - IntValues: []int64{12345, 8080}, - StrKeys: []string{"service.name", "resource.host", "resource.region"}, - StrValues: []string{"user-service", "host-1", "us-west-1"}, - ComplexKeys: []string{"@bytes@resource.metadata"}, - ComplexValues: []string{"eyJkZXBsb3ltZW50IjoicHJvZCJ9"}, + BoolKeys: []string{"resource.available", "resource.active"}, + BoolValues: []bool{true, true}, + DoubleKeys: []string{"resource.cpu_limit", "resource.memory_usage"}, + DoubleValues: []float64{2.5, 80.5}, + IntKeys: []string{"resource.instance_id", "resource.port"}, + IntValues: []int64{12345, 8080}, + StrKeys: []string{"service.name", "resource.host", "resource.region"}, + StrValues: []string{"user-service", "host-1", "us-west-1"}, + ComplexKeys: []string{ + "@bytes@resource.metadata", + "@map@metadata", + "@slice@tags", + }, + ComplexValues: []string{ + "eyJkZXBsb3ltZW50IjoicHJvZCJ9", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, }, ScopeName: "auth-scope", ScopeVersion: "v1.0.0", ScopeAttributes: dbmodel.Attributes{ - BoolKeys: []string{"scope.enabled", "scope.persistent"}, - BoolValues: []bool{true, false}, - DoubleKeys: []string{"scope.version_number", "scope.priority"}, - DoubleValues: []float64{1.0, 0.8}, - IntKeys: []string{"scope.instance_count", "scope.max_spans"}, - IntValues: []int64{5, 1000}, - StrKeys: []string{"scope.environment", "scope.component"}, - StrValues: []string{"production", "auth"}, - ComplexKeys: []string{"@bytes@scope.metadata"}, - ComplexValues: []string{"eyJzY29wZV90eXBlIjoiYXV0aGVudGljYXRpb24ifQ=="}, + BoolKeys: []string{"scope.enabled", "scope.persistent"}, + BoolValues: []bool{true, false}, + DoubleKeys: []string{"scope.version_number", "scope.priority"}, + DoubleValues: []float64{1.0, 0.8}, + IntKeys: []string{"scope.instance_count", "scope.max_spans"}, + IntValues: []int64{5, 1000}, + StrKeys: []string{"scope.environment", "scope.component"}, + StrValues: []string{"production", "auth"}, + ComplexKeys: []string{ + "@bytes@scope.metadata", + "@map@metadata", + "@slice@tags", + }, + ComplexValues: []string{ + "eyJzY29wZV90eXBlIjoiYXV0aGVudGljYXRpb24ifQ==", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, }, }, } @@ -109,72 +157,120 @@ var multipleSpans = []*dbmodel.SpanRow{ StatusMessage: "success", Duration: 1_000_000_000, Attributes: dbmodel.Attributes{ - BoolKeys: []string{"authenticated", "cache_hit"}, - BoolValues: []bool{true, false}, - DoubleKeys: []string{"response_time", "cpu_usage"}, - DoubleValues: []float64{0.123, 45.67}, - IntKeys: []string{"user_id", "request_size"}, - IntValues: []int64{12345, 1024}, - StrKeys: []string{"http.method", "http.url"}, - StrValues: []string{"GET", "/api/user"}, - ComplexKeys: []string{"@bytes@request_body"}, - ComplexValues: []string{"eyJuYW1lIjoidGVzdCJ9"}, + BoolKeys: []string{"authenticated", "cache_hit"}, + BoolValues: []bool{true, false}, + DoubleKeys: []string{"response_time", "cpu_usage"}, + DoubleValues: []float64{0.123, 45.67}, + IntKeys: []string{"user_id", "request_size"}, + IntValues: []int64{12345, 1024}, + StrKeys: []string{"http.method", "http.url"}, + StrValues: []string{"GET", "/api/user"}, + ComplexKeys: []string{ + "@bytes@request_body", + "@map@metadata", + "@slice@tags", + }, + ComplexValues: []string{ + "eyJuYW1lIjoidGVzdCJ9", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, }, EventNames: []string{"login"}, EventTimestamps: []time.Time{now}, EventAttributes: dbmodel.Attributes2D{ - BoolKeys: [][]string{{"event.authenticated", "event.cached"}}, - BoolValues: [][]bool{{true, false}}, - DoubleKeys: [][]string{{"event.response_time"}}, - DoubleValues: [][]float64{{0.001}}, - IntKeys: [][]string{{"event.sequence"}}, - IntValues: [][]int64{{1}}, - StrKeys: [][]string{{"event.message"}}, - StrValues: [][]string{{"user login successful"}}, - ComplexKeys: [][]string{{"@bytes@event.payload"}}, - ComplexValues: [][]string{{"eyJ1c2VyX2lkIjoxMjM0NX0="}}, + BoolKeys: [][]string{{"event.authenticated", "event.cached"}}, + BoolValues: [][]bool{{true, false}}, + DoubleKeys: [][]string{{"event.response_time"}}, + DoubleValues: [][]float64{{0.001}}, + IntKeys: [][]string{{"event.sequence"}}, + IntValues: [][]int64{{1}}, + StrKeys: [][]string{{"event.message"}}, + StrValues: [][]string{{"user login successful"}}, + ComplexKeys: [][]string{ + { + "@bytes@event.payload", + "@map@metadata", + "@slice@tags", + }, + }, + ComplexValues: [][]string{ + { + "eyJ1c2VyX2lkIjoxMjM0NX0=", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, + }, }, LinkTraceIDs: []string{"00000000000000000000000000000002"}, LinkSpanIDs: []string{"0000000000000002"}, LinkTraceStates: []string{"state2"}, LinkAttributes: dbmodel.Attributes2D{ - BoolKeys: [][]string{{"link.validated", "link.active"}}, - BoolValues: [][]bool{{true, true}}, - DoubleKeys: [][]string{{"link.weight"}}, - DoubleValues: [][]float64{{0.8}}, - IntKeys: [][]string{{"link.priority"}}, - IntValues: [][]int64{{1}}, - StrKeys: [][]string{{"link.type"}}, - StrValues: [][]string{{"follows_from"}}, - ComplexKeys: [][]string{{"@bytes@link.metadata"}}, - ComplexValues: [][]string{{"eyJsaW5rX2lkIjoxfQ=="}}, + BoolKeys: [][]string{{"link.validated", "link.active"}}, + BoolValues: [][]bool{{true, true}}, + DoubleKeys: [][]string{{"link.weight"}}, + DoubleValues: [][]float64{{0.8}}, + IntKeys: [][]string{{"link.priority"}}, + IntValues: [][]int64{{1}}, + StrKeys: [][]string{{"link.type"}}, + StrValues: [][]string{{"follows_from"}}, + ComplexKeys: [][]string{ + { + "@bytes@link.metadata", + "@map@metadata", + "@slice@tags", + }, + }, + ComplexValues: [][]string{ + { + "eyJsaW5rX2lkIjoxfQ==", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, + }, }, ServiceName: "user-service", ResourceAttributes: dbmodel.Attributes{ - BoolKeys: []string{"resource.available", "resource.active"}, - BoolValues: []bool{true, true}, - DoubleKeys: []string{"resource.cpu_limit", "resource.memory_usage"}, - DoubleValues: []float64{2.5, 80.5}, - IntKeys: []string{"resource.instance_id", "resource.port"}, - IntValues: []int64{12345, 8080}, - StrKeys: []string{"service.name", "resource.host", "resource.region"}, - StrValues: []string{"user-service", "host-1", "us-west-1"}, - ComplexKeys: []string{"@bytes@resource.metadata"}, - ComplexValues: []string{"eyJkZXBsb3ltZW50IjoicHJvZCJ9"}, + BoolKeys: []string{"resource.available", "resource.active"}, + BoolValues: []bool{true, true}, + DoubleKeys: []string{"resource.cpu_limit", "resource.memory_usage"}, + DoubleValues: []float64{2.5, 80.5}, + IntKeys: []string{"resource.instance_id", "resource.port"}, + IntValues: []int64{12345, 8080}, + StrKeys: []string{"service.name", "resource.host", "resource.region"}, + StrValues: []string{"user-service", "host-1", "us-west-1"}, + ComplexKeys: []string{ + "@bytes@resource.metadata", + "@map@metadata", + "@slice@tags", + }, + ComplexValues: []string{ + "eyJkZXBsb3ltZW50IjoicHJvZCJ9", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, }, ScopeName: "auth-scope", ScopeVersion: "v1.0.0", ScopeAttributes: dbmodel.Attributes{ - BoolKeys: []string{"scope.enabled", "scope.persistent"}, - BoolValues: []bool{true, false}, - DoubleKeys: []string{"scope.version_number", "scope.priority"}, - DoubleValues: []float64{1.0, 0.8}, - IntKeys: []string{"scope.instance_count", "scope.max_spans"}, - IntValues: []int64{5, 1000}, - StrKeys: []string{"scope.environment", "scope.component"}, - StrValues: []string{"production", "auth"}, - ComplexKeys: []string{"@bytes@scope.metadata"}, - ComplexValues: []string{"eyJzY29wZV90eXBlIjoiYXV0aGVudGljYXRpb24ifQ=="}, + BoolKeys: []string{"scope.enabled", "scope.persistent"}, + BoolValues: []bool{true, false}, + DoubleKeys: []string{"scope.version_number", "scope.priority"}, + DoubleValues: []float64{1.0, 0.8}, + IntKeys: []string{"scope.instance_count", "scope.max_spans"}, + IntValues: []int64{5, 1000}, + StrKeys: []string{"scope.environment", "scope.component"}, + StrValues: []string{"production", "auth"}, + ComplexKeys: []string{ + "@bytes@scope.metadata", + "@map@metadata", + "@slice@tags", + }, + ComplexValues: []string{ + "eyJzY29wZV90eXBlIjoiYXV0aGVudGljYXRpb24ifQ==", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, }, }, { @@ -189,72 +285,126 @@ var multipleSpans = []*dbmodel.SpanRow{ StatusMessage: "success", Duration: 500_000_000, Attributes: dbmodel.Attributes{ - BoolKeys: []string{"db.cached", "db.readonly"}, - BoolValues: []bool{false, true}, - DoubleKeys: []string{"db.latency", "db.connections"}, - DoubleValues: []float64{0.05, 5.0}, - IntKeys: []string{"db.rows_affected", "db.connection_id"}, - IntValues: []int64{150, 42}, - StrKeys: []string{"db.statement", "db.name"}, - StrValues: []string{"SELECT * FROM users", "userdb"}, - ComplexKeys: []string{"@bytes@db.query_plan"}, - ComplexValues: []string{"UExBTiBTRUxFQ1Q="}, + BoolKeys: []string{"db.cached", "db.readonly"}, + BoolValues: []bool{false, true}, + DoubleKeys: []string{"db.latency", "db.connections"}, + DoubleValues: []float64{0.05, 5.0}, + IntKeys: []string{"db.rows_affected", "db.connection_id"}, + IntValues: []int64{150, 42}, + StrKeys: []string{"db.statement", "db.name"}, + StrValues: []string{"SELECT * FROM users", "userdb"}, + ComplexKeys: []string{ + "@bytes@db.query_plan", + "@map@metadata", + "@slice@tags", + }, + ComplexValues: []string{ + "UExBTiBTRUxFQ1Q=", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, }, EventNames: []string{"query-start", "query-end"}, EventTimestamps: []time.Time{now.Add(10 * time.Millisecond), now.Add(510 * time.Millisecond)}, EventAttributes: dbmodel.Attributes2D{ - BoolKeys: [][]string{{"db.optimized", "db.indexed"}, {"db.cached", "db.successful"}}, - BoolValues: [][]bool{{true, false}, {true, false}}, - DoubleKeys: [][]string{{"db.query_time"}, {"db.result_time"}}, - DoubleValues: [][]float64{{0.001}, {0.5}}, - IntKeys: [][]string{{"db.connection_pool_size"}, {"db.result_count"}}, - IntValues: [][]int64{{10}, {150}}, - StrKeys: [][]string{{"db.event.type"}, {"db.event.status"}}, - StrValues: [][]string{{"query_execution_start"}, {"query_execution_complete"}}, - ComplexKeys: [][]string{{"@bytes@db.query_metadata"}, {"@bytes@db.result_metadata"}}, - ComplexValues: [][]string{{"eyJxdWVyeV9pZCI6MTIzfQ=="}, {"eyJyb3dfY291bnQiOjE1MH0="}}, + BoolKeys: [][]string{{"db.optimized", "db.indexed"}, {"db.cached", "db.successful"}}, + BoolValues: [][]bool{{true, false}, {true, false}}, + DoubleKeys: [][]string{{"db.query_time"}, {"db.result_time"}}, + DoubleValues: [][]float64{{0.001}, {0.5}}, + IntKeys: [][]string{{"db.connection_pool_size"}, {"db.result_count"}}, + IntValues: [][]int64{{10}, {150}}, + StrKeys: [][]string{{"db.event.type"}, {"db.event.status"}}, + StrValues: [][]string{{"query_execution_start"}, {"query_execution_complete"}}, + ComplexKeys: [][]string{ + { + "@bytes@db.query_metadata", + "@map@metadata", + "@slice@tags", + }, + { + "@bytes@db.result_metadata", + }, + }, + ComplexValues: [][]string{ + { + "eyJxdWVyeV9pZCI6MTIzfQ==", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, + { + "eyJyb3dfY291bnQiOjE1MH0=", + }, + }, }, LinkTraceIDs: []string{"00000000000000000000000000000004"}, LinkSpanIDs: []string{"0000000000000004"}, LinkTraceStates: []string{"state3"}, LinkAttributes: dbmodel.Attributes2D{ - BoolKeys: [][]string{{"link.persistent", "link.direct"}}, - BoolValues: [][]bool{{true, false}}, - DoubleKeys: [][]string{{"link.confidence"}}, - DoubleValues: [][]float64{{0.95}}, - IntKeys: [][]string{{"link.sequence"}}, - IntValues: [][]int64{{2}}, - StrKeys: [][]string{{"link.operation"}}, - StrValues: [][]string{{"child_of"}}, - ComplexKeys: [][]string{{"@bytes@link.context"}}, - ComplexValues: [][]string{{"eyJkYl9jb250ZXh0IjoidXNlcmRiIn0="}}, + BoolKeys: [][]string{{"link.persistent", "link.direct"}}, + BoolValues: [][]bool{{true, false}}, + DoubleKeys: [][]string{{"link.confidence"}}, + DoubleValues: [][]float64{{0.95}}, + IntKeys: [][]string{{"link.sequence"}}, + IntValues: [][]int64{{2}}, + StrKeys: [][]string{{"link.operation"}}, + StrValues: [][]string{{"child_of"}}, + ComplexKeys: [][]string{ + { + "@bytes@link.context", + "@map@metadata", + "@slice@tags", + }, + }, + ComplexValues: [][]string{ + { + "eyJkYl9jb250ZXh0IjoidXNlcmRiIn0=", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, + }, }, ServiceName: "db-service", ResourceAttributes: dbmodel.Attributes{ - BoolKeys: []string{"resource.persistent", "resource.pooled"}, - BoolValues: []bool{true, true}, - DoubleKeys: []string{"resource.cpu_limit", "resource.memory_limit"}, - DoubleValues: []float64{1.5, 512.0}, - IntKeys: []string{"resource.instance_id", "resource.max_connections"}, - IntValues: []int64{67890, 100}, - StrKeys: []string{"service.name", "resource.host", "resource.database_type"}, - StrValues: []string{"db-service", "db-host-1", "postgresql"}, - ComplexKeys: []string{"@bytes@resource.config"}, - ComplexValues: []string{"eyJkYl90eXBlIjoicG9zdGdyZXNxbCJ9"}, + BoolKeys: []string{"resource.persistent", "resource.pooled"}, + BoolValues: []bool{true, true}, + DoubleKeys: []string{"resource.cpu_limit", "resource.memory_limit"}, + DoubleValues: []float64{1.5, 512.0}, + IntKeys: []string{"resource.instance_id", "resource.max_connections"}, + IntValues: []int64{67890, 100}, + StrKeys: []string{"service.name", "resource.host", "resource.database_type"}, + StrValues: []string{"db-service", "db-host-1", "postgresql"}, + ComplexKeys: []string{ + "@bytes@resource.config", + "@map@metadata", + "@slice@tags", + }, + ComplexValues: []string{ + "eyJkYl90eXBlIjoicG9zdGdyZXNxbCJ9", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, }, ScopeName: "db-scope", ScopeVersion: "v1.0.0", ScopeAttributes: dbmodel.Attributes{ - BoolKeys: []string{"scope.enabled", "scope.persistent"}, - BoolValues: []bool{true, false}, - DoubleKeys: []string{"scope.version_number", "scope.priority"}, - DoubleValues: []float64{1.0, 0.8}, - IntKeys: []string{"scope.instance_count", "scope.max_spans"}, - IntValues: []int64{5, 1000}, - StrKeys: []string{"scope.environment", "scope.component"}, - StrValues: []string{"production", "database"}, - ComplexKeys: []string{"@bytes@scope.metadata"}, - ComplexValues: []string{"eyJzY29wZV90eXBlIjoiZGF0YWJhc2UifQ=="}, + BoolKeys: []string{"scope.enabled", "scope.persistent"}, + BoolValues: []bool{true, false}, + DoubleKeys: []string{"scope.version_number", "scope.priority"}, + DoubleValues: []float64{1.0, 0.8}, + IntKeys: []string{"scope.instance_count", "scope.max_spans"}, + IntValues: []int64{5, 1000}, + StrKeys: []string{"scope.environment", "scope.component"}, + StrValues: []string{"production", "database"}, + ComplexKeys: []string{ + "@bytes@scope.metadata", + "@map@metadata", + "@slice@tags", + }, + ComplexValues: []string{ + "eyJzY29wZV90eXBlIjoiZGF0YWJhc2UifQ==", + "{\"kvlistValue\":{\"values\":[{\"key\":\"key\",\"value\":{\"stringValue\":\"value\"}}]}}", + "{\"arrayValue\":{\"values\":[{\"intValue\":\"1\"},{\"intValue\":\"2\"},{\"intValue\":\"3\"}]}}", + }, }, }, }