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