Component(s)
pdata
Describe the issue you're reporting
Background
We aim to store the complex types (map, slice) of value within attributes as JSON safely. Currently, serializing them to JSON strings using value.AsString() leads to the risk of losing type information during deserialization. Specifically:
- All numerical values become JSON numbers, making it impossible to distinguish whether a value was originally an
int64 or a float64.
- Parsing nested
map and slice structures is particularly problematic due to their dynamic and unpredictable nesting levels.
Solution
This issue can be resolved with a minor modification. Instead of directly serializing and deserializing the high-level Value type, we will operate on the underlying otlpcommon.AnyValue type it holds. AnyValue is a Go struct generated from Protobuf definitions, which allows for a more precise representation of different data types.
Here is the code implementing this functionality:
import oteljson "go.opentelemetry.io/collector/pdata/internal/json"
import "go.opentelemetry.io/collector/pdata/internal"
import "go.opentelemetry.io/proto/otlp/common/v1"
// UnmarshalValue deserializes a JSON byte stream into a Value type.
// It uses oteljson.ReadValue to read the JSON data into an AnyValue,
// and then creates a new Value instance using the AnyValue.
func UnmarshalValue(buf []byte) Value {
iter := jsoniter.ConfigFastest.BorrowIterator(buf)
defer jsoniter.ConfigFastest.ReturnIterator(iter)
var anyValue v1.AnyValue // Using the correct Protobuf-generated AnyValue type
state := internal.StateMutable
oteljson.ReadValue(iter, &anyValue)
return newValue(&anyValue, &state)
}
// MarshalValue serializes a Value type into a JSON byte stream.
// It retrieves the underlying AnyValue using value.getOrig()
// and then uses oteljson.Marshal to serialize the AnyValue into JSON.
func MarshalValue(value Value) ([]byte, error) {
var buf bytes.Buffer
if err := oteljson.Marshal(&buf, value.getOrig()); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
Component(s)
pdata
Describe the issue you're reporting
Background
We aim to store the complex types (
map,slice) ofvaluewithinattributesas JSON safely. Currently, serializing them to JSON strings usingvalue.AsString()leads to the risk of losing type information during deserialization. Specifically:int64or afloat64.mapandslicestructures is particularly problematic due to their dynamic and unpredictable nesting levels.Solution
This issue can be resolved with a minor modification. Instead of directly serializing and deserializing the high-level
Valuetype, we will operate on the underlyingotlpcommon.AnyValuetype it holds.AnyValueis a Go struct generated from Protobuf definitions, which allows for a more precise representation of different data types.Here is the code implementing this functionality: