Skip to content

Commit 0da1f11

Browse files
author
Razvan Rotari
committed
When deserializing JSON, accept both int and string in 'intValue' field of
AnyValue
1 parent 0303a38 commit 0da1f11

File tree

2 files changed

+109
-58
lines changed

2 files changed

+109
-58
lines changed

opentelemetry-proto/src/proto.rs

+79-58
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use serde::Deserialize;
2+
13
/// provide serde support for proto traceIds and spanIds.
24
/// Those are hex encoded strings in the jsons but they are byte arrays in the proto.
35
/// See https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding for more details
@@ -74,76 +76,95 @@ pub(crate) mod serializers {
7476
}
7577

7678
pub fn deserialize_from_value<'de, D>(deserializer: D) -> Result<Option<AnyValue>, D::Error>
77-
where
78-
D: Deserializer<'de>,
79-
{
80-
struct ValueVisitor;
79+
where
80+
D: Deserializer<'de>,
81+
{
82+
struct ValueVisitor;
8183

82-
impl<'de> de::Visitor<'de> for ValueVisitor {
83-
type Value = AnyValue;
84+
#[derive(Deserialize)]
85+
#[serde(untagged)]
86+
enum StringOrInt {
87+
Int(i64),
88+
String(String),
89+
}
8490

85-
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
86-
formatter.write_str("a JSON object for AnyValue")
91+
impl StringOrInt {
92+
fn get_int<'de, V>(&self) -> Result<i64, V::Error>
93+
where
94+
V: de::MapAccess<'de>,
95+
{
96+
match self {
97+
Self::Int(val) => Ok(*val),
98+
Self::String(val) => Ok(val.parse::<i64>().map_err(de::Error::custom)?),
99+
}
100+
}
87101
}
88102

89-
fn visit_map<V>(self, mut map: V) -> Result<AnyValue, V::Error>
90-
where
91-
V: de::MapAccess<'de>,
92-
{
93-
let mut value: Option<any_value::Value> = None;
103+
impl<'de> de::Visitor<'de> for ValueVisitor {
104+
type Value = AnyValue;
105+
106+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
107+
formatter.write_str("a JSON object for AnyValue")
108+
}
109+
110+
fn visit_map<V>(self, mut map: V) -> Result<AnyValue, V::Error>
111+
where
112+
V: de::MapAccess<'de>,
113+
{
114+
let mut value: Option<any_value::Value> = None;
94115

95-
while let Some(key) = map.next_key::<String>()? {
96-
let key_str = key.as_str();
97-
match key_str {
98-
"stringValue" => {
99-
let s = map.next_value()?;
100-
value = Some(any_value::Value::StringValue(s));
101-
},
102-
"boolValue" => {
103-
let b = map.next_value()?;
104-
value = Some(any_value::Value::BoolValue(b));
105-
},
106-
"intValue" => {
107-
let value_str = map.next_value::<String>()?;
108-
let int_value = value_str.parse::<i64>()
109-
.map_err(de::Error::custom)?;
110-
value = Some(any_value::Value::IntValue(int_value));
111-
},
112-
"doubleValue" => {
113-
let d = map.next_value()?;
114-
value = Some(any_value::Value::DoubleValue(d));
115-
},
116-
"arrayValue" => {
117-
let a = map.next_value()?;
118-
value = Some(any_value::Value::ArrayValue(a));
119-
},
120-
"kvlistValue" => {
121-
let kv = map.next_value()?;
122-
value = Some(any_value::Value::KvlistValue(kv));
123-
},
124-
"bytesValue" => {
125-
let bytes = map.next_value()?;
126-
value = Some(any_value::Value::BytesValue(bytes));
127-
},
128-
_ => {
129-
//skip unknown keys, and handle error later.
130-
continue
116+
while let Some(key) = map.next_key::<String>()? {
117+
let key_str = key.as_str();
118+
match key_str {
119+
"stringValue" => {
120+
let s = map.next_value()?;
121+
value = Some(any_value::Value::StringValue(s));
122+
}
123+
"boolValue" => {
124+
let b = map.next_value()?;
125+
value = Some(any_value::Value::BoolValue(b));
126+
}
127+
"intValue" => {
128+
let int_value = map.next_value::<StringOrInt>()?.get_int::<V>()?;
129+
value = Some(any_value::Value::IntValue(int_value));
130+
}
131+
"doubleValue" => {
132+
let d = map.next_value()?;
133+
value = Some(any_value::Value::DoubleValue(d));
134+
}
135+
"arrayValue" => {
136+
let a = map.next_value()?;
137+
value = Some(any_value::Value::ArrayValue(a));
138+
}
139+
"kvlistValue" => {
140+
let kv = map.next_value()?;
141+
value = Some(any_value::Value::KvlistValue(kv));
142+
}
143+
"bytesValue" => {
144+
let bytes = map.next_value()?;
145+
value = Some(any_value::Value::BytesValue(bytes));
146+
}
147+
_ => {
148+
//skip unknown keys, and handle error later.
149+
continue;
150+
}
131151
}
132152
}
133-
}
134153

135-
if let Some(v) = value {
136-
Ok(AnyValue { value: Some(v) })
137-
} else {
138-
Err(de::Error::custom("Invalid data for AnyValue, no known keys found"))
154+
if let Some(v) = value {
155+
Ok(AnyValue { value: Some(v) })
156+
} else {
157+
Err(de::Error::custom(
158+
"Invalid data for AnyValue, no known keys found",
159+
))
160+
}
139161
}
140162
}
163+
164+
let value = deserializer.deserialize_map(ValueVisitor)?;
165+
Ok(Some(value))
141166
}
142167

143-
let value = deserializer.deserialize_map(ValueVisitor)?;
144-
Ok(Some(value))
145-
}
146-
147168
pub fn serialize_u64_to_string<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
148169
where
149170
S: Serializer,

opentelemetry-proto/tests/json_deserialize.rs

+30
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,36 @@ mod json_deserialize {
146146
keyvalue.value.unwrap().value.unwrap(),
147147
Value::StringValue("my.service".to_string())
148148
);
149+
150+
let keyvalue: KeyValue = serde_json::from_str(
151+
r#"
152+
{
153+
"key": "service.name",
154+
"value": {
155+
"intValue": "303"
156+
}
157+
}
158+
"#,
159+
)
160+
.unwrap();
161+
162+
assert_eq!(keyvalue.key, "service.name".to_string());
163+
assert_eq!(keyvalue.value.unwrap().value.unwrap(), Value::IntValue(303));
164+
165+
let keyvalue: KeyValue = serde_json::from_str(
166+
r#"
167+
{
168+
"key": "service.name",
169+
"value": {
170+
"intValue": 303
171+
}
172+
}
173+
"#,
174+
)
175+
.unwrap();
176+
177+
assert_eq!(keyvalue.key, "service.name".to_string());
178+
assert_eq!(keyvalue.value.unwrap().value.unwrap(), Value::IntValue(303));
149179
}
150180

151181
#[test]

0 commit comments

Comments
 (0)