Skip to content

Commit 5be82c0

Browse files
Added support array attributes (#798)
* Added support array attributes * Changed function signature for AsArray attribute * Fixed code comments for array attributes * Fixed typos in comments in value.go Co-authored-by: Tyler Yahn <[email protected]>
1 parent 7d631db commit 5be82c0

File tree

6 files changed

+138
-4
lines changed

6 files changed

+138
-4
lines changed

api/kv/key.go

+13
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,16 @@ func (k Key) Uint(v uint) KeyValue {
158158
func (k Key) Defined() bool {
159159
return len(k) != 0
160160
}
161+
162+
// Array creates a KeyValue instance with a ARRAY Value.
163+
//
164+
// If creating both key and a array value at the same time, then
165+
// instead of calling kv.Key(name).String(value) consider using a
166+
// convenience function provided by the api/key package -
167+
// key.Array(name, value).
168+
func (k Key) Array(v interface{}) KeyValue {
169+
return KeyValue{
170+
Key: k,
171+
Value: value.Array(v),
172+
}
173+
}

api/kv/kv.go

+8
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ func Uint(k string, v uint) KeyValue {
9595
return Key(k).Uint(v)
9696
}
9797

98+
// Array creates a new key-value pair with a passed name and a array.
99+
// Only arrays of primitive type are supported.
100+
func Array(k string, v interface{}) KeyValue {
101+
return Key(k).Array(v)
102+
}
103+
98104
// Infer creates a new key-value pair instance with a passed name and
99105
// automatic type inference. This is slower, and not type-safe.
100106
func Infer(k string, value interface{}) KeyValue {
@@ -109,6 +115,8 @@ func Infer(k string, value interface{}) KeyValue {
109115
rv := reflect.ValueOf(value)
110116

111117
switch rv.Kind() {
118+
case reflect.Array, reflect.Slice:
119+
return Array(k, value)
112120
case reflect.Bool:
113121
return Bool(k, rv.Bool())
114122
case reflect.Int, reflect.Int8, reflect.Int16:

api/kv/value/type_string.go

+3-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/kv/value/value.go

+40
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ package value
1717
import (
1818
"encoding/json"
1919
"fmt"
20+
"reflect"
2021
"strconv"
22+
"strings"
2123
"unsafe"
2224

2325
"go.opentelemetry.io/otel/api/internal"
@@ -34,6 +36,8 @@ type Value struct {
3436
numeric uint64
3537
stringly string
3638
// TODO Lazy value type?
39+
40+
array interface{}
3741
}
3842

3943
const (
@@ -46,6 +50,7 @@ const (
4650
FLOAT32 // 32 bit floating point value, use AsFloat32() to get it.
4751
FLOAT64 // 64 bit floating point value, use AsFloat64() to get it.
4852
STRING // String value, use AsString() to get it.
53+
ARRAY // Array value of arbitrary type, use AsArray() to get it.
4954
)
5055

5156
// Bool creates a BOOL Value.
@@ -130,6 +135,32 @@ func Uint(v uint) Value {
130135
return Uint64(uint64(v))
131136
}
132137

138+
// Array creates an ARRAY value.
139+
func Array(array interface{}) Value {
140+
switch reflect.TypeOf(array).Kind() {
141+
case reflect.Array, reflect.Slice:
142+
isValidType := func() bool {
143+
// get array type regardless of dimensions
144+
typeName := reflect.TypeOf(array).String()
145+
typeName = typeName[strings.LastIndex(typeName, "]")+1:]
146+
switch typeName {
147+
case "bool", "int", "int32", "int64",
148+
"float32", "float64", "string",
149+
"uint", "uint32", "uint64":
150+
return true
151+
}
152+
return false
153+
}()
154+
if isValidType {
155+
return Value{
156+
vtype: ARRAY,
157+
array: array,
158+
}
159+
}
160+
}
161+
return Value{vtype: INVALID}
162+
}
163+
133164
// Type returns a type of the Value.
134165
func (v Value) Type() Type {
135166
return v.vtype
@@ -183,11 +214,18 @@ func (v Value) AsString() string {
183214
return v.stringly
184215
}
185216

217+
// AsArray returns the array Value as an interface{}.
218+
func (v Value) AsArray() interface{} {
219+
return v.array
220+
}
221+
186222
type unknownValueType struct{}
187223

188224
// AsInterface returns Value's data as interface{}.
189225
func (v Value) AsInterface() interface{} {
190226
switch v.Type() {
227+
case ARRAY:
228+
return v.AsArray()
191229
case BOOL:
192230
return v.AsBool()
193231
case INT32:
@@ -211,6 +249,8 @@ func (v Value) AsInterface() interface{} {
211249
// Emit returns a string representation of Value's data.
212250
func (v Value) Emit() string {
213251
switch v.Type() {
252+
case ARRAY:
253+
return fmt.Sprint(v.array)
214254
case BOOL:
215255
return strconv.FormatBool(v.AsBool())
216256
case INT32:

api/kv/value/value_test.go

+66
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ func TestValue(t *testing.T) {
4040
wantType: value.BOOL,
4141
wantValue: true,
4242
},
43+
{
44+
name: "Key.Array([]bool) correctly return key's internal bool values",
45+
value: k.Array([]bool{true, false}).Value,
46+
wantType: value.ARRAY,
47+
wantValue: []bool{true, false},
48+
},
4349
{
4450
name: "Key.Int64() correctly returns keys's internal int64 value",
4551
value: k.Int64(42).Value,
@@ -94,6 +100,66 @@ func TestValue(t *testing.T) {
94100
wantType: bli.unsignedType,
95101
wantValue: bli.unsignedValue,
96102
},
103+
{
104+
name: "Key.Array([]int64) correctly returns keys's internal int64 values",
105+
value: k.Array([]int64{42, 43}).Value,
106+
wantType: value.ARRAY,
107+
wantValue: []int64{42, 43},
108+
},
109+
{
110+
name: "KeyArray([]uint64) correctly returns keys's internal uint64 values",
111+
value: k.Array([]uint64{42, 43}).Value,
112+
wantType: value.ARRAY,
113+
wantValue: []uint64{42, 43},
114+
},
115+
{
116+
name: "Key.Array([]float64) correctly returns keys's internal float64 values",
117+
value: k.Array([]float64{42, 43}).Value,
118+
wantType: value.ARRAY,
119+
wantValue: []float64{42, 43},
120+
},
121+
{
122+
name: "Key.Array([]int32) correctly returns keys's internal int32 values",
123+
value: k.Array([]int32{42, 43}).Value,
124+
wantType: value.ARRAY,
125+
wantValue: []int32{42, 43},
126+
},
127+
{
128+
name: "Key.Array([]uint32) correctly returns keys's internal uint32 values",
129+
value: k.Array([]uint32{42, 43}).Value,
130+
wantType: value.ARRAY,
131+
wantValue: []uint32{42, 43},
132+
},
133+
{
134+
name: "Key.Array([]float32) correctly returns keys's internal float32 values",
135+
value: k.Array([]float32{42, 43}).Value,
136+
wantType: value.ARRAY,
137+
wantValue: []float32{42, 43},
138+
},
139+
{
140+
name: "Key.Array([]string) correctly return key's internal string values",
141+
value: k.Array([]string{"foo", "bar"}).Value,
142+
wantType: value.ARRAY,
143+
wantValue: []string{"foo", "bar"},
144+
},
145+
{
146+
name: "Key.Array([]int) correctly returns keys's internal signed integral values",
147+
value: k.Array([]int{42, 43}).Value,
148+
wantType: value.ARRAY,
149+
wantValue: []int{42, 43},
150+
},
151+
{
152+
name: "Key.Array([]uint) correctly returns keys's internal unsigned integral values",
153+
value: k.Array([]uint{42, 43}).Value,
154+
wantType: value.ARRAY,
155+
wantValue: []uint{42, 43},
156+
},
157+
{
158+
name: "Key.Array([][]int) correctly return key's multi dimensional array",
159+
value: k.Array([][]int{{1, 2}, {3, 4}}).Value,
160+
wantType: value.ARRAY,
161+
wantValue: [][]int{{1, 2}, {3, 4}},
162+
},
97163
} {
98164
t.Logf("Running test case %s", testcase.name)
99165
if testcase.value.Type() != testcase.wantType {

sdk/trace/span.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
"go.opentelemetry.io/otel/api/global"
2828
"go.opentelemetry.io/otel/api/kv"
29+
"go.opentelemetry.io/otel/api/kv/value"
2930
apitrace "go.opentelemetry.io/otel/api/trace"
3031
export "go.opentelemetry.io/otel/sdk/export/trace"
3132
"go.opentelemetry.io/otel/sdk/internal"
@@ -103,7 +104,10 @@ func (s *span) SetAttributes(attributes ...kv.KeyValue) {
103104
}
104105

105106
func (s *span) SetAttribute(k string, v interface{}) {
106-
s.SetAttributes(kv.Infer(k, v))
107+
attr := kv.Infer(k, v)
108+
if attr.Value.Type() != value.INVALID {
109+
s.SetAttributes(attr)
110+
}
107111
}
108112

109113
func (s *span) End(options ...apitrace.EndOption) {
@@ -293,7 +297,9 @@ func (s *span) copyToCappedAttributes(attributes ...kv.KeyValue) {
293297
s.mu.Lock()
294298
defer s.mu.Unlock()
295299
for _, a := range attributes {
296-
s.attributes.add(a)
300+
if a.Value.Type() != value.INVALID {
301+
s.attributes.add(a)
302+
}
297303
}
298304
}
299305

0 commit comments

Comments
 (0)