Skip to content

Commit 758cdd7

Browse files
authored
Add custom serde encoding/decoding for timestamp (#1666)
1 parent 2286378 commit 758cdd7

File tree

6 files changed

+63
-15
lines changed

6 files changed

+63
-15
lines changed

opentelemetry-otlp/tests/integration_test/expected/failed_traces.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
"parentSpanId": "",
2424
"name": "Sub operation...",
2525
"kind": 1,
26-
"startTimeUnixNano": 1703985537070566698,
27-
"endTimeUnixNano": 1703985537070572718,
26+
"startTimeUnixNano": "1703985537070566698",
27+
"endTimeUnixNano": "1703985537070572718",
2828
"attributes": [
2929
{
3030
"key": "lemons",
@@ -35,7 +35,7 @@
3535
],
3636
"events": [
3737
{
38-
"timeUnixNano": 1703985537070567697,
38+
"timeUnixNano": "1703985537070567697",
3939
"name": "Sub span event"
4040
}
4141
],
@@ -68,8 +68,8 @@
6868
"parentSpanId": "cd7cf7bf939930b7",
6969
"name": "operation",
7070
"kind": 1,
71-
"startTimeUnixNano": 1703985537070558635,
72-
"endTimeUnixNano": 1703985537070580454,
71+
"startTimeUnixNano": "1703985537070558635",
72+
"endTimeUnixNano": "1703985537070580454",
7373
"attributes": [
7474
{
7575
"key": "ex.com/another",
@@ -80,7 +80,7 @@
8080
],
8181
"events": [
8282
{
83-
"timeUnixNano": 1703985537070563326,
83+
"timeUnixNano": "1703985537070563326",
8484
"name": "Nice operation!",
8585
"attributes": [
8686
{

opentelemetry-otlp/tests/integration_test/expected/traces.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
"parentSpanId": "d58cf2d702a061e0",
2424
"name": "Sub operation...",
2525
"kind": 1,
26-
"startTimeUnixNano": 1703985537070566698,
27-
"endTimeUnixNano": 1703985537070572718,
26+
"startTimeUnixNano": "1703985537070566698",
27+
"endTimeUnixNano": "1703985537070572718",
2828
"attributes": [
2929
{
3030
"key": "lemons",
@@ -35,7 +35,7 @@
3535
],
3636
"events": [
3737
{
38-
"timeUnixNano": 1703985537070567697,
38+
"timeUnixNano": "1703985537070567697",
3939
"name": "Sub span event"
4040
}
4141
],
@@ -68,8 +68,8 @@
6868
"parentSpanId": "",
6969
"name": "operation",
7070
"kind": 1,
71-
"startTimeUnixNano": 1703985537070558635,
72-
"endTimeUnixNano": 1703985537070580454,
71+
"startTimeUnixNano": "1703985537070558635",
72+
"endTimeUnixNano": "1703985537070580454",
7373
"attributes": [
7474
{
7575
"key": "ex.com/another",
@@ -80,7 +80,7 @@
8080
],
8181
"events": [
8282
{
83-
"timeUnixNano": 1703985537070563326,
83+
"timeUnixNano": "1703985537070563326",
8484
"name": "Nice operation!",
8585
"attributes": [
8686
{

opentelemetry-proto/src/proto.rs

+14
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,21 @@ pub(crate) mod serializers {
6969
Ok(Some(AnyValue { value }))
7070
}
7171

72+
pub fn serialize_u64_to_string<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
73+
where
74+
S: Serializer,
75+
{
76+
let s = value.to_string();
77+
serializer.serialize_str(&s)
78+
}
7279

80+
pub fn deserialize_string_to_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
81+
where
82+
D: Deserializer<'de>,
83+
{
84+
let s: String = Deserialize::deserialize(deserializer)?;
85+
s.parse::<u64>().map_err(de::Error::custom)
86+
}
7387
}
7488

7589
#[cfg(feature = "gen-tonic-messages")]

opentelemetry-proto/src/proto/tonic/opentelemetry.proto.trace.v1.rs

+21
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ pub struct Span {
166166
///
167167
/// This field is semantically required and it is expected that end_time >= start_time.
168168
#[prost(fixed64, tag = "7")]
169+
#[cfg_attr(
170+
feature = "with-serde",
171+
serde(
172+
serialize_with = "crate::proto::serializers::serialize_u64_to_string",
173+
deserialize_with = "crate::proto::serializers::deserialize_string_to_u64"
174+
)
175+
)]
169176
pub start_time_unix_nano: u64,
170177
/// end_time_unix_nano is the end time of the span. On the client side, this is the time
171178
/// kept by the local machine where the span execution ends. On the server side, this
@@ -174,6 +181,13 @@ pub struct Span {
174181
///
175182
/// This field is semantically required and it is expected that end_time >= start_time.
176183
#[prost(fixed64, tag = "8")]
184+
#[cfg_attr(
185+
feature = "with-serde",
186+
serde(
187+
serialize_with = "crate::proto::serializers::serialize_u64_to_string",
188+
deserialize_with = "crate::proto::serializers::deserialize_string_to_u64"
189+
)
190+
)]
177191
pub end_time_unix_nano: u64,
178192
/// attributes is a collection of key/value pairs. Note, global attributes
179193
/// like server name can be set using the resource API. Examples of attributes:
@@ -227,6 +241,13 @@ pub mod span {
227241
pub struct Event {
228242
/// time_unix_nano is the time the event occurred.
229243
#[prost(fixed64, tag = "1")]
244+
#[cfg_attr(
245+
feature = "with-serde",
246+
serde(
247+
serialize_with = "crate::proto::serializers::serialize_u64_to_string",
248+
deserialize_with = "crate::proto::serializers::deserialize_string_to_u64"
249+
)
250+
)]
230251
pub time_unix_nano: u64,
231252
/// name of the event.
232253
/// This field is semantically required to be set to non-empty string.

opentelemetry-proto/tests/grpc_build.rs

+13
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,19 @@ fn build_tonic() {
7373
.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\"))]")
7474
}
7575

76+
// special serializer and deserializer for timestamp
77+
// OTLP/JSON format may uses string for timestamp
78+
// the proto file uses u64 for timestamp
79+
// Thus, special serializer and deserializer are needed
80+
for path in [
81+
"trace.v1.Span.start_time_unix_nano",
82+
"trace.v1.Span.end_time_unix_nano",
83+
"trace.v1.Span.Event.time_unix_nano",
84+
] {
85+
builder = builder
86+
.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\"))]")
87+
}
88+
7689
// add custom serializer and deserializer for AnyValue
7790
builder = builder
7891
.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\"))]");

opentelemetry-proto/tests/json_deserialize.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ mod json_deserialize {
4141
"spanId": "EEE19B7EC3C1B174",
4242
"parentSpanId": "EEE19B7EC3C1B173",
4343
"name": "I'm a server span",
44-
"startTimeUnixNano": 1544712660000000000,
45-
"endTimeUnixNano": 1544712661000000000,
44+
"startTimeUnixNano": "1544712660000000000",
45+
"endTimeUnixNano": "1544712661000000000",
4646
"kind": 2,
4747
"attributes": [
4848
{
@@ -73,7 +73,7 @@ mod json_deserialize {
7373
const EVENT_JSON: &str = r#"
7474
{
7575
"name": "my_event",
76-
"time_unix_nano": 1234567890
76+
"time_unix_nano": "1234567890"
7777
}
7878
"#;
7979

0 commit comments

Comments
 (0)