Skip to content

Commit

Permalink
Use the correct format when deserializing body field from logs
Browse files Browse the repository at this point in the history
  • Loading branch information
RazvanRotari committed Oct 6, 2024
1 parent 6aad3db commit 67f1f78
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 69 deletions.
44 changes: 16 additions & 28 deletions opentelemetry-proto/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub(crate) mod serializers {
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;
use serde::ser::{SerializeMap, SerializeStruct};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;

Expand Down Expand Up @@ -45,35 +45,23 @@ pub(crate) mod serializers {
}

// AnyValue <-> KeyValue conversion
pub fn serialize_to_value<S>(value: &Option<AnyValue>, serializer: S) -> Result<S::Ok, S::Error>
pub fn serialize_to_value<S>(value: &Option<Value>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match value {
Some(any_value) => match &any_value.value {
Some(Value::IntValue(i)) => {
// Attempt to create a struct to wrap the intValue
let mut state = match serializer.serialize_struct("Value", 1) {
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(),
},
match &value {
Some(Value::IntValue(i)) => {
// Attempt to serialize the intValue field
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("intValue", &i.to_string());
map.end()
}
Some(value) => value.serialize(serializer),
None => serializer.serialize_none(),
}
}

pub fn deserialize_from_value<'de, D>(deserializer: D) -> Result<Option<AnyValue>, D::Error>
pub fn deserialize_from_value<'de, D>(deserializer: D) -> Result<Option<Value>, D::Error>
where
D: Deserializer<'de>,
{
Expand All @@ -99,13 +87,13 @@ pub(crate) mod serializers {
}

impl<'de> de::Visitor<'de> for ValueVisitor {
type Value = AnyValue;
type Value = Option<Value>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a JSON object for AnyValue")
}

fn visit_map<V>(self, mut map: V) -> Result<AnyValue, V::Error>
fn visit_map<V>(self, mut map: V) -> Result<Option<Value>, V::Error>
where
V: de::MapAccess<'de>,
{
Expand Down Expand Up @@ -150,17 +138,17 @@ pub(crate) mod serializers {
}

if let Some(v) = value {
Ok(AnyValue { value: Some(v) })
Ok(Some(v))
} else {
Err(de::Error::custom(
"Invalid data for AnyValue, no known keys found",
"Invalid data for Value, no known keys found",
))
}
}
}

let value = deserializer.deserialize_map(ValueVisitor)?;
Ok(Some(value))
Ok(value)
}

pub fn serialize_u64_to_string<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ pub struct AnyValue {
/// The value is one of the listed fields. It is valid for all values to be unspecified
/// in which case this AnyValue is considered to be "empty".
#[prost(oneof = "any_value::Value", tags = "1, 2, 3, 4, 5, 6, 7")]
#[cfg_attr(
feature = "with-serde",
serde(
flatten,
serialize_with = "crate::proto::serializers::serialize_to_value",
deserialize_with = "crate::proto::serializers::deserialize_from_value"
)
)]
pub value: ::core::option::Option<any_value::Value>,
}
/// Nested message and enum types in `AnyValue`.
Expand Down Expand Up @@ -75,13 +83,6 @@ pub struct KeyValue {
#[prost(string, tag = "1")]
pub key: ::prost::alloc::string::String,
#[prost(message, optional, tag = "2")]
#[cfg_attr(
feature = "with-serde",
serde(
serialize_with = "crate::proto::serializers::serialize_to_value",
deserialize_with = "crate::proto::serializers::deserialize_from_value"
)
)]
pub value: ::core::option::Option<AnyValue>,
}
/// InstrumentationScope is a message representing the instrumentation scope information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,6 @@ pub struct LogRecord {
/// string message (including multi-line) describing the event in a free form or it can
/// be a structured data composed of arrays and maps of other values. \[Optional\].
#[prost(message, optional, tag = "5")]
#[cfg_attr(
feature = "with-serde",
serde(
serialize_with = "crate::proto::serializers::serialize_to_value",
deserialize_with = "crate::proto::serializers::deserialize_from_value"
)
)]
pub body: ::core::option::Option<super::super::common::v1::AnyValue>,
/// Additional attributes that describe the specific event occurrence. \[Optional\].
/// Attribute keys MUST be unique (it is not allowed to have more than one
Expand Down
7 changes: 4 additions & 3 deletions opentelemetry-proto/tests/grpc_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,11 @@ fn build_tonic() {
.field_attribute(path, "#[cfg_attr(feature = \"with-serde\", serde(serialize_with = \"crate::proto::serializers::serialize_u64_to_string\", deserialize_with = \"crate::proto::serializers::deserialize_string_to_u64\"))]")
}

// add custom serializer and deserializer for AnyValue
for path in ["common.v1.KeyValue.value", "logs.v1.LogRecord.body"] {
// special serializer and deserializer for value
// The Value::value field must be hidden
for path in ["common.v1.AnyValue.value"] {
builder = builder
.field_attribute(path, "#[cfg_attr(feature =\"with-serde\", serde(serialize_with = \"crate::proto::serializers::serialize_to_value\", deserialize_with = \"crate::proto::serializers::deserialize_from_value\"))]");
.field_attribute(path, "#[cfg_attr(feature =\"with-serde\", serde(flatten, serialize_with = \"crate::proto::serializers::serialize_to_value\", deserialize_with = \"crate::proto::serializers::deserialize_from_value\"))]");
}

// flatten
Expand Down
32 changes: 8 additions & 24 deletions opentelemetry-proto/tests/json_serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,14 +518,10 @@ mod json_serde {
"arrayValue": {
"values": [
{
"value": {
"stringValue": "foo"
}
"stringValue": "foo"
},
{
"value": {
"stringValue": "bar"
}
"stringValue": "bar"
}
]
}
Expand Down Expand Up @@ -557,14 +553,10 @@ mod json_serde {
"arrayValue": {
"values": [
{
"value": {
"stringValue": "foo"
}
"stringValue": "foo"
},
{
"value": {
"intValue": 1337
}
"intValue": "1337"
}
]
}
Expand Down Expand Up @@ -1339,14 +1331,10 @@ mod json_serde {
"arrayValue": {
"values": [
{
"value": {
"stringValue": "many"
}
"stringValue": "many"
},
{
"value": {
"stringValue": "values"
}
"stringValue": "values"
}
]
}
Expand Down Expand Up @@ -1453,14 +1441,10 @@ mod json_serde {
"arrayValue": {
"values": [
{
"value": {
"stringValue": "many"
}
"stringValue": "many"
},
{
"value": {
"stringValue": "values"
}
"stringValue": "values"
}
]
}
Expand Down

0 comments on commit 67f1f78

Please sign in to comment.