@@ -73,7 +73,9 @@ pub struct TransactionContext {
73
73
}
74
74
75
75
impl TransactionContext {
76
- /// Creates a new Transaction Context with the given `name` and `op`.
76
+ /// Creates a new Transaction Context with the given `name` and `op`. A random
77
+ /// `trace_id` is assigned. Use [`TransactionContext::new_with_trace_id`] to
78
+ /// specify a custom trace ID.
77
79
///
78
80
/// See <https://docs.sentry.io/platforms/native/enriching-events/transaction-name/>
79
81
/// for an explanation of a Transaction's `name`, and
@@ -84,13 +86,32 @@ impl TransactionContext {
84
86
/// can be used for distributed tracing.
85
87
#[ must_use = "this must be used with `start_transaction`" ]
86
88
pub fn new ( name : & str , op : & str ) -> Self {
87
- Self :: continue_from_headers ( name, op, std:: iter:: empty ( ) )
89
+ Self :: new_with_trace_id ( name, op, protocol:: TraceId :: default ( ) )
90
+ }
91
+
92
+ /// Creates a new Transaction Context with the given `name`, `op`, and `trace_id`.
93
+ ///
94
+ /// See <https://docs.sentry.io/platforms/native/enriching-events/transaction-name/>
95
+ /// for an explanation of a Transaction's `name`, and
96
+ /// <https://develop.sentry.dev/sdk/performance/span-operations/> for conventions
97
+ /// around an `operation`'s value.
98
+ #[ must_use = "this must be used with `start_transaction`" ]
99
+ pub fn new_with_trace_id ( name : & str , op : & str , trace_id : protocol:: TraceId ) -> Self {
100
+ Self {
101
+ name : name. into ( ) ,
102
+ op : op. into ( ) ,
103
+ trace_id,
104
+ parent_span_id : None ,
105
+ sampled : None ,
106
+ custom : None ,
107
+ }
88
108
}
89
109
90
110
/// Creates a new Transaction Context based on the distributed tracing `headers`.
91
111
///
92
- /// The `headers` in particular need to include the `sentry-trace` header,
93
- /// which is used to associate the transaction with a distributed trace.
112
+ /// The `headers` in particular need to include either the `sentry-trace` or W3C
113
+ /// `traceparent` header, which is used to associate the transaction with a distributed
114
+ /// trace. If both are present, `sentry-trace` takes precedence.
94
115
#[ must_use = "this must be used with `start_transaction`" ]
95
116
pub fn continue_from_headers < ' a , I : IntoIterator < Item = ( & ' a str , & ' a str ) > > (
96
117
name : & str ,
@@ -101,6 +122,11 @@ impl TransactionContext {
101
122
for ( k, v) in headers. into_iter ( ) {
102
123
if k. eq_ignore_ascii_case ( "sentry-trace" ) {
103
124
trace = parse_sentry_trace ( v) ;
125
+ break ;
126
+ }
127
+
128
+ if k. eq_ignore_ascii_case ( "traceparent" ) {
129
+ trace = parse_w3c_traceparent ( v) ;
104
130
}
105
131
}
106
132
@@ -808,6 +834,23 @@ fn parse_sentry_trace(header: &str) -> Option<SentryTrace> {
808
834
Some ( SentryTrace ( trace_id, parent_span_id, parent_sampled) )
809
835
}
810
836
837
+ /// Parses a W3C traceparent header.
838
+ /// Reference: <https://w3c.github.io/trace-context/#traceparent-header-field-values>
839
+ fn parse_w3c_traceparent ( header : & str ) -> Option < SentryTrace > {
840
+ let header = header. trim ( ) ;
841
+ let mut parts = header. splitn ( 4 , '-' ) ;
842
+
843
+ let _version = parts. next ( ) ?;
844
+ let trace_id = parts. next ( ) ?. parse ( ) . ok ( ) ?;
845
+ let parent_span_id = parts. next ( ) ?. parse ( ) . ok ( ) ?;
846
+ let parent_sampled = parts
847
+ . next ( )
848
+ . and_then ( |sampled| u8:: from_str_radix ( sampled, 16 ) . ok ( ) )
849
+ . map ( |flag| flag & 1 != 0 ) ;
850
+
851
+ Some ( SentryTrace ( trace_id, parent_span_id, parent_sampled) )
852
+ }
853
+
811
854
impl std:: fmt:: Display for SentryTrace {
812
855
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
813
856
write ! ( f, "{}-{}" , self . 0 , self . 1 ) ?;
@@ -840,6 +883,26 @@ mod tests {
840
883
assert_eq ! ( parsed, Some ( trace) ) ;
841
884
}
842
885
886
+ #[ test]
887
+ fn parses_traceparent ( ) {
888
+ let trace_id = protocol:: TraceId :: from_str ( "4bf92f3577b34da6a3ce929d0e0e4736" ) . unwrap ( ) ;
889
+ let parent_trace_id = protocol:: SpanId :: from_str ( "00f067aa0ba902b7" ) . unwrap ( ) ;
890
+
891
+ let trace =
892
+ parse_w3c_traceparent ( "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" ) ;
893
+ assert_eq ! (
894
+ trace,
895
+ Some ( SentryTrace ( trace_id, parent_trace_id, Some ( true ) ) )
896
+ ) ;
897
+
898
+ let trace =
899
+ parse_w3c_traceparent ( "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00" ) ;
900
+ assert_eq ! (
901
+ trace,
902
+ Some ( SentryTrace ( trace_id, parent_trace_id, Some ( false ) ) )
903
+ ) ;
904
+ }
905
+
843
906
#[ test]
844
907
fn disabled_forwards_trace_id ( ) {
845
908
let headers = [ (
0 commit comments