Skip to content

Commit

Permalink
Fix span link deserialization when missing optional fields (#887)
Browse files Browse the repository at this point in the history
  • Loading branch information
nhulston authored Feb 19, 2025
1 parent 3f188fd commit 0957884
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
4 changes: 4 additions & 0 deletions trace-protobuf/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ fn generate_protobuf() {
config.type_attribute("TraceChunk", "#[derive(Deserialize, Serialize)]");

config.type_attribute("SpanLink", "#[derive(Deserialize, Serialize)]");
config.field_attribute(".pb.SpanLink.traceID_high", "#[serde(default)]");
config.field_attribute(".pb.SpanLink.attributes", "#[serde(default)]");
config.field_attribute(".pb.SpanLink.tracestate", "#[serde(default)]");
config.field_attribute(".pb.SpanLink.flags", "#[serde(default)]");

config.type_attribute("Span", "#[derive(Deserialize, Serialize)]");
config.field_attribute(
Expand Down
4 changes: 4 additions & 0 deletions trace-protobuf/src/pb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub struct SpanLink {
///
/// Optional. The high 64 bits of a referenced trace id.
#[prost(uint64, tag = "2")]
#[serde(default)]
pub trace_id_high: u64,
/// @gotags: json:"span_id" msg:"span_id"
///
Expand All @@ -39,6 +40,7 @@ pub struct SpanLink {
///
/// Optional. Simple mapping of keys to string values.
#[prost(map = "string, string", tag = "4")]
#[serde(default)]
pub attributes: ::std::collections::HashMap<
::prost::alloc::string::String,
::prost::alloc::string::String,
Expand All @@ -47,11 +49,13 @@ pub struct SpanLink {
///
/// Optional. W3C tracestate.
#[prost(string, tag = "5")]
#[serde(default)]
pub tracestate: ::prost::alloc::string::String,
/// @gotags: msg:"flags,omitempty"
///
/// Optional. W3C trace flags. If set, the high bit (bit 31) must be set.
#[prost(uint32, tag = "6")]
#[serde(default)]
pub flags: u32,
}
#[derive(Deserialize, Serialize)]
Expand Down
58 changes: 58 additions & 0 deletions trace-utils/src/trace_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,64 @@ mod tests {
}
}

#[tokio::test]
async fn test_get_traces_from_request_body_with_span_links() {
let trace_input = json!([[{
"service": "test-service",
"name": "test-name",
"resource": "test-resource",
"trace_id": 111,
"span_id": 222,
"parent_id": 333,
"start": 1,
"duration": 5,
"error": 0,
"meta": {},
"metrics": {},
"span_links": [{
"trace_id": 999,
"span_id": 888,
"trace_id_high": 777,
"attributes": {"key": "value"},
"tracestate": "vendor=value"
// flags field intentionally omitted
}]
}]]);

let expected_output = vec![vec![pb::Span {
service: "test-service".to_string(),
name: "test-name".to_string(),
resource: "test-resource".to_string(),
trace_id: 111,
span_id: 222,
parent_id: 333,
start: 1,
duration: 5,
error: 0,
meta: HashMap::new(),
metrics: HashMap::new(),
meta_struct: HashMap::new(),
r#type: String::new(),
span_links: vec![pb::SpanLink {
trace_id: 999,
span_id: 888,
trace_id_high: 777,
attributes: HashMap::from([("key".to_string(), "value".to_string())]),
tracestate: "vendor=value".to_string(),
flags: 0, // Should default to 0 when omitted
}],
}]];

let bytes = rmp_serde::to_vec(&trace_input).unwrap();
let request = Request::builder()
.body(hyper::body::Body::from(bytes))
.unwrap();

let res = get_traces_from_request_body(request.into_body()).await;
assert!(res.is_ok(), "Failed to deserialize: {:?}", res);
assert_eq!(res.unwrap().1, expected_output);
}

#[test]
fn test_get_root_span_index_from_complete_trace() {
let trace = vec![
Expand Down

0 comments on commit 0957884

Please sign in to comment.