diff --git a/opentelemetry-otlp/tests/integration_test/expected/traces.json b/opentelemetry-otlp/tests/integration_test/expected/traces.json index 49fcc1ea55..97e2b04d4d 100644 --- a/opentelemetry-otlp/tests/integration_test/expected/traces.json +++ b/opentelemetry-otlp/tests/integration_test/expected/traces.json @@ -88,6 +88,12 @@ "value": { "intValue": "100" } + }, + { + "key": "number/int", + "value": { + "intValue": 100 + } } ] } diff --git a/opentelemetry-proto/src/proto.rs b/opentelemetry-proto/src/proto.rs index 8bc372b889..ba4038072f 100644 --- a/opentelemetry-proto/src/proto.rs +++ b/opentelemetry-proto/src/proto.rs @@ -57,15 +57,15 @@ pub(crate) mod serializers { Ok(s) => s, Err(e) => return Err(e), // Handle the error or return it }; - + // Attempt to serialize the intValue field if let Err(e) = state.serialize_field("intValue", &i.to_string()) { return Err(e); // Handle the error or return it } - + // Finalize the struct serialization state.end() - }, + } Some(value) => value.serialize(serializer), None => serializer.serialize_none(), }, @@ -74,76 +74,95 @@ pub(crate) mod serializers { } pub fn deserialize_from_value<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - struct ValueVisitor; + where + D: Deserializer<'de>, + { + struct ValueVisitor; - impl<'de> de::Visitor<'de> for ValueVisitor { - type Value = AnyValue; + #[derive(Deserialize)] + #[serde(untagged)] + enum StringOrInt { + Int(i64), + String(String), + } - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a JSON object for AnyValue") + impl StringOrInt { + fn get_int<'de, V>(&self) -> Result + where + V: de::MapAccess<'de>, + { + match self { + Self::Int(val) => Ok(*val), + Self::String(val) => Ok(val.parse::().map_err(de::Error::custom)?), + } + } } - fn visit_map(self, mut map: V) -> Result - where - V: de::MapAccess<'de>, - { - let mut value: Option = None; - - while let Some(key) = map.next_key::()? { - let key_str = key.as_str(); - match key_str { - "stringValue" => { - let s = map.next_value()?; - value = Some(any_value::Value::StringValue(s)); - }, - "boolValue" => { - let b = map.next_value()?; - value = Some(any_value::Value::BoolValue(b)); - }, - "intValue" => { - let value_str = map.next_value::()?; - let int_value = value_str.parse::() - .map_err(de::Error::custom)?; - value = Some(any_value::Value::IntValue(int_value)); - }, - "doubleValue" => { - let d = map.next_value()?; - value = Some(any_value::Value::DoubleValue(d)); - }, - "arrayValue" => { - let a = map.next_value()?; - value = Some(any_value::Value::ArrayValue(a)); - }, - "kvlistValue" => { - let kv = map.next_value()?; - value = Some(any_value::Value::KvlistValue(kv)); - }, - "bytesValue" => { - let bytes = map.next_value()?; - value = Some(any_value::Value::BytesValue(bytes)); - }, - _ => { - //skip unknown keys, and handle error later. - continue + impl<'de> de::Visitor<'de> for ValueVisitor { + type Value = AnyValue; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a JSON object for AnyValue") + } + + fn visit_map(self, mut map: V) -> Result + where + V: de::MapAccess<'de>, + { + let mut value: Option = None; + + while let Some(key) = map.next_key::()? { + let key_str = key.as_str(); + match key_str { + "stringValue" => { + let s = map.next_value()?; + value = Some(any_value::Value::StringValue(s)); + } + "boolValue" => { + let b = map.next_value()?; + value = Some(any_value::Value::BoolValue(b)); + } + "intValue" => { + let int_value = map.next_value::()?.get_int::()?; + value = Some(any_value::Value::IntValue(int_value)); + } + "doubleValue" => { + let d = map.next_value()?; + value = Some(any_value::Value::DoubleValue(d)); + } + "arrayValue" => { + let a = map.next_value()?; + value = Some(any_value::Value::ArrayValue(a)); + } + "kvlistValue" => { + let kv = map.next_value()?; + value = Some(any_value::Value::KvlistValue(kv)); + } + "bytesValue" => { + let bytes = map.next_value()?; + value = Some(any_value::Value::BytesValue(bytes)); + } + _ => { + //skip unknown keys, and handle error later. + continue; + } } } - } - if let Some(v) = value { - Ok(AnyValue { value: Some(v) }) - } else { - Err(de::Error::custom("Invalid data for AnyValue, no known keys found")) + if let Some(v) = value { + Ok(AnyValue { value: Some(v) }) + } else { + Err(de::Error::custom( + "Invalid data for AnyValue, no known keys found", + )) + } } } + + let value = deserializer.deserialize_map(ValueVisitor)?; + Ok(Some(value)) } - let value = deserializer.deserialize_map(ValueVisitor)?; - Ok(Some(value)) -} - pub fn serialize_u64_to_string(value: &u64, serializer: S) -> Result where S: Serializer, @@ -167,7 +186,7 @@ where let s = value.to_string(); serializer.serialize_str(&s) } - + pub fn deserialize_string_to_i64<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, diff --git a/opentelemetry-proto/tests/json_deserialize.rs b/opentelemetry-proto/tests/json_deserialize.rs index f1fcd3d6b9..6632ffadd5 100644 --- a/opentelemetry-proto/tests/json_deserialize.rs +++ b/opentelemetry-proto/tests/json_deserialize.rs @@ -146,6 +146,36 @@ mod json_deserialize { keyvalue.value.unwrap().value.unwrap(), Value::StringValue("my.service".to_string()) ); + + let keyvalue: KeyValue = serde_json::from_str( + r#" +{ + "key": "service.name", + "value": { + "intValue": "303" + } + } + "#, + ) + .unwrap(); + + assert_eq!(keyvalue.key, "service.name".to_string()); + assert_eq!(keyvalue.value.unwrap().value.unwrap(), Value::IntValue(303)); + + let keyvalue: KeyValue = serde_json::from_str( + r#" +{ + "key": "service.name", + "value": { + "intValue": 303 + } + } + "#, + ) + .unwrap(); + + assert_eq!(keyvalue.key, "service.name".to_string()); + assert_eq!(keyvalue.value.unwrap().value.unwrap(), Value::IntValue(303)); } #[test]