Skip to content

Commit 0957884

Browse files
authored
Fix span link deserialization when missing optional fields (#887)
1 parent 3f188fd commit 0957884

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

trace-protobuf/build.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ fn generate_protobuf() {
5454
config.type_attribute("TraceChunk", "#[derive(Deserialize, Serialize)]");
5555

5656
config.type_attribute("SpanLink", "#[derive(Deserialize, Serialize)]");
57+
config.field_attribute(".pb.SpanLink.traceID_high", "#[serde(default)]");
58+
config.field_attribute(".pb.SpanLink.attributes", "#[serde(default)]");
59+
config.field_attribute(".pb.SpanLink.tracestate", "#[serde(default)]");
60+
config.field_attribute(".pb.SpanLink.flags", "#[serde(default)]");
5761

5862
config.type_attribute("Span", "#[derive(Deserialize, Serialize)]");
5963
config.field_attribute(

trace-protobuf/src/pb.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub struct SpanLink {
2929
///
3030
/// Optional. The high 64 bits of a referenced trace id.
3131
#[prost(uint64, tag = "2")]
32+
#[serde(default)]
3233
pub trace_id_high: u64,
3334
/// @gotags: json:"span_id" msg:"span_id"
3435
///
@@ -39,6 +40,7 @@ pub struct SpanLink {
3940
///
4041
/// Optional. Simple mapping of keys to string values.
4142
#[prost(map = "string, string", tag = "4")]
43+
#[serde(default)]
4244
pub attributes: ::std::collections::HashMap<
4345
::prost::alloc::string::String,
4446
::prost::alloc::string::String,
@@ -47,11 +49,13 @@ pub struct SpanLink {
4749
///
4850
/// Optional. W3C tracestate.
4951
#[prost(string, tag = "5")]
52+
#[serde(default)]
5053
pub tracestate: ::prost::alloc::string::String,
5154
/// @gotags: msg:"flags,omitempty"
5255
///
5356
/// Optional. W3C trace flags. If set, the high bit (bit 31) must be set.
5457
#[prost(uint32, tag = "6")]
58+
#[serde(default)]
5559
pub flags: u32,
5660
}
5761
#[derive(Deserialize, Serialize)]

trace-utils/src/trace_utils.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,64 @@ mod tests {
902902
}
903903
}
904904

905+
#[tokio::test]
906+
async fn test_get_traces_from_request_body_with_span_links() {
907+
let trace_input = json!([[{
908+
"service": "test-service",
909+
"name": "test-name",
910+
"resource": "test-resource",
911+
"trace_id": 111,
912+
"span_id": 222,
913+
"parent_id": 333,
914+
"start": 1,
915+
"duration": 5,
916+
"error": 0,
917+
"meta": {},
918+
"metrics": {},
919+
"span_links": [{
920+
"trace_id": 999,
921+
"span_id": 888,
922+
"trace_id_high": 777,
923+
"attributes": {"key": "value"},
924+
"tracestate": "vendor=value"
925+
// flags field intentionally omitted
926+
}]
927+
}]]);
928+
929+
let expected_output = vec![vec![pb::Span {
930+
service: "test-service".to_string(),
931+
name: "test-name".to_string(),
932+
resource: "test-resource".to_string(),
933+
trace_id: 111,
934+
span_id: 222,
935+
parent_id: 333,
936+
start: 1,
937+
duration: 5,
938+
error: 0,
939+
meta: HashMap::new(),
940+
metrics: HashMap::new(),
941+
meta_struct: HashMap::new(),
942+
r#type: String::new(),
943+
span_links: vec![pb::SpanLink {
944+
trace_id: 999,
945+
span_id: 888,
946+
trace_id_high: 777,
947+
attributes: HashMap::from([("key".to_string(), "value".to_string())]),
948+
tracestate: "vendor=value".to_string(),
949+
flags: 0, // Should default to 0 when omitted
950+
}],
951+
}]];
952+
953+
let bytes = rmp_serde::to_vec(&trace_input).unwrap();
954+
let request = Request::builder()
955+
.body(hyper::body::Body::from(bytes))
956+
.unwrap();
957+
958+
let res = get_traces_from_request_body(request.into_body()).await;
959+
assert!(res.is_ok(), "Failed to deserialize: {:?}", res);
960+
assert_eq!(res.unwrap().1, expected_output);
961+
}
962+
905963
#[test]
906964
fn test_get_root_span_index_from_complete_trace() {
907965
let trace = vec![

0 commit comments

Comments
 (0)