@@ -9,12 +9,12 @@ use opentelemetry::{
9
9
} ;
10
10
#[ cfg( feature = "activate_context" ) ]
11
11
use std:: cell:: RefCell ;
12
- use std:: fmt;
13
12
use std:: marker;
14
13
use std:: thread;
15
14
#[ cfg( not( all( target_arch = "wasm32" , not( target_os = "wasi" ) ) ) ) ]
16
15
use std:: time:: Instant ;
17
16
use std:: { any:: TypeId , borrow:: Cow } ;
17
+ use std:: { fmt, vec} ;
18
18
use tracing_core:: span:: { self , Attributes , Id , Record } ;
19
19
use tracing_core:: { field, Event , Subscriber } ;
20
20
#[ cfg( feature = "tracing-log" ) ]
@@ -1145,7 +1145,7 @@ where
1145
1145
fn on_follows_from ( & self , id : & Id , follows : & Id , ctx : Context < S > ) {
1146
1146
let span = ctx. span ( id) . expect ( "Span not found, this is a bug" ) ;
1147
1147
let mut extensions = span. extensions_mut ( ) ;
1148
- let _data = extensions
1148
+ let data = extensions
1149
1149
. get_mut :: < OtelData > ( )
1150
1150
. expect ( "Missing otel data span extensions" ) ;
1151
1151
@@ -1154,26 +1154,20 @@ where
1154
1154
// uses the same reasoning as `parent_context` above.
1155
1155
if let Some ( follows_span) = ctx. span ( follows) {
1156
1156
let mut follows_extensions = follows_span. extensions_mut ( ) ;
1157
- let _follows_data = follows_extensions
1157
+ let follows_data = follows_extensions
1158
1158
. get_mut :: < OtelData > ( )
1159
1159
. expect ( "Missing otel data span extensions" ) ;
1160
- // TODO:ban There are no tests that check this code :(
1161
- // TODO:ban if the follows span has a span builder the follows span should be _started_ here
1162
- // let follows_link = self.with_started_cx(follows_data, &|cx| {
1163
- // otel::Link::with_context(cx.span().span_context().clone())
1164
- // });
1165
- // let follows_context = self
1166
- // .tracer
1167
- // .sampled_context(follows_data)
1168
- // .span()
1169
- // .span_context()
1170
- // .clone();
1171
- // let follows_link = otel::Link::with_context(follows_context);
1172
- // if let Some(ref mut links) = data.builder.links {
1173
- // links.push(follows_link);
1174
- // } else {
1175
- // data.builder.links = Some(vec![follows_link]);
1176
- // }
1160
+ let follows_context =
1161
+ self . with_started_cx ( follows_data, & |cx| cx. span ( ) . span_context ( ) . clone ( ) ) ;
1162
+ if let Some ( builder) = data. builder . as_mut ( ) {
1163
+ if let Some ( ref mut links) = builder. links {
1164
+ links. push ( otel:: Link :: with_context ( follows_context) ) ;
1165
+ } else {
1166
+ builder. links = Some ( vec ! [ otel:: Link :: with_context( follows_context) ] ) ;
1167
+ }
1168
+ } else {
1169
+ data. parent_cx . span ( ) . add_link ( follows_context, vec ! [ ] ) ;
1170
+ }
1177
1171
}
1178
1172
}
1179
1173
@@ -2095,7 +2089,115 @@ mod tests {
2095
2089
assert_eq ! ( child1. parent_span_id, root. span_context. span_id( ) ) ;
2096
2090
assert_eq ! ( child2. parent_span_id, child1. span_context. span_id( ) ) ;
2097
2091
2098
- // This is surprising, the parent should be `child1`, but is 'root'.
2092
+ // The parent should be `child1`
2099
2093
assert_eq ! ( child3. parent_span_id, child1. span_context. span_id( ) ) ;
2100
2094
}
2095
+
2096
+ #[ test]
2097
+ fn follows_from_adds_link ( ) {
2098
+ use crate :: OpenTelemetrySpanExt ;
2099
+ let mut tracer = TestTracer :: default ( ) ;
2100
+ let subscriber = tracing_subscriber:: registry ( ) . with ( layer ( ) . with_tracer ( tracer. clone ( ) ) ) ;
2101
+
2102
+ let span1_id = tracing:: subscriber:: with_default ( subscriber, || {
2103
+ let span2 = tracing:: debug_span!( "span2" ) ;
2104
+ let span1 = tracing:: debug_span!( "span1" ) ;
2105
+
2106
+ // Ensure that span2 is started
2107
+ let _ = span2. context ( ) ;
2108
+
2109
+ // Establish follows_from relationship
2110
+ span2. follows_from ( & span1) ;
2111
+
2112
+ // Enter span2 to ensure it's exported
2113
+ let _guard = span2. enter ( ) ;
2114
+
2115
+ // Get span ID for later verification
2116
+ span1. context ( ) . span ( ) . span_context ( ) . span_id ( )
2117
+ } ) ;
2118
+
2119
+ let spans = tracer. spans ( ) ;
2120
+ // Check that both spans are exported
2121
+ assert_eq ! ( spans. len( ) , 2 , "Expected two spans to be exported" ) ;
2122
+ assert ! ( spans. iter( ) . any( |span| span. name == "span1" ) ) ;
2123
+ let span2 = spans
2124
+ . iter ( )
2125
+ . find ( |span| span. name == "span2" )
2126
+ . expect ( "Expected span2 to be exported" ) ;
2127
+
2128
+ // Collect span2 links
2129
+ let links = span2
2130
+ . links
2131
+ . iter ( )
2132
+ . map ( |link| link. span_context . span_id ( ) )
2133
+ . collect :: < Vec < _ > > ( ) ;
2134
+
2135
+ // Verify that span2 has a link to span1
2136
+ assert_eq ! (
2137
+ links. len( ) ,
2138
+ 1 ,
2139
+ "Expected span to have one link from follows_from relationship"
2140
+ ) ;
2141
+
2142
+ assert ! (
2143
+ links. contains( & span1_id) ,
2144
+ "Link should point to the correct source span"
2145
+ ) ;
2146
+ }
2147
+
2148
+ #[ test]
2149
+ fn follows_from_multiple_links ( ) {
2150
+ use crate :: OpenTelemetrySpanExt ;
2151
+ let mut tracer = TestTracer :: default ( ) ;
2152
+ let subscriber = tracing_subscriber:: registry ( ) . with ( layer ( ) . with_tracer ( tracer. clone ( ) ) ) ;
2153
+
2154
+ let ( span1_id, span2_id) = tracing:: subscriber:: with_default ( subscriber, || {
2155
+ let span3 = tracing:: debug_span!( "span3" ) ;
2156
+ let span2 = tracing:: debug_span!( "span2" ) ;
2157
+ let span1 = tracing:: debug_span!( "span1" ) ;
2158
+
2159
+ // Establish multiple follows_from relationships
2160
+ span3. follows_from ( & span1) ;
2161
+ span3. follows_from ( & span2) ;
2162
+
2163
+ // Enter span3 to ensure it's exported
2164
+ let _guard = span3. enter ( ) ;
2165
+
2166
+ // Get span IDs for later verification
2167
+ (
2168
+ span1. context ( ) . span ( ) . span_context ( ) . span_id ( ) ,
2169
+ span2. context ( ) . span ( ) . span_context ( ) . span_id ( ) ,
2170
+ )
2171
+ } ) ;
2172
+
2173
+ let spans = tracer. spans ( ) ;
2174
+ // Check that all three spans are exported
2175
+ assert_eq ! ( spans. len( ) , 3 , "Expected three spans to be exported" ) ;
2176
+ assert ! ( spans. iter( ) . any( |span| span. name == "span1" ) ) ;
2177
+ assert ! ( spans. iter( ) . any( |span| span. name == "span2" ) ) ;
2178
+ let span3 = spans
2179
+ . iter ( )
2180
+ . find ( |span| span. name == "span3" )
2181
+ . expect ( "Expected span3 to be exported" ) ;
2182
+
2183
+ // Collect span3 links
2184
+ let links = span3
2185
+ . links
2186
+ . iter ( )
2187
+ . map ( |link| link. span_context . span_id ( ) )
2188
+ . collect :: < Vec < _ > > ( ) ;
2189
+
2190
+ // Verify that span3 has multiple links and they point to the correct spans
2191
+ assert_eq ! (
2192
+ links. len( ) ,
2193
+ 2 ,
2194
+ "Expected span to have two links from follows_from relationships"
2195
+ ) ;
2196
+
2197
+ // Verify that the links point to the correct spans in the correct order
2198
+ assert ! (
2199
+ links[ 0 ] == span1_id && links[ 1 ] == span2_id,
2200
+ "Links should point to the correct source spans"
2201
+ ) ;
2202
+ }
2101
2203
}
0 commit comments