@@ -19,6 +19,7 @@ import (
19
19
"fmt"
20
20
"reflect"
21
21
"sort"
22
+ "strconv"
22
23
23
24
ocmetricdata "go.opencensus.io/metric/metricdata"
24
25
octrace "go.opencensus.io/trace"
@@ -28,13 +29,12 @@ import (
28
29
)
29
30
30
31
var (
31
- errAggregationType = errors .New ("unsupported OpenCensus aggregation type" )
32
- errMismatchedValueTypes = errors .New ("wrong value type for data point" )
33
- errNegativeDistributionCount = errors .New ("distribution count is negative" )
34
- errNegativeBucketCount = errors .New ("distribution bucket count is negative" )
35
- errMismatchedAttributeKeyValues = errors .New ("mismatched number of attribute keys and values" )
36
- errInvalidExemplarSpanContext = errors .New ("span context exemplar attachment does not contain an OpenCensus SpanContext" )
37
- errInvalidExemplarAttachmentValue = errors .New ("exemplar attachment is not a supported OpenTelemetry attribute type" )
32
+ errAggregationType = errors .New ("unsupported OpenCensus aggregation type" )
33
+ errMismatchedValueTypes = errors .New ("wrong value type for data point" )
34
+ errNegativeDistributionCount = errors .New ("distribution count is negative" )
35
+ errNegativeBucketCount = errors .New ("distribution bucket count is negative" )
36
+ errMismatchedAttributeKeyValues = errors .New ("mismatched number of attribute keys and values" )
37
+ errInvalidExemplarSpanContext = errors .New ("span context exemplar attachment does not contain an OpenCensus SpanContext" )
38
38
)
39
39
40
40
// ConvertMetrics converts metric data from OpenCensus to OpenTelemetry.
@@ -206,12 +206,7 @@ func convertExemplar(ocExemplar *ocmetricdata.Exemplar) (metricdata.Exemplar[flo
206
206
exemplar .SpanID = sc .SpanID [:]
207
207
exemplar .TraceID = sc .TraceID [:]
208
208
default :
209
- kv := convertKV (k , v )
210
- if ! kv .Valid () {
211
- err = errors .Join (err , fmt .Errorf ("%w; type: %v" , errInvalidExemplarAttachmentValue , reflect .TypeOf (v )))
212
- continue
213
- }
214
- exemplar .FilteredAttributes = append (exemplar .FilteredAttributes , kv )
209
+ exemplar .FilteredAttributes = append (exemplar .FilteredAttributes , convertKV (k , v ))
215
210
}
216
211
}
217
212
sortable := attribute .Sortable (exemplar .FilteredAttributes )
@@ -224,28 +219,125 @@ func convertKV(key string, value any) attribute.KeyValue {
224
219
switch typedVal := value .(type ) {
225
220
case bool :
226
221
return attribute .Bool (key , typedVal )
227
- case []bool :
228
- return attribute .BoolSlice (key , typedVal )
229
222
case int :
230
223
return attribute .Int (key , typedVal )
231
- case []int :
232
- return attribute .IntSlice (key , typedVal )
224
+ case int8 :
225
+ return attribute .Int (key , int (typedVal ))
226
+ case int16 :
227
+ return attribute .Int (key , int (typedVal ))
228
+ case int32 :
229
+ return attribute .Int (key , int (typedVal ))
233
230
case int64 :
234
231
return attribute .Int64 (key , typedVal )
235
- case []int64 :
236
- return attribute .Int64Slice (key , typedVal )
232
+ case uint :
233
+ return uintKV (key , typedVal )
234
+ case uint8 :
235
+ return uintKV (key , uint (typedVal ))
236
+ case uint16 :
237
+ return uintKV (key , uint (typedVal ))
238
+ case uint32 :
239
+ return uintKV (key , uint (typedVal ))
240
+ case uintptr :
241
+ return uint64KV (key , uint64 (typedVal ))
242
+ case uint64 :
243
+ return uint64KV (key , uint64 (typedVal ))
244
+ case float32 :
245
+ return attribute .Float64 (key , float64 (typedVal ))
237
246
case float64 :
238
247
return attribute .Float64 (key , typedVal )
239
- case []float64 :
240
- return attribute .Float64Slice (key , typedVal )
248
+ case complex64 :
249
+ return attribute .String (key , complexToString (typedVal ))
250
+ case complex128 :
251
+ return attribute .String (key , complexToString (typedVal ))
241
252
case string :
242
253
return attribute .String (key , typedVal )
254
+ case []bool :
255
+ return attribute .BoolSlice (key , typedVal )
256
+ case []int :
257
+ return attribute .IntSlice (key , typedVal )
258
+ case []int8 :
259
+ return intSliceKV (key , typedVal )
260
+ case []int16 :
261
+ return intSliceKV (key , typedVal )
262
+ case []int32 :
263
+ return intSliceKV (key , typedVal )
264
+ case []int64 :
265
+ return attribute .Int64Slice (key , typedVal )
266
+ case []uint :
267
+ return uintSliceKV (key , typedVal )
268
+ case []uint8 :
269
+ return uintSliceKV (key , typedVal )
270
+ case []uint16 :
271
+ return uintSliceKV (key , typedVal )
272
+ case []uint32 :
273
+ return uintSliceKV (key , typedVal )
274
+ case []uintptr :
275
+ return uintSliceKV (key , typedVal )
276
+ case []uint64 :
277
+ return uintSliceKV (key , typedVal )
278
+ case []float32 :
279
+ floatSlice := make ([]float64 , len (typedVal ))
280
+ for i := range typedVal {
281
+ floatSlice [i ] = float64 (typedVal [i ])
282
+ }
283
+ return attribute .Float64Slice (key , floatSlice )
284
+ case []float64 :
285
+ return attribute .Float64Slice (key , typedVal )
286
+ case []complex64 :
287
+ return complexSliceKV (key , typedVal )
288
+ case []complex128 :
289
+ return complexSliceKV (key , typedVal )
243
290
case []string :
244
291
return attribute .StringSlice (key , typedVal )
245
292
case fmt.Stringer :
246
293
return attribute .Stringer (key , typedVal )
294
+ default :
295
+ return attribute .String (key , fmt .Sprintf ("unhandled attribute value: %+v" , value ))
296
+ }
297
+ }
298
+
299
+ func intSliceKV [N int8 | int16 | int32 ](key string , val []N ) attribute.KeyValue {
300
+ intSlice := make ([]int , len (val ))
301
+ for i := range val {
302
+ intSlice [i ] = int (val [i ])
303
+ }
304
+ return attribute .IntSlice (key , intSlice )
305
+ }
306
+
307
+ func uintKV (key string , val uint ) attribute.KeyValue {
308
+ const maxInt = ^ uint (0 ) >> 1
309
+ if val > maxInt {
310
+ return uint64KV (key , uint64 (val ))
311
+ }
312
+ return attribute .Int (key , int (val ))
313
+ }
314
+
315
+ func uintSliceKV [N uint | uint8 | uint16 | uint32 | uint64 | uintptr ](key string , val []N ) attribute.KeyValue {
316
+ strSlice := make ([]string , len (val ))
317
+ for i := range val {
318
+ strSlice [i ] = strconv .FormatUint (uint64 (val [i ]), 10 )
247
319
}
248
- return attribute.KeyValue {}
320
+ return attribute .StringSlice (key , strSlice )
321
+ }
322
+
323
+ func uint64KV (key string , val uint64 ) attribute.KeyValue {
324
+ const maxInt64 = ^ uint64 (0 ) >> 1
325
+ if val > maxInt64 {
326
+ return attribute .String (key , strconv .FormatUint (val , 10 ))
327
+ }
328
+ return attribute .Int64 (key , int64 (val ))
329
+ }
330
+
331
+ func complexSliceKV [N complex64 | complex128 ](key string , val []N ) attribute.KeyValue {
332
+ strSlice := make ([]string , len (val ))
333
+ for i := range val {
334
+ strSlice [i ] = complexToString (val [i ])
335
+ }
336
+ return attribute .StringSlice (key , strSlice )
337
+ }
338
+
339
+ func complexToString [N complex64 | complex128 ](val N ) string {
340
+ return strconv .FormatComplex (complex128 (val ), 'f' , - 1 , 64 )
249
341
}
250
342
251
343
// convertAttrs converts from OpenCensus attribute keys and values to an
0 commit comments