1
1
use rand:: Rng ;
2
2
use std:: fmt;
3
3
4
- use crate :: Headers ;
4
+ use crate :: headers:: { HeaderName , HeaderValue , Headers , TRACEPARENT } ;
5
+ use crate :: Status ;
5
6
6
- /// Extract and inject [Trace-Context](https://w3c.github.io/trace-context/) headers.
7
+ /// Extract and apply [Trace-Context](https://w3c.github.io/trace-context/) headers.
7
8
///
8
- /// ## Examples
9
+ /// # Examples
9
10
///
10
11
/// ```
12
+ /// # fn main() -> http_types::Result<()> {
13
+ /// #
11
14
/// use http_types::trace::TraceContext;
12
15
///
13
16
/// let mut res = http_types::Response::new(200);
@@ -17,14 +20,16 @@ use crate::Headers;
17
20
/// "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01"
18
21
/// );
19
22
///
20
- /// let context = TraceContext::extract (&res).unwrap();
23
+ /// let context = TraceContext::from_headers (&res)? .unwrap();
21
24
///
22
25
/// let trace_id = u128::from_str_radix("0af7651916cd43dd8448eb211c80319c", 16);
23
26
/// let parent_id = u64::from_str_radix("00f067aa0ba902b7", 16);
24
27
///
25
28
/// assert_eq!(context.trace_id(), trace_id.unwrap());
26
29
/// assert_eq!(context.parent_id(), parent_id.ok());
27
30
/// assert_eq!(context.sampled(), true);
31
+ /// #
32
+ /// # Ok(()) }
28
33
/// ```
29
34
#[ derive( Debug ) ]
30
35
pub struct TraceContext {
@@ -36,10 +41,44 @@ pub struct TraceContext {
36
41
}
37
42
38
43
impl TraceContext {
44
+ /// Generate a new TraceContect object without a parent.
45
+ ///
46
+ /// By default root TraceContext objects are sampled.
47
+ /// To mark it unsampled, call `context.set_sampled(false)`.
48
+ ///
49
+ /// # Examples
50
+ /// ```
51
+ /// use http_types::trace::TraceContext;
52
+ ///
53
+ /// let context = TraceContext::new();
54
+ ///
55
+ /// assert_eq!(context.parent_id(), None);
56
+ /// assert_eq!(context.sampled(), true);
57
+ /// ```
58
+ pub fn new ( ) -> Self {
59
+ let mut rng = rand:: thread_rng ( ) ;
60
+
61
+ Self {
62
+ id : rng. gen ( ) ,
63
+ version : 0 ,
64
+ trace_id : rng. gen ( ) ,
65
+ parent_id : None ,
66
+ flags : 1 ,
67
+ }
68
+ }
69
+
39
70
/// Create and return TraceContext object based on `traceparent` HTTP header.
40
71
///
41
- /// ## Examples
72
+ /// # Errors
73
+ ///
74
+ /// This function may error if the header is malformed. An error with a
75
+ /// status code of `400: Bad Request` will be generated.
76
+ ///
77
+ /// # Examples
78
+ ///
42
79
/// ```
80
+ /// # fn main() -> http_types::Result<()> {
81
+ /// #
43
82
/// use http_types::trace::TraceContext;
44
83
///
45
84
/// let mut res = http_types::Response::new(200);
@@ -48,65 +87,43 @@ impl TraceContext {
48
87
/// "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01"
49
88
/// );
50
89
///
51
- /// let context = TraceContext::extract (&res).unwrap();
90
+ /// let context = TraceContext::from_headers (&res)? .unwrap();
52
91
///
53
92
/// let trace_id = u128::from_str_radix("0af7651916cd43dd8448eb211c80319c", 16);
54
93
/// let parent_id = u64::from_str_radix("00f067aa0ba902b7", 16);
55
94
///
56
95
/// assert_eq!(context.trace_id(), trace_id.unwrap());
57
96
/// assert_eq!(context.parent_id(), parent_id.ok());
58
97
/// assert_eq!(context.sampled(), true);
98
+ /// #
99
+ /// # Ok(()) }
59
100
/// ```
60
- pub fn extract ( headers : impl AsRef < Headers > ) -> crate :: Result < Self > {
101
+ pub fn from_headers ( headers : impl AsRef < Headers > ) -> crate :: Result < Option < Self > > {
61
102
let headers = headers. as_ref ( ) ;
62
103
let mut rng = rand:: thread_rng ( ) ;
63
104
64
- let traceparent = match headers. get ( "traceparent" ) {
65
- Some ( header) => header. as_str ( ) ,
66
- None => return Ok ( Self :: new_root ( ) ) ,
105
+ let traceparent = match headers. get ( TRACEPARENT ) {
106
+ Some ( header) => header,
107
+ None => return Ok ( None ) ,
67
108
} ;
109
+ let parts: Vec < & str > = traceparent. as_str ( ) . split ( '-' ) . collect ( ) ;
68
110
69
- let parts: Vec < & str > = traceparent. split ( '-' ) . collect ( ) ;
70
-
71
- Ok ( Self {
111
+ Ok ( Some ( Self {
72
112
id : rng. gen ( ) ,
73
113
version : u8:: from_str_radix ( parts[ 0 ] , 16 ) ?,
74
- trace_id : u128:: from_str_radix ( parts[ 1 ] , 16 ) ?,
75
- parent_id : Some ( u64:: from_str_radix ( parts[ 2 ] , 16 ) ?) ,
76
- flags : u8:: from_str_radix ( parts[ 3 ] , 16 ) ?,
77
- } )
78
- }
79
-
80
- /// Generate a new TraceContect object without a parent.
81
- ///
82
- /// By default root TraceContext objects are sampled.
83
- /// To mark it unsampled, call `context.set_sampled(false)`.
84
- ///
85
- /// ## Examples
86
- /// ```
87
- /// use http_types::trace::TraceContext;
88
- ///
89
- /// let context = TraceContext::new_root();
90
- ///
91
- /// assert_eq!(context.parent_id(), None);
92
- /// assert_eq!(context.sampled(), true);
93
- /// ```
94
- pub fn new_root ( ) -> Self {
95
- let mut rng = rand:: thread_rng ( ) ;
96
-
97
- Self {
98
- id : rng. gen ( ) ,
99
- version : 0 ,
100
- trace_id : rng. gen ( ) ,
101
- parent_id : None ,
102
- flags : 1 ,
103
- }
114
+ trace_id : u128:: from_str_radix ( parts[ 1 ] , 16 ) . status ( 400 ) ?,
115
+ parent_id : Some ( u64:: from_str_radix ( parts[ 2 ] , 16 ) . status ( 400 ) ?) ,
116
+ flags : u8:: from_str_radix ( parts[ 3 ] , 16 ) . status ( 400 ) ?,
117
+ } ) )
104
118
}
105
119
106
120
/// Add the traceparent header to the http headers
107
121
///
108
- /// ## Examples
122
+ /// # Examples
123
+ ///
109
124
/// ```
125
+ /// # fn main() -> http_types::Result<()> {
126
+ /// #
110
127
/// use http_types::trace::TraceContext;
111
128
/// use http_types::{Request, Response, Url, Method};
112
129
///
@@ -116,20 +133,33 @@ impl TraceContext {
116
133
/// "00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01"
117
134
/// );
118
135
///
119
- /// let parent = TraceContext::extract (&req).unwrap();
136
+ /// let parent = TraceContext::from_headers (&req)? .unwrap();
120
137
///
121
138
/// let mut res = Response::new(200);
122
- /// parent.inject (&mut res);
139
+ /// parent.apply (&mut res);
123
140
///
124
- /// let child = TraceContext::extract (&res).unwrap();
141
+ /// let child = TraceContext::from_headers (&res)? .unwrap();
125
142
///
126
143
/// assert_eq!(child.version(), parent.version());
127
144
/// assert_eq!(child.trace_id(), parent.trace_id());
128
145
/// assert_eq!(child.parent_id(), Some(parent.id()));
146
+ /// #
147
+ /// # Ok(()) }
129
148
/// ```
130
- pub fn inject ( & self , mut headers : impl AsMut < Headers > ) {
149
+ pub fn apply ( & self , mut headers : impl AsMut < Headers > ) {
131
150
let headers = headers. as_mut ( ) ;
132
- headers. insert ( "traceparent" , format ! ( "{}" , self ) ) ;
151
+ headers. insert ( TRACEPARENT , self . value ( ) ) ;
152
+ }
153
+
154
+ /// Get the `HeaderName`.
155
+ pub fn name ( & self ) -> HeaderName {
156
+ TRACEPARENT
157
+ }
158
+
159
+ /// Get the `HeaderValue`.
160
+ pub fn value ( & self ) -> HeaderValue {
161
+ let output = format ! ( "{}" , self ) ;
162
+ unsafe { HeaderValue :: from_bytes_unchecked ( output. into ( ) ) }
133
163
}
134
164
135
165
/// Generate a child of the current TraceContext and return it.
@@ -175,29 +205,33 @@ impl TraceContext {
175
205
176
206
/// Returns true if the trace is sampled
177
207
///
178
- /// ## Examples
208
+ /// # Examples
179
209
///
180
210
/// ```
211
+ /// # fn main() -> http_types::Result<()> {
212
+ /// #
181
213
/// use http_types::trace::TraceContext;
182
214
/// use http_types::Response;
183
215
///
184
216
/// let mut res = Response::new(200);
185
217
/// res.insert_header("traceparent", "00-00000000000000000000000000000001-0000000000000002-01");
186
- /// let context = TraceContext::extract (&res).unwrap();
218
+ /// let context = TraceContext::from_headers (&res)? .unwrap();
187
219
/// assert_eq!(context.sampled(), true);
220
+ /// #
221
+ /// # Ok(()) }
188
222
/// ```
189
223
pub fn sampled ( & self ) -> bool {
190
224
( self . flags & 0b00000001 ) == 1
191
225
}
192
226
193
227
/// Change sampled flag
194
228
///
195
- /// ## Examples
229
+ /// # Examples
196
230
///
197
231
/// ```
198
232
/// use http_types::trace::TraceContext;
199
233
///
200
- /// let mut context = TraceContext::new_root ();
234
+ /// let mut context = TraceContext::new ();
201
235
/// assert_eq!(context.sampled(), true);
202
236
/// context.set_sampled(false);
203
237
/// assert_eq!(context.sampled(), false);
@@ -225,8 +259,8 @@ mod test {
225
259
#[ test]
226
260
fn default ( ) -> crate :: Result < ( ) > {
227
261
let mut headers = crate :: Headers :: new ( ) ;
228
- headers. insert ( "traceparent" , "00-01-deadbeef-00" ) ;
229
- let context = TraceContext :: extract ( & mut headers) ?;
262
+ headers. insert ( TRACEPARENT , "00-01-deadbeef-00" ) ;
263
+ let context = TraceContext :: from_headers ( & mut headers) ?. unwrap ( ) ;
230
264
assert_eq ! ( context. version( ) , 0 ) ;
231
265
assert_eq ! ( context. trace_id( ) , 1 ) ;
232
266
assert_eq ! ( context. parent_id( ) . unwrap( ) , 3735928559 ) ;
@@ -237,8 +271,7 @@ mod test {
237
271
238
272
#[ test]
239
273
fn no_header ( ) -> crate :: Result < ( ) > {
240
- let mut headers = crate :: Headers :: new ( ) ;
241
- let context = TraceContext :: extract ( & mut headers) ?;
274
+ let context = TraceContext :: new ( ) ;
242
275
assert_eq ! ( context. version( ) , 0 ) ;
243
276
assert_eq ! ( context. parent_id( ) , None ) ;
244
277
assert_eq ! ( context. flags, 1 ) ;
@@ -249,17 +282,17 @@ mod test {
249
282
#[ test]
250
283
fn not_sampled ( ) -> crate :: Result < ( ) > {
251
284
let mut headers = crate :: Headers :: new ( ) ;
252
- headers. insert ( "traceparent" , "00-01-02-00" ) ;
253
- let context = TraceContext :: extract ( & mut headers) ?;
285
+ headers. insert ( TRACEPARENT , "00-01-02-00" ) ;
286
+ let context = TraceContext :: from_headers ( & mut headers) ?. unwrap ( ) ;
254
287
assert_eq ! ( context. sampled( ) , false ) ;
255
288
Ok ( ( ) )
256
289
}
257
290
258
291
#[ test]
259
292
fn sampled ( ) -> crate :: Result < ( ) > {
260
293
let mut headers = crate :: Headers :: new ( ) ;
261
- headers. insert ( "traceparent" , "00-01-02-01" ) ;
262
- let context = TraceContext :: extract ( & mut headers) ?;
294
+ headers. insert ( TRACEPARENT , "00-01-02-01" ) ;
295
+ let context = TraceContext :: from_headers ( & mut headers) ?. unwrap ( ) ;
263
296
assert_eq ! ( context. sampled( ) , true ) ;
264
297
Ok ( ( ) )
265
298
}
0 commit comments