@@ -65,7 +65,7 @@ impl Tracer {
65
65
span_kind : & api:: SpanKind ,
66
66
attributes : & [ api:: KeyValue ] ,
67
67
links : & [ api:: Link ] ,
68
- ) -> Option < ( u8 , Vec < api:: KeyValue > ) > {
68
+ ) -> Option < ( u8 , Vec < api:: KeyValue > , TraceState ) > {
69
69
let provider = self . provider ( ) ?;
70
70
let sampler = & provider. config ( ) . default_sampler ;
71
71
let sampling_result =
@@ -78,7 +78,7 @@ impl Tracer {
78
78
& self ,
79
79
sampling_result : sdk:: SamplingResult ,
80
80
parent_context : Option < & api:: SpanContext > ,
81
- ) -> Option < ( u8 , Vec < api:: KeyValue > ) > {
81
+ ) -> Option < ( u8 , Vec < api:: KeyValue > , TraceState ) > {
82
82
match sampling_result {
83
83
sdk:: SamplingResult {
84
84
decision : sdk:: SamplingDecision :: NotRecord ,
@@ -87,16 +87,26 @@ impl Tracer {
87
87
sdk:: SamplingResult {
88
88
decision : sdk:: SamplingDecision :: Record ,
89
89
attributes,
90
+ trace_state,
90
91
} => {
91
92
let trace_flags = parent_context. map ( |ctx| ctx. trace_flags ( ) ) . unwrap_or ( 0 ) ;
92
- Some ( ( trace_flags & !api:: TRACE_FLAG_SAMPLED , attributes) )
93
+ Some ( (
94
+ trace_flags & !api:: TRACE_FLAG_SAMPLED ,
95
+ attributes,
96
+ trace_state,
97
+ ) )
93
98
}
94
99
sdk:: SamplingResult {
95
100
decision : sdk:: SamplingDecision :: RecordAndSampled ,
96
101
attributes,
102
+ trace_state,
97
103
} => {
98
104
let trace_flags = parent_context. map ( |ctx| ctx. trace_flags ( ) ) . unwrap_or ( 0 ) ;
99
- Some ( ( trace_flags | api:: TRACE_FLAG_SAMPLED , attributes) )
105
+ Some ( (
106
+ trace_flags | api:: TRACE_FLAG_SAMPLED ,
107
+ attributes,
108
+ trace_state,
109
+ ) )
100
110
}
101
111
}
102
112
}
@@ -163,7 +173,7 @@ impl api::Tracer for Tracer {
163
173
. or_else ( || cx. remote_span_context ( ) . cloned ( ) )
164
174
. filter ( |cx| cx. is_valid ( ) ) ;
165
175
// Build context for sampling decision
166
- let ( no_parent, trace_id, parent_span_id, remote_parent, parent_trace_flags, trace_state ) =
176
+ let ( no_parent, trace_id, parent_span_id, remote_parent, parent_trace_flags) =
167
177
parent_span_context
168
178
. as_ref ( )
169
179
. map ( |ctx| {
@@ -173,7 +183,6 @@ impl api::Tracer for Tracer {
173
183
ctx. span_id ( ) ,
174
184
ctx. is_remote ( ) ,
175
185
ctx. trace_flags ( ) ,
176
- ctx. trace_state ( ) . clone ( ) ,
177
186
)
178
187
} )
179
188
. unwrap_or ( (
@@ -184,7 +193,6 @@ impl api::Tracer for Tracer {
184
193
api:: SpanId :: invalid ( ) ,
185
194
false ,
186
195
0 ,
187
- TraceState :: default ( ) ,
188
196
) ) ;
189
197
190
198
// There are 3 paths for sampling.
@@ -207,11 +215,17 @@ impl api::Tracer for Tracer {
207
215
// has parent that is local: use parent if sampled, or don't record.
208
216
parent_span_context
209
217
. filter ( |span_context| span_context. is_sampled ( ) )
210
- . map ( |_| ( parent_trace_flags, Vec :: new ( ) ) )
218
+ . map ( |span_context| {
219
+ (
220
+ parent_trace_flags,
221
+ Vec :: new ( ) ,
222
+ span_context. trace_state ( ) . clone ( ) ,
223
+ )
224
+ } )
211
225
} ;
212
226
213
227
// Build optional inner context, `None` if not recording.
214
- let inner = sampling_decision. map ( move |( trace_flags, mut extra_attrs) | {
228
+ let inner = sampling_decision. map ( move |( trace_flags, mut extra_attrs, trace_state ) | {
215
229
attribute_options. append ( & mut extra_attrs) ;
216
230
let mut attributes = sdk:: EvictedHashMap :: new ( config. max_attributes_per_span ) ;
217
231
for attribute in attribute_options {
@@ -263,3 +277,60 @@ impl api::Tracer for Tracer {
263
277
sdk:: Span :: new ( span_id, inner, self . clone ( ) )
264
278
}
265
279
}
280
+
281
+ #[ cfg( test) ]
282
+ mod tests {
283
+ use crate :: api:: {
284
+ Context , KeyValue , Link , Span , SpanBuilder , SpanContext , SpanId , SpanKind , TraceId ,
285
+ TraceState , Tracer , TracerProvider , TRACE_FLAG_SAMPLED ,
286
+ } ;
287
+ use crate :: sdk;
288
+ use crate :: sdk:: { Config , SamplingDecision , SamplingResult , ShouldSample } ;
289
+
290
+ #[ derive( Debug ) ]
291
+ struct TestSampler { }
292
+
293
+ impl ShouldSample for TestSampler {
294
+ fn should_sample (
295
+ & self ,
296
+ parent_context : Option < & SpanContext > ,
297
+ _trace_id : TraceId ,
298
+ _name : & str ,
299
+ _span_kind : & SpanKind ,
300
+ _attributes : & [ KeyValue ] ,
301
+ _links : & [ Link ] ,
302
+ ) -> SamplingResult {
303
+ let trace_state = parent_context. unwrap ( ) . trace_state ( ) . clone ( ) ;
304
+ SamplingResult {
305
+ decision : SamplingDecision :: RecordAndSampled ,
306
+ attributes : Vec :: new ( ) ,
307
+ trace_state : trace_state. insert ( "foo" . into ( ) , "notbar" . into ( ) ) . unwrap ( ) ,
308
+ }
309
+ }
310
+ }
311
+
312
+ #[ test]
313
+ fn allow_sampler_to_change_trace_state ( ) {
314
+ // Setup
315
+ let sampler = TestSampler { } ;
316
+ let config = Config :: default ( ) . with_default_sampler ( sampler) ;
317
+ let tracer_provider = sdk:: TracerProvider :: builder ( ) . with_config ( config) . build ( ) ;
318
+ let tracer = tracer_provider. get_tracer ( "test" , None ) ;
319
+ let context = Context :: default ( ) ;
320
+ let trace_state = TraceState :: from_key_value ( vec ! [ ( "foo" , "bar" ) ] ) . unwrap ( ) ;
321
+ let mut span_builder = SpanBuilder :: default ( ) ;
322
+ span_builder. parent_context = Some ( SpanContext :: new (
323
+ TraceId :: from_u128 ( 128 ) ,
324
+ SpanId :: from_u64 ( 64 ) ,
325
+ TRACE_FLAG_SAMPLED ,
326
+ true ,
327
+ trace_state,
328
+ ) ) ;
329
+
330
+ // Test sampler should change trace state
331
+ let span = tracer. build_with_context ( span_builder, & context) ;
332
+ let span_context = span. span_context ( ) ;
333
+ let expected = span_context. trace_state ( ) ;
334
+ assert_eq ! ( expected. get( "foo" ) , Some ( "notbar" ) )
335
+ }
336
+ }
0 commit comments