1- use relay_protocol:: { Annotated , Empty , FromValue , IntoValue , Object , Value } ;
1+ use relay_protocol:: { Annotated , Array , Empty , FromValue , IntoValue , Object , Value } ;
22
33use std:: fmt;
44
@@ -57,6 +57,10 @@ pub struct SpanV2 {
5757 #[ metastructure( required = true ) ]
5858 pub end_timestamp : Annotated < Timestamp > ,
5959
60+ /// Links from this span to other spans.
61+ #[ metastructure( pii = "maybe" ) ]
62+ pub links : Annotated < Array < SpanV2Link > > ,
63+
6064 /// Arbitrary attributes on a span.
6165 #[ metastructure( pii = "true" , trim = false ) ]
6266 pub attributes : Annotated < Object < Attribute > > ,
@@ -255,6 +259,31 @@ impl IntoValue for SpanV2Kind {
255259 }
256260}
257261
262+ /// A link from a span to another span.
263+ #[ derive( Clone , Debug , Default , PartialEq , Empty , FromValue , IntoValue , ProcessValue ) ]
264+ #[ metastructure( trim = false ) ]
265+ pub struct SpanV2Link {
266+ /// The trace id of the linked span.
267+ #[ metastructure( required = true , trim = false ) ]
268+ pub trace_id : Annotated < TraceId > ,
269+
270+ /// The span id of the linked span.
271+ #[ metastructure( required = true , trim = false ) ]
272+ pub span_id : Annotated < SpanId > ,
273+
274+ /// Whether the linked span was positively/negatively sampled.
275+ #[ metastructure( trim = false ) ]
276+ pub sampled : Annotated < bool > ,
277+
278+ /// Span link attributes, similar to span attributes/data.
279+ #[ metastructure( pii = "maybe" , trim = false ) ]
280+ pub attributes : Annotated < Object < Attribute > > ,
281+
282+ /// Additional arbitrary fields for forwards compatibility.
283+ #[ metastructure( additional_properties, pii = "maybe" , trim = false ) ]
284+ pub other : Object < Value > ,
285+ }
286+
258287#[ cfg( test) ]
259288mod tests {
260289 use chrono:: { TimeZone , Utc } ;
@@ -287,6 +316,19 @@ mod tests {
287316 "kind": "server",
288317 "start_timestamp": 1742921669.25,
289318 "end_timestamp": 1742921669.75,
319+ "links": [
320+ {
321+ "trace_id": "627a2885119dcc8184fae7eef09438cb",
322+ "span_id": "6c71fc6b09b8b716",
323+ "sampled": true,
324+ "attributes": {
325+ "sentry.link.type": {
326+ "type": "string",
327+ "value": "previous_trace"
328+ }
329+ }
330+ }
331+ ],
290332 "attributes": {
291333 "custom.error_rate": {
292334 "type": "double",
@@ -348,6 +390,16 @@ mod tests {
348390 "server.address" => "DHWKN7KX6N.local" , String ,
349391 "http.response.status_code" => 200i64 , Integer ,
350392 ) ;
393+
394+ let links = vec ! [ Annotated :: new( SpanV2Link {
395+ trace_id: Annotated :: new( "627a2885119dcc8184fae7eef09438cb" . parse( ) . unwrap( ) ) ,
396+ span_id: Annotated :: new( SpanId ( "6c71fc6b09b8b716" . into( ) ) ) ,
397+ sampled: Annotated :: new( true ) ,
398+ attributes: Annotated :: new( attrs!(
399+ "sentry.link.type" => "previous_trace" , String
400+ ) ) ,
401+ ..Default :: default ( )
402+ } ) ] ;
351403 let span = Annotated :: new ( SpanV2 {
352404 start_timestamp : Annotated :: new (
353405 Utc . timestamp_opt ( 1742921669 , 250000000 ) . unwrap ( ) . into ( ) ,
@@ -360,6 +412,7 @@ mod tests {
360412 status : Annotated :: new ( SpanV2Status :: Ok ) ,
361413 kind : Annotated :: new ( SpanV2Kind :: Server ) ,
362414 is_remote : Annotated :: new ( true ) ,
415+ links : Annotated :: new ( links) ,
363416 attributes : Annotated :: new ( attributes) ,
364417 ..Default :: default ( )
365418 } ) ;
0 commit comments