diff --git a/opentelemetry-otlp/tests/integration_test/expected/failed_traces.json b/opentelemetry-otlp/tests/integration_test/expected/failed_traces.json index 160c86e1c2..1d065f4b2d 100644 --- a/opentelemetry-otlp/tests/integration_test/expected/failed_traces.json +++ b/opentelemetry-otlp/tests/integration_test/expected/failed_traces.json @@ -86,7 +86,7 @@ { "key": "bogons", "value": { - "intValue": 100 + "intValue": "100" } } ] diff --git a/opentelemetry-otlp/tests/integration_test/expected/traces.json b/opentelemetry-otlp/tests/integration_test/expected/traces.json index cc85443e76..49fcc1ea55 100644 --- a/opentelemetry-otlp/tests/integration_test/expected/traces.json +++ b/opentelemetry-otlp/tests/integration_test/expected/traces.json @@ -86,7 +86,7 @@ { "key": "bogons", "value": { - "intValue": 100 + "intValue": "100" } } ] diff --git a/opentelemetry-otlp/tests/integration_test/tests/traces.rs b/opentelemetry-otlp/tests/integration_test/tests/traces.rs index 45507e5035..64d59e911e 100644 --- a/opentelemetry-otlp/tests/integration_test/tests/traces.rs +++ b/opentelemetry-otlp/tests/integration_test/tests/traces.rs @@ -58,12 +58,12 @@ pub async fn traces() -> Result<(), Box> { Ok(()) } -pub fn assert_traces_results(result: &str, _: &str) { - // let left = read_spans_from_json(File::open(expected).unwrap()); - // let right = read_spans_from_json(File::open(result).unwrap()); +pub fn assert_traces_results(result: &str, expected: &str) { + let left = read_spans_from_json(File::open(expected).unwrap()); + let right = read_spans_from_json(File::open(result).unwrap()); + + TraceAsserter::new(left, right).assert(); - // TraceAsserter::new(left, right).assert(); - // // we cannot read result json file because the timestamp was represents as string instead of u64. // need to fix it on json file exporter diff --git a/opentelemetry-proto/src/proto.rs b/opentelemetry-proto/src/proto.rs index 2d10d7feab..fd7ddd7652 100644 --- a/opentelemetry-proto/src/proto.rs +++ b/opentelemetry-proto/src/proto.rs @@ -3,7 +3,7 @@ /// See https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding for more details #[cfg(all(feature = "with-serde", feature = "gen-tonic-messages"))] pub(crate) mod serializers { - use crate::tonic::common::v1::any_value::Value; + use crate::tonic::common::v1::any_value::{self, Value}; use crate::tonic::common::v1::AnyValue; use serde::de::{self, MapAccess, Visitor}; use serde::ser::SerializeStruct; @@ -52,23 +52,86 @@ pub(crate) mod serializers { // Serialize any_value::Value using its own implementation // If value is None, it will be serialized as such match value { - Some(value) => value.value.serialize(serializer), + Some(any_value) => match &any_value.value { + Some(Value::IntValue(i)) => serialize_i64_to_string(i, serializer), + Some(value) => value.serialize(serializer), + None => serializer.serialize_none(), + }, None => serializer.serialize_none(), } - } pub fn deserialize_from_value<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - // Deserialize any_value::Value using its own implementation - let value = Option::::deserialize(deserializer)?; +where + D: Deserializer<'de>, +{ + struct ValueVisitor; + + 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") + } - // Wrap the deserialized value in AnyValue - Ok(Some(AnyValue { value })) + 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 + } + } + } + + 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)) +} + pub fn serialize_u64_to_string(value: &u64, serializer: S) -> Result where S: Serializer, @@ -84,6 +147,22 @@ pub(crate) mod serializers { let s: String = Deserialize::deserialize(deserializer)?; s.parse::().map_err(de::Error::custom) } + + pub fn serialize_i64_to_string(value: &i64, serializer: S) -> Result + where + S: Serializer, + { + let s = value.to_string(); + serializer.serialize_str(&s) + } + + pub fn deserialize_string_to_i64<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = Deserialize::deserialize(deserializer)?; + s.parse::().map_err(de::Error::custom) + } } #[cfg(feature = "gen-tonic-messages")]