Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom serde encoding/decoding for timestamp #1666

Merged
merged 8 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"parentSpanId": "",
"name": "Sub operation...",
"kind": 1,
"startTimeUnixNano": 1703985537070566698,
"endTimeUnixNano": 1703985537070572718,
"startTimeUnixNano": "1703985537070566698",
"endTimeUnixNano": "1703985537070572718",
"attributes": [
{
"key": "lemons",
Expand All @@ -35,7 +35,7 @@
],
"events": [
{
"timeUnixNano": 1703985537070567697,
"timeUnixNano": "1703985537070567697",
"name": "Sub span event"
}
],
Expand Down Expand Up @@ -68,8 +68,8 @@
"parentSpanId": "cd7cf7bf939930b7",
"name": "operation",
"kind": 1,
"startTimeUnixNano": 1703985537070558635,
"endTimeUnixNano": 1703985537070580454,
"startTimeUnixNano": "1703985537070558635",
"endTimeUnixNano": "1703985537070580454",
"attributes": [
{
"key": "ex.com/another",
Expand All @@ -80,7 +80,7 @@
],
"events": [
{
"timeUnixNano": 1703985537070563326,
"timeUnixNano": "1703985537070563326",
"name": "Nice operation!",
"attributes": [
{
Expand Down
12 changes: 6 additions & 6 deletions opentelemetry-otlp/tests/integration_test/expected/traces.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"parentSpanId": "d58cf2d702a061e0",
"name": "Sub operation...",
"kind": 1,
"startTimeUnixNano": 1703985537070566698,
"endTimeUnixNano": 1703985537070572718,
"startTimeUnixNano": "1703985537070566698",
"endTimeUnixNano": "1703985537070572718",
"attributes": [
{
"key": "lemons",
Expand All @@ -35,7 +35,7 @@
],
"events": [
{
"timeUnixNano": 1703985537070567697,
"timeUnixNano": "1703985537070567697",
"name": "Sub span event"
}
],
Expand Down Expand Up @@ -68,8 +68,8 @@
"parentSpanId": "",
"name": "operation",
"kind": 1,
"startTimeUnixNano": 1703985537070558635,
"endTimeUnixNano": 1703985537070580454,
"startTimeUnixNano": "1703985537070558635",
"endTimeUnixNano": "1703985537070580454",
"attributes": [
{
"key": "ex.com/another",
Expand All @@ -80,7 +80,7 @@
],
"events": [
{
"timeUnixNano": 1703985537070563326,
"timeUnixNano": "1703985537070563326",
"name": "Nice operation!",
"attributes": [
{
Expand Down
14 changes: 14 additions & 0 deletions opentelemetry-proto/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,21 @@ pub(crate) mod serializers {
Ok(Some(AnyValue { value }))
}

pub fn serialize_u64_to_string<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = value.to_string();
serializer.serialize_str(&s)
}

pub fn deserialize_string_to_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
s.parse::<u64>().map_err(de::Error::custom)
}
}

#[cfg(feature = "gen-tonic-messages")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ pub struct Span {
///
/// This field is semantically required and it is expected that end_time >= start_time.
#[prost(fixed64, tag = "7")]
#[cfg_attr(
feature = "with-serde",
serde(
serialize_with = "crate::proto::serializers::serialize_u64_to_string",
deserialize_with = "crate::proto::serializers::deserialize_string_to_u64"
)
)]
pub start_time_unix_nano: u64,
/// end_time_unix_nano is the end time of the span. On the client side, this is the time
/// kept by the local machine where the span execution ends. On the server side, this
Expand All @@ -174,6 +181,13 @@ pub struct Span {
///
/// This field is semantically required and it is expected that end_time >= start_time.
#[prost(fixed64, tag = "8")]
#[cfg_attr(
feature = "with-serde",
serde(
serialize_with = "crate::proto::serializers::serialize_u64_to_string",
deserialize_with = "crate::proto::serializers::deserialize_string_to_u64"
)
)]
pub end_time_unix_nano: u64,
/// attributes is a collection of key/value pairs. Note, global attributes
/// like server name can be set using the resource API. Examples of attributes:
Expand Down Expand Up @@ -227,6 +241,13 @@ pub mod span {
pub struct Event {
/// time_unix_nano is the time the event occurred.
#[prost(fixed64, tag = "1")]
#[cfg_attr(
feature = "with-serde",
serde(
serialize_with = "crate::proto::serializers::serialize_u64_to_string",
deserialize_with = "crate::proto::serializers::deserialize_string_to_u64"
)
)]
pub time_unix_nano: u64,
/// name of the event.
/// This field is semantically required to be set to non-empty string.
Expand Down
13 changes: 13 additions & 0 deletions opentelemetry-proto/tests/grpc_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ fn build_tonic() {
.field_attribute(path, "#[cfg_attr(feature = \"with-serde\", serde(serialize_with = \"crate::proto::serializers::serialize_to_hex_string\", deserialize_with = \"crate::proto::serializers::deserialize_from_hex_string\"))]")
}

// special serializer and deserializer for timestamp
// OTLP/JSON format may uses string for timestamp
// the proto file uses u64 for timestamp
// Thus, special serializer and deserializer are needed
for path in [
"trace.v1.Span.start_time_unix_nano",
"trace.v1.Span.end_time_unix_nano",
"trace.v1.Span.Event.time_unix_nano",
] {
builder = builder
.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
builder = builder
.field_attribute("common.v1.KeyValue.value", "#[cfg_attr(feature =\"with-serde\", serde(serialize_with = \"crate::proto::serializers::serialize_to_value\", deserialize_with = \"crate::proto::serializers::deserialize_from_value\"))]");
Expand Down
6 changes: 3 additions & 3 deletions opentelemetry-proto/tests/json_deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ mod json_deserialize {
"spanId": "EEE19B7EC3C1B174",
"parentSpanId": "EEE19B7EC3C1B173",
"name": "I'm a server span",
"startTimeUnixNano": 1544712660000000000,
"endTimeUnixNano": 1544712661000000000,
"startTimeUnixNano": "1544712660000000000",
"endTimeUnixNano": "1544712661000000000",
"kind": 2,
"attributes": [
{
Expand Down Expand Up @@ -73,7 +73,7 @@ mod json_deserialize {
const EVENT_JSON: &str = r#"
{
"name": "my_event",
"time_unix_nano": 1234567890
"time_unix_nano": "1234567890"
}
"#;

Expand Down
Loading