You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2026-06-19 21:45:50 +02:00
exporters: support MAP attributes (#8453)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/8163 Add end-to-end exporter handling for `attribute.SLICE` in the remaining paths that still treated it as invalid or relied on fallback formatting. Changes: - encode `attribute.MAP` as OTLP `AnyValue_AnyValue_KvlistValue` for trace, log, and metric transforms - serialize Zipkin `MAP` attributes using the non-OTLP AnyValue string representation
This commit is contained in:
@@ -11,6 +11,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
### Added
|
||||
|
||||
- Add `Map` and `MapValue` functions for new `MAP` attribute type in `go.opentelemetry.io/otel/attribute`. (#8445)
|
||||
- Support `MAP` attributes in `go.opentelemetry.io/otel/exporters/otlp/otlptrace`. (#8453)
|
||||
- Support `MAP` attributes in `go.opentelemetry.io/otel/exporters/otlp/otlplog`. (#8453)
|
||||
- Support `MAP` attributes in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric`. (#8453)
|
||||
- Support `MAP` attributes in `go.opentelemetry.io/otel/exporters/zipkin`. (#8453)
|
||||
- Apply `AttributeValueLengthLimit` to `attribute.MAP` type attribute values in `go.opentelemetry.io/otel/sdk/trace`, recursively truncating contained values. (#8454)
|
||||
- Add `WithUnsafeAttributes` to `go.opentelemetry.io/otel/metric/x` as an experimental no-copy attribute option intended for future performance work. This is a work in progress. (#8251)
|
||||
|
||||
|
||||
@@ -33,6 +33,18 @@ var (
|
||||
attribute.ByteSliceValue([]byte("otlp")),
|
||||
attribute.SliceValue(attribute.IntValue(2), attribute.Value{}),
|
||||
)
|
||||
attrMap = attribute.Map("map",
|
||||
attribute.String("string", "o"),
|
||||
attribute.Int("number", 2),
|
||||
attribute.ByteSlice("bytes", []byte("otlp")),
|
||||
attribute.Slice(
|
||||
"slice",
|
||||
attribute.BoolValue(true),
|
||||
attribute.MapValue(attribute.String("inner", "value")),
|
||||
),
|
||||
attribute.Map("nested", attribute.Bool("ok", true)),
|
||||
attribute.KeyValue{Key: "empty"},
|
||||
)
|
||||
attrStringSlice = attribute.StringSlice("string slice", []string{"o", "n"})
|
||||
attrEmpty = attribute.KeyValue{
|
||||
Key: attribute.Key("empty"),
|
||||
@@ -61,7 +73,10 @@ var (
|
||||
Values: []*cpb.AnyValue{valDblNOne, valDblOne},
|
||||
},
|
||||
}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrValue = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{
|
||||
StringValue: "value",
|
||||
}}
|
||||
valAttrBytes = &cpb.AnyValue{Value: &cpb.AnyValue_BytesValue{BytesValue: []byte("otlp")}}
|
||||
valSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -76,6 +91,37 @@ var (
|
||||
},
|
||||
},
|
||||
}}
|
||||
valAttrMap = &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "bytes", Value: valAttrBytes},
|
||||
{Key: "empty", Value: &cpb.AnyValue{}},
|
||||
{Key: "nested", Value: &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "ok", Value: valBoolTrue},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "number", Value: valIntTwo},
|
||||
{Key: "slice", Value: &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
Values: []*cpb.AnyValue{
|
||||
valBoolTrue,
|
||||
{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "inner", Value: valStrValue},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "string", Value: valStrO},
|
||||
},
|
||||
},
|
||||
}}
|
||||
valStrN = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "n"}}
|
||||
valStrSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -94,6 +140,7 @@ var (
|
||||
kvString = &cpb.KeyValue{Key: "string", Value: valStrO}
|
||||
kvAttrBytes = &cpb.KeyValue{Key: "bytes", Value: valAttrBytes}
|
||||
kvAttrSlice = &cpb.KeyValue{Key: "slice", Value: valSlice}
|
||||
kvAttrMap = &cpb.KeyValue{Key: "map", Value: valAttrMap}
|
||||
kvStringSlice = &cpb.KeyValue{Key: "string slice", Value: valStrSlice}
|
||||
kvEmpty = &cpb.KeyValue{Key: "empty", Value: &cpb.AnyValue{}}
|
||||
)
|
||||
@@ -168,6 +215,11 @@ func TestAttrTransforms(t *testing.T) {
|
||||
[]attribute.KeyValue{attrSlice},
|
||||
[]*cpb.KeyValue{kvAttrSlice},
|
||||
},
|
||||
{
|
||||
"map",
|
||||
[]attribute.KeyValue{attrMap},
|
||||
[]*cpb.KeyValue{kvAttrMap},
|
||||
},
|
||||
{
|
||||
"string slice",
|
||||
[]attribute.KeyValue{attrStringSlice},
|
||||
@@ -187,6 +239,7 @@ func TestAttrTransforms(t *testing.T) {
|
||||
attrString,
|
||||
attrBytes,
|
||||
attrSlice,
|
||||
attrMap,
|
||||
attrStringSlice,
|
||||
attrEmpty,
|
||||
},
|
||||
@@ -202,6 +255,7 @@ func TestAttrTransforms(t *testing.T) {
|
||||
kvString,
|
||||
kvAttrBytes,
|
||||
kvAttrSlice,
|
||||
kvAttrMap,
|
||||
kvStringSlice,
|
||||
kvEmpty,
|
||||
},
|
||||
|
||||
@@ -205,6 +205,12 @@ func AttrValue(v attribute.Value) *cpb.AnyValue {
|
||||
Values: attrValues(v.AsSlice()),
|
||||
},
|
||||
}
|
||||
case attribute.MAP:
|
||||
av.Value = &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: Attrs(v.AsMap()),
|
||||
},
|
||||
}
|
||||
case attribute.STRINGSLICE:
|
||||
av.Value = &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
|
||||
@@ -33,6 +33,18 @@ var (
|
||||
attribute.ByteSliceValue([]byte("otlp")),
|
||||
attribute.SliceValue(attribute.IntValue(2), attribute.Value{}),
|
||||
)
|
||||
attrMap = attribute.Map("map",
|
||||
attribute.String("string", "o"),
|
||||
attribute.Int("number", 2),
|
||||
attribute.ByteSlice("bytes", []byte("otlp")),
|
||||
attribute.Slice(
|
||||
"slice",
|
||||
attribute.BoolValue(true),
|
||||
attribute.MapValue(attribute.String("inner", "value")),
|
||||
),
|
||||
attribute.Map("nested", attribute.Bool("ok", true)),
|
||||
attribute.KeyValue{Key: "empty"},
|
||||
)
|
||||
attrStringSlice = attribute.StringSlice("string slice", []string{"o", "n"})
|
||||
attrEmpty = attribute.KeyValue{
|
||||
Key: attribute.Key("empty"),
|
||||
@@ -61,7 +73,10 @@ var (
|
||||
Values: []*cpb.AnyValue{valDblNOne, valDblOne},
|
||||
},
|
||||
}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrValue = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{
|
||||
StringValue: "value",
|
||||
}}
|
||||
valAttrBytes = &cpb.AnyValue{Value: &cpb.AnyValue_BytesValue{BytesValue: []byte("otlp")}}
|
||||
valSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -76,6 +91,37 @@ var (
|
||||
},
|
||||
},
|
||||
}}
|
||||
valAttrMap = &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "bytes", Value: valAttrBytes},
|
||||
{Key: "empty", Value: &cpb.AnyValue{}},
|
||||
{Key: "nested", Value: &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "ok", Value: valBoolTrue},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "number", Value: valIntTwo},
|
||||
{Key: "slice", Value: &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
Values: []*cpb.AnyValue{
|
||||
valBoolTrue,
|
||||
{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "inner", Value: valStrValue},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "string", Value: valStrO},
|
||||
},
|
||||
},
|
||||
}}
|
||||
valStrN = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "n"}}
|
||||
valStrSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -94,6 +140,7 @@ var (
|
||||
kvString = &cpb.KeyValue{Key: "string", Value: valStrO}
|
||||
kvAttrBytes = &cpb.KeyValue{Key: "bytes", Value: valAttrBytes}
|
||||
kvAttrSlice = &cpb.KeyValue{Key: "slice", Value: valSlice}
|
||||
kvAttrMap = &cpb.KeyValue{Key: "map", Value: valAttrMap}
|
||||
kvStringSlice = &cpb.KeyValue{Key: "string slice", Value: valStrSlice}
|
||||
kvEmpty = &cpb.KeyValue{Key: "empty", Value: &cpb.AnyValue{}}
|
||||
)
|
||||
@@ -168,6 +215,11 @@ func TestAttrTransforms(t *testing.T) {
|
||||
[]attribute.KeyValue{attrSlice},
|
||||
[]*cpb.KeyValue{kvAttrSlice},
|
||||
},
|
||||
{
|
||||
"map",
|
||||
[]attribute.KeyValue{attrMap},
|
||||
[]*cpb.KeyValue{kvAttrMap},
|
||||
},
|
||||
{
|
||||
"string slice",
|
||||
[]attribute.KeyValue{attrStringSlice},
|
||||
@@ -187,6 +239,7 @@ func TestAttrTransforms(t *testing.T) {
|
||||
attrString,
|
||||
attrBytes,
|
||||
attrSlice,
|
||||
attrMap,
|
||||
attrStringSlice,
|
||||
attrEmpty,
|
||||
},
|
||||
@@ -202,6 +255,7 @@ func TestAttrTransforms(t *testing.T) {
|
||||
kvString,
|
||||
kvAttrBytes,
|
||||
kvAttrSlice,
|
||||
kvAttrMap,
|
||||
kvStringSlice,
|
||||
kvEmpty,
|
||||
},
|
||||
|
||||
@@ -205,6 +205,12 @@ func AttrValue(v attribute.Value) *cpb.AnyValue {
|
||||
Values: attrValues(v.AsSlice()),
|
||||
},
|
||||
}
|
||||
case attribute.MAP:
|
||||
av.Value = &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: Attrs(v.AsMap()),
|
||||
},
|
||||
}
|
||||
case attribute.STRINGSLICE:
|
||||
av.Value = &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
|
||||
@@ -91,6 +91,12 @@ func Value(v attribute.Value) *cpb.AnyValue {
|
||||
Values: attrValues(v.AsSlice()),
|
||||
},
|
||||
}
|
||||
case attribute.MAP:
|
||||
av.Value = &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: KeyValues(v.AsMap()),
|
||||
},
|
||||
}
|
||||
case attribute.STRINGSLICE:
|
||||
av.Value = &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
|
||||
@@ -33,6 +33,18 @@ var (
|
||||
attribute.ByteSliceValue([]byte("otlp")),
|
||||
attribute.SliceValue(attribute.IntValue(2), attribute.Value{}),
|
||||
)
|
||||
attrMap = attribute.Map("map",
|
||||
attribute.String("string", "o"),
|
||||
attribute.Int("number", 2),
|
||||
attribute.ByteSlice("bytes", []byte("otlp")),
|
||||
attribute.Slice(
|
||||
"slice",
|
||||
attribute.BoolValue(true),
|
||||
attribute.MapValue(attribute.String("inner", "value")),
|
||||
),
|
||||
attribute.Map("nested", attribute.Bool("ok", true)),
|
||||
attribute.KeyValue{Key: "empty"},
|
||||
)
|
||||
attrStringSlice = attribute.StringSlice("string slice", []string{"o", "n"})
|
||||
attrEmpty = attribute.KeyValue{
|
||||
Key: attribute.Key("empty"),
|
||||
@@ -61,7 +73,10 @@ var (
|
||||
Values: []*cpb.AnyValue{valDblNOne, valDblOne},
|
||||
},
|
||||
}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrValue = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{
|
||||
StringValue: "value",
|
||||
}}
|
||||
valBytes = &cpb.AnyValue{Value: &cpb.AnyValue_BytesValue{BytesValue: []byte("otlp")}}
|
||||
valSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -76,6 +91,37 @@ var (
|
||||
},
|
||||
},
|
||||
}}
|
||||
valMap = &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "bytes", Value: valBytes},
|
||||
{Key: "empty", Value: &cpb.AnyValue{}},
|
||||
{Key: "nested", Value: &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "ok", Value: valBoolTrue},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "number", Value: valIntTwo},
|
||||
{Key: "slice", Value: &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
Values: []*cpb.AnyValue{
|
||||
valBoolTrue,
|
||||
{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "inner", Value: valStrValue},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "string", Value: valStrO},
|
||||
},
|
||||
},
|
||||
}}
|
||||
valStrN = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "n"}}
|
||||
valStrSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -94,6 +140,7 @@ var (
|
||||
kvString = &cpb.KeyValue{Key: "string", Value: valStrO}
|
||||
kvBytes = &cpb.KeyValue{Key: "bytes", Value: valBytes}
|
||||
kvSlice = &cpb.KeyValue{Key: "slice", Value: valSlice}
|
||||
kvMap = &cpb.KeyValue{Key: "map", Value: valMap}
|
||||
kvStringSlice = &cpb.KeyValue{Key: "string slice", Value: valStrSlice}
|
||||
kvEmpty = &cpb.KeyValue{Key: "empty", Value: &cpb.AnyValue{}}
|
||||
)
|
||||
@@ -168,6 +215,11 @@ func TestAttributeTransforms(t *testing.T) {
|
||||
[]attribute.KeyValue{attrSlice},
|
||||
[]*cpb.KeyValue{kvSlice},
|
||||
},
|
||||
{
|
||||
"map",
|
||||
[]attribute.KeyValue{attrMap},
|
||||
[]*cpb.KeyValue{kvMap},
|
||||
},
|
||||
{
|
||||
"string slice",
|
||||
[]attribute.KeyValue{attrStringSlice},
|
||||
@@ -187,6 +239,7 @@ func TestAttributeTransforms(t *testing.T) {
|
||||
attrString,
|
||||
attrBytes,
|
||||
attrSlice,
|
||||
attrMap,
|
||||
attrStringSlice,
|
||||
attrEmpty,
|
||||
},
|
||||
@@ -202,6 +255,7 @@ func TestAttributeTransforms(t *testing.T) {
|
||||
kvString,
|
||||
kvBytes,
|
||||
kvSlice,
|
||||
kvMap,
|
||||
kvStringSlice,
|
||||
kvEmpty,
|
||||
},
|
||||
|
||||
@@ -91,6 +91,12 @@ func Value(v attribute.Value) *cpb.AnyValue {
|
||||
Values: attrValues(v.AsSlice()),
|
||||
},
|
||||
}
|
||||
case attribute.MAP:
|
||||
av.Value = &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: KeyValues(v.AsMap()),
|
||||
},
|
||||
}
|
||||
case attribute.STRINGSLICE:
|
||||
av.Value = &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
|
||||
@@ -33,6 +33,18 @@ var (
|
||||
attribute.ByteSliceValue([]byte("otlp")),
|
||||
attribute.SliceValue(attribute.IntValue(2), attribute.Value{}),
|
||||
)
|
||||
attrMap = attribute.Map("map",
|
||||
attribute.String("string", "o"),
|
||||
attribute.Int("number", 2),
|
||||
attribute.ByteSlice("bytes", []byte("otlp")),
|
||||
attribute.Slice(
|
||||
"slice",
|
||||
attribute.BoolValue(true),
|
||||
attribute.MapValue(attribute.String("inner", "value")),
|
||||
),
|
||||
attribute.Map("nested", attribute.Bool("ok", true)),
|
||||
attribute.KeyValue{Key: "empty"},
|
||||
)
|
||||
attrStringSlice = attribute.StringSlice("string slice", []string{"o", "n"})
|
||||
attrEmpty = attribute.KeyValue{
|
||||
Key: attribute.Key("empty"),
|
||||
@@ -61,7 +73,10 @@ var (
|
||||
Values: []*cpb.AnyValue{valDblNOne, valDblOne},
|
||||
},
|
||||
}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrValue = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{
|
||||
StringValue: "value",
|
||||
}}
|
||||
valBytes = &cpb.AnyValue{Value: &cpb.AnyValue_BytesValue{BytesValue: []byte("otlp")}}
|
||||
valSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -76,6 +91,37 @@ var (
|
||||
},
|
||||
},
|
||||
}}
|
||||
valMap = &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "bytes", Value: valBytes},
|
||||
{Key: "empty", Value: &cpb.AnyValue{}},
|
||||
{Key: "nested", Value: &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "ok", Value: valBoolTrue},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "number", Value: valIntTwo},
|
||||
{Key: "slice", Value: &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
Values: []*cpb.AnyValue{
|
||||
valBoolTrue,
|
||||
{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "inner", Value: valStrValue},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "string", Value: valStrO},
|
||||
},
|
||||
},
|
||||
}}
|
||||
valStrN = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "n"}}
|
||||
valStrSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -94,6 +140,7 @@ var (
|
||||
kvString = &cpb.KeyValue{Key: "string", Value: valStrO}
|
||||
kvBytes = &cpb.KeyValue{Key: "bytes", Value: valBytes}
|
||||
kvSlice = &cpb.KeyValue{Key: "slice", Value: valSlice}
|
||||
kvMap = &cpb.KeyValue{Key: "map", Value: valMap}
|
||||
kvStringSlice = &cpb.KeyValue{Key: "string slice", Value: valStrSlice}
|
||||
kvEmpty = &cpb.KeyValue{Key: "empty", Value: &cpb.AnyValue{}}
|
||||
)
|
||||
@@ -168,6 +215,11 @@ func TestAttributeTransforms(t *testing.T) {
|
||||
[]attribute.KeyValue{attrSlice},
|
||||
[]*cpb.KeyValue{kvSlice},
|
||||
},
|
||||
{
|
||||
"map",
|
||||
[]attribute.KeyValue{attrMap},
|
||||
[]*cpb.KeyValue{kvMap},
|
||||
},
|
||||
{
|
||||
"string slice",
|
||||
[]attribute.KeyValue{attrStringSlice},
|
||||
@@ -187,6 +239,7 @@ func TestAttributeTransforms(t *testing.T) {
|
||||
attrString,
|
||||
attrBytes,
|
||||
attrSlice,
|
||||
attrMap,
|
||||
attrStringSlice,
|
||||
attrEmpty,
|
||||
},
|
||||
@@ -202,6 +255,7 @@ func TestAttributeTransforms(t *testing.T) {
|
||||
kvString,
|
||||
kvBytes,
|
||||
kvSlice,
|
||||
kvMap,
|
||||
kvStringSlice,
|
||||
kvEmpty,
|
||||
},
|
||||
|
||||
@@ -97,6 +97,12 @@ func Value(v attribute.Value) *commonpb.AnyValue {
|
||||
Values: values(v.AsSlice()),
|
||||
},
|
||||
}
|
||||
case attribute.MAP:
|
||||
av.Value = &commonpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &commonpb.KeyValueList{
|
||||
Values: KeyValues(v.AsMap()),
|
||||
},
|
||||
}
|
||||
case attribute.STRINGSLICE:
|
||||
av.Value = &commonpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &commonpb.ArrayValue{
|
||||
|
||||
@@ -33,6 +33,19 @@ func TestAttributes(t *testing.T) {
|
||||
attribute.ByteSliceValue([]byte("bytes")),
|
||||
attribute.SliceValue(attribute.IntValue(2), attribute.Value{}),
|
||||
),
|
||||
attribute.Map(
|
||||
"map to kvlist",
|
||||
attribute.String("string", "string"),
|
||||
attribute.Int("number", 2),
|
||||
attribute.ByteSlice("bytes", []byte("bytes")),
|
||||
attribute.Slice(
|
||||
"slice",
|
||||
attribute.BoolValue(true),
|
||||
attribute.MapValue(attribute.String("inner", "value")),
|
||||
),
|
||||
attribute.Map("nested", attribute.Bool("ok", true)),
|
||||
attribute.KeyValue{Key: "empty"},
|
||||
),
|
||||
attribute.Bool("bool to bool", true),
|
||||
{Key: "empty to empty"},
|
||||
},
|
||||
@@ -112,6 +125,96 @@ func TestAttributes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "map to kvlist",
|
||||
Value: &commonpb.AnyValue{
|
||||
Value: &commonpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &commonpb.KeyValueList{
|
||||
Values: []*commonpb.KeyValue{
|
||||
{
|
||||
Key: "bytes",
|
||||
Value: &commonpb.AnyValue{
|
||||
Value: &commonpb.AnyValue_BytesValue{
|
||||
BytesValue: []byte("bytes"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "empty",
|
||||
Value: &commonpb.AnyValue{},
|
||||
},
|
||||
{
|
||||
Key: "nested",
|
||||
Value: &commonpb.AnyValue{
|
||||
Value: &commonpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &commonpb.KeyValueList{
|
||||
Values: []*commonpb.KeyValue{
|
||||
{
|
||||
Key: "ok",
|
||||
Value: &commonpb.AnyValue{
|
||||
Value: &commonpb.AnyValue_BoolValue{
|
||||
BoolValue: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "number",
|
||||
Value: &commonpb.AnyValue{
|
||||
Value: &commonpb.AnyValue_IntValue{
|
||||
IntValue: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "slice",
|
||||
Value: &commonpb.AnyValue{
|
||||
Value: &commonpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &commonpb.ArrayValue{
|
||||
Values: []*commonpb.AnyValue{
|
||||
{
|
||||
Value: &commonpb.AnyValue_BoolValue{
|
||||
BoolValue: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Value: &commonpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &commonpb.KeyValueList{
|
||||
Values: []*commonpb.KeyValue{
|
||||
{
|
||||
Key: "inner",
|
||||
Value: &commonpb.AnyValue{
|
||||
Value: &commonpb.AnyValue_StringValue{
|
||||
StringValue: "value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "string",
|
||||
Value: &commonpb.AnyValue{
|
||||
Value: &commonpb.AnyValue_StringValue{
|
||||
StringValue: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: "bool to bool",
|
||||
Value: &commonpb.AnyValue{
|
||||
|
||||
@@ -182,10 +182,10 @@ func attributeToStringPair(kv attribute.KeyValue) (string, string) {
|
||||
}
|
||||
encoded, _ := json.Marshal(data)
|
||||
return string(kv.Key), string(encoded)
|
||||
case attribute.SLICE:
|
||||
case attribute.SLICE, attribute.MAP:
|
||||
// Note that this is a best effort support as this exporter is already deprecated.
|
||||
// Yet, we want to preserve other existing behavior as much as possible.
|
||||
// Emit the slice using the non-OTLP AnyValue string representation.
|
||||
// Emit the value using the non-OTLP AnyValue string representation.
|
||||
// Some values will be emitted differently than the specific types above.
|
||||
return string(kv.Key), kv.Value.String()
|
||||
default:
|
||||
|
||||
@@ -1003,6 +1003,29 @@ func TestAttributeToStringPairSlice(t *testing.T) {
|
||||
assert.Equal(t, `[true,"Ymlu",[2,null]]`, v)
|
||||
}
|
||||
|
||||
func TestAttributeToStringPairMap(t *testing.T) {
|
||||
k, v := attributeToStringPair(attribute.Map(
|
||||
"map",
|
||||
attribute.String("string", "o"),
|
||||
attribute.Int("number", 2),
|
||||
attribute.ByteSlice("bytes", []byte("bin")),
|
||||
attribute.Slice(
|
||||
"slice",
|
||||
attribute.BoolValue(true),
|
||||
attribute.MapValue(attribute.String("inner", "value")),
|
||||
),
|
||||
attribute.Map("nested", attribute.Bool("ok", true)),
|
||||
attribute.KeyValue{Key: "empty"},
|
||||
))
|
||||
|
||||
assert.Equal(t, "map", k)
|
||||
assert.JSONEq(
|
||||
t,
|
||||
`{"bytes":"Ymlu","empty":null,"nested":{"ok":true},"number":2,"slice":[true,{"inner":"value"}],"string":"o"}`,
|
||||
v,
|
||||
)
|
||||
}
|
||||
|
||||
func zkmodelIDPtr(n uint64) *zkmodel.ID {
|
||||
id := zkmodel.ID(n)
|
||||
return &id
|
||||
|
||||
@@ -33,6 +33,18 @@ var (
|
||||
attribute.ByteSliceValue([]byte("otlp")),
|
||||
attribute.SliceValue(attribute.IntValue(2), attribute.Value{}),
|
||||
)
|
||||
attrMap = attribute.Map("map",
|
||||
attribute.String("string", "o"),
|
||||
attribute.Int("number", 2),
|
||||
attribute.ByteSlice("bytes", []byte("otlp")),
|
||||
attribute.Slice(
|
||||
"slice",
|
||||
attribute.BoolValue(true),
|
||||
attribute.MapValue(attribute.String("inner", "value")),
|
||||
),
|
||||
attribute.Map("nested", attribute.Bool("ok", true)),
|
||||
attribute.KeyValue{Key: "empty"},
|
||||
)
|
||||
attrStringSlice = attribute.StringSlice("string slice", []string{"o", "n"})
|
||||
attrEmpty = attribute.KeyValue{
|
||||
Key: attribute.Key("empty"),
|
||||
@@ -61,7 +73,10 @@ var (
|
||||
Values: []*cpb.AnyValue{valDblNOne, valDblOne},
|
||||
},
|
||||
}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrValue = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{
|
||||
StringValue: "value",
|
||||
}}
|
||||
valAttrBytes = &cpb.AnyValue{Value: &cpb.AnyValue_BytesValue{BytesValue: []byte("otlp")}}
|
||||
valSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -76,6 +91,37 @@ var (
|
||||
},
|
||||
},
|
||||
}}
|
||||
valAttrMap = &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "bytes", Value: valAttrBytes},
|
||||
{Key: "empty", Value: &cpb.AnyValue{}},
|
||||
{Key: "nested", Value: &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "ok", Value: valBoolTrue},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "number", Value: valIntTwo},
|
||||
{Key: "slice", Value: &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
Values: []*cpb.AnyValue{
|
||||
valBoolTrue,
|
||||
{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "inner", Value: valStrValue},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "string", Value: valStrO},
|
||||
},
|
||||
},
|
||||
}}
|
||||
valStrN = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "n"}}
|
||||
valStrSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -94,6 +140,7 @@ var (
|
||||
kvString = &cpb.KeyValue{Key: "string", Value: valStrO}
|
||||
kvAttrBytes = &cpb.KeyValue{Key: "bytes", Value: valAttrBytes}
|
||||
kvAttrSlice = &cpb.KeyValue{Key: "slice", Value: valSlice}
|
||||
kvAttrMap = &cpb.KeyValue{Key: "map", Value: valAttrMap}
|
||||
kvStringSlice = &cpb.KeyValue{Key: "string slice", Value: valStrSlice}
|
||||
kvEmpty = &cpb.KeyValue{Key: "empty", Value: &cpb.AnyValue{}}
|
||||
)
|
||||
@@ -168,6 +215,11 @@ func TestAttrTransforms(t *testing.T) {
|
||||
[]attribute.KeyValue{attrSlice},
|
||||
[]*cpb.KeyValue{kvAttrSlice},
|
||||
},
|
||||
{
|
||||
"map",
|
||||
[]attribute.KeyValue{attrMap},
|
||||
[]*cpb.KeyValue{kvAttrMap},
|
||||
},
|
||||
{
|
||||
"string slice",
|
||||
[]attribute.KeyValue{attrStringSlice},
|
||||
@@ -187,6 +239,7 @@ func TestAttrTransforms(t *testing.T) {
|
||||
attrString,
|
||||
attrBytes,
|
||||
attrSlice,
|
||||
attrMap,
|
||||
attrStringSlice,
|
||||
attrEmpty,
|
||||
},
|
||||
@@ -202,6 +255,7 @@ func TestAttrTransforms(t *testing.T) {
|
||||
kvString,
|
||||
kvAttrBytes,
|
||||
kvAttrSlice,
|
||||
kvAttrMap,
|
||||
kvStringSlice,
|
||||
kvEmpty,
|
||||
},
|
||||
|
||||
@@ -205,6 +205,12 @@ func AttrValue(v attribute.Value) *cpb.AnyValue {
|
||||
Values: attrValues(v.AsSlice()),
|
||||
},
|
||||
}
|
||||
case attribute.MAP:
|
||||
av.Value = &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: Attrs(v.AsMap()),
|
||||
},
|
||||
}
|
||||
case attribute.STRINGSLICE:
|
||||
av.Value = &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
|
||||
@@ -91,6 +91,12 @@ func Value(v attribute.Value) *cpb.AnyValue {
|
||||
Values: attrValues(v.AsSlice()),
|
||||
},
|
||||
}
|
||||
case attribute.MAP:
|
||||
av.Value = &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: KeyValues(v.AsMap()),
|
||||
},
|
||||
}
|
||||
case attribute.STRINGSLICE:
|
||||
av.Value = &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
|
||||
@@ -33,6 +33,18 @@ var (
|
||||
attribute.ByteSliceValue([]byte("otlp")),
|
||||
attribute.SliceValue(attribute.IntValue(2), attribute.Value{}),
|
||||
)
|
||||
attrMap = attribute.Map("map",
|
||||
attribute.String("string", "o"),
|
||||
attribute.Int("number", 2),
|
||||
attribute.ByteSlice("bytes", []byte("otlp")),
|
||||
attribute.Slice(
|
||||
"slice",
|
||||
attribute.BoolValue(true),
|
||||
attribute.MapValue(attribute.String("inner", "value")),
|
||||
),
|
||||
attribute.Map("nested", attribute.Bool("ok", true)),
|
||||
attribute.KeyValue{Key: "empty"},
|
||||
)
|
||||
attrStringSlice = attribute.StringSlice("string slice", []string{"o", "n"})
|
||||
attrEmpty = attribute.KeyValue{
|
||||
Key: attribute.Key("empty"),
|
||||
@@ -61,7 +73,10 @@ var (
|
||||
Values: []*cpb.AnyValue{valDblNOne, valDblOne},
|
||||
},
|
||||
}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrO = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "o"}}
|
||||
valStrValue = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{
|
||||
StringValue: "value",
|
||||
}}
|
||||
valBytes = &cpb.AnyValue{Value: &cpb.AnyValue_BytesValue{BytesValue: []byte("otlp")}}
|
||||
valSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -76,6 +91,37 @@ var (
|
||||
},
|
||||
},
|
||||
}}
|
||||
valMap = &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "bytes", Value: valBytes},
|
||||
{Key: "empty", Value: &cpb.AnyValue{}},
|
||||
{Key: "nested", Value: &cpb.AnyValue{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "ok", Value: valBoolTrue},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "number", Value: valIntTwo},
|
||||
{Key: "slice", Value: &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
Values: []*cpb.AnyValue{
|
||||
valBoolTrue,
|
||||
{Value: &cpb.AnyValue_KvlistValue{
|
||||
KvlistValue: &cpb.KeyValueList{
|
||||
Values: []*cpb.KeyValue{
|
||||
{Key: "inner", Value: valStrValue},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}}},
|
||||
{Key: "string", Value: valStrO},
|
||||
},
|
||||
},
|
||||
}}
|
||||
valStrN = &cpb.AnyValue{Value: &cpb.AnyValue_StringValue{StringValue: "n"}}
|
||||
valStrSlice = &cpb.AnyValue{Value: &cpb.AnyValue_ArrayValue{
|
||||
ArrayValue: &cpb.ArrayValue{
|
||||
@@ -94,6 +140,7 @@ var (
|
||||
kvString = &cpb.KeyValue{Key: "string", Value: valStrO}
|
||||
kvBytes = &cpb.KeyValue{Key: "bytes", Value: valBytes}
|
||||
kvSlice = &cpb.KeyValue{Key: "slice", Value: valSlice}
|
||||
kvMap = &cpb.KeyValue{Key: "map", Value: valMap}
|
||||
kvStringSlice = &cpb.KeyValue{Key: "string slice", Value: valStrSlice}
|
||||
kvEmpty = &cpb.KeyValue{Key: "empty", Value: &cpb.AnyValue{}}
|
||||
)
|
||||
@@ -168,6 +215,11 @@ func TestAttributeTransforms(t *testing.T) {
|
||||
[]attribute.KeyValue{attrSlice},
|
||||
[]*cpb.KeyValue{kvSlice},
|
||||
},
|
||||
{
|
||||
"map",
|
||||
[]attribute.KeyValue{attrMap},
|
||||
[]*cpb.KeyValue{kvMap},
|
||||
},
|
||||
{
|
||||
"string slice",
|
||||
[]attribute.KeyValue{attrStringSlice},
|
||||
@@ -187,6 +239,7 @@ func TestAttributeTransforms(t *testing.T) {
|
||||
attrString,
|
||||
attrBytes,
|
||||
attrSlice,
|
||||
attrMap,
|
||||
attrStringSlice,
|
||||
attrEmpty,
|
||||
},
|
||||
@@ -202,6 +255,7 @@ func TestAttributeTransforms(t *testing.T) {
|
||||
kvString,
|
||||
kvBytes,
|
||||
kvSlice,
|
||||
kvMap,
|
||||
kvStringSlice,
|
||||
kvEmpty,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user