@@ -74,7 +74,9 @@ pub struct TransactionContext {
74
74
}
75
75
76
76
impl TransactionContext {
77
- /// Creates a new Transaction Context with the given `name` and `op`.
77
+ /// Creates a new Transaction Context with the given `name` and `op`. A random
78
+ /// `trace_id` is assigned. Use [`TransactionContext::new_with_trace_id`] to
79
+ /// specify a custom trace ID.
78
80
///
79
81
/// See <https://docs.sentry.io/platforms/native/enriching-events/transaction-name/>
80
82
/// for an explanation of a Transaction's `name`, and
@@ -85,13 +87,32 @@ impl TransactionContext {
85
87
/// can be used for distributed tracing.
86
88
#[ must_use = "this must be used with `start_transaction`" ]
87
89
pub fn new ( name : & str , op : & str ) -> Self {
88
- Self :: continue_from_headers ( name, op, std:: iter:: empty ( ) )
90
+ Self :: new_with_trace_id ( name, op, protocol:: TraceId :: default ( ) )
91
+ }
92
+
93
+ /// Creates a new Transaction Context with the given `name`, `op`, and `trace_id`.
94
+ ///
95
+ /// See <https://docs.sentry.io/platforms/native/enriching-events/transaction-name/>
96
+ /// for an explanation of a Transaction's `name`, and
97
+ /// <https://develop.sentry.dev/sdk/performance/span-operations/> for conventions
98
+ /// around an `operation`'s value.
99
+ #[ must_use = "this must be used with `start_transaction`" ]
100
+ pub fn new_with_trace_id ( name : & str , op : & str , trace_id : protocol:: TraceId ) -> Self {
101
+ Self {
102
+ name : name. into ( ) ,
103
+ op : op. into ( ) ,
104
+ trace_id,
105
+ parent_span_id : None ,
106
+ sampled : None ,
107
+ custom : None ,
108
+ }
89
109
}
90
110
91
111
/// Creates a new Transaction Context based on the distributed tracing `headers`.
92
112
///
93
- /// The `headers` in particular need to include the `sentry-trace` header,
94
- /// which is used to associate the transaction with a distributed trace.
113
+ /// The `headers` in particular need to include either the `sentry-trace` or W3C
114
+ /// `traceparent` header, which is used to associate the transaction with a distributed
115
+ /// trace. If both are present, `sentry-trace` takes precedence.
95
116
#[ must_use = "this must be used with `start_transaction`" ]
96
117
pub fn continue_from_headers < ' a , I : IntoIterator < Item = ( & ' a str , & ' a str ) > > (
97
118
name : & str ,
@@ -102,6 +123,11 @@ impl TransactionContext {
102
123
for ( k, v) in headers. into_iter ( ) {
103
124
if k. eq_ignore_ascii_case ( "sentry-trace" ) {
104
125
trace = parse_sentry_trace ( v) ;
126
+ break ;
127
+ }
128
+
129
+ if k. eq_ignore_ascii_case ( "traceparent" ) {
130
+ trace = parse_w3c_traceparent ( v) ;
105
131
}
106
132
}
107
133
@@ -858,6 +884,23 @@ fn parse_sentry_trace(header: &str) -> Option<SentryTrace> {
858
884
Some ( SentryTrace ( trace_id, parent_span_id, parent_sampled) )
859
885
}
860
886
887
+ /// Parses a W3C traceparent header.
888
+ /// Reference: <https://w3c.github.io/trace-context/#traceparent-header-field-values>
889
+ fn parse_w3c_traceparent ( header : & str ) -> Option < SentryTrace > {
890
+ let header = header. trim ( ) ;
891
+ let mut parts = header. splitn ( 4 , '-' ) ;
892
+
893
+ let _version = parts. next ( ) ?;
894
+ let trace_id = parts. next ( ) ?. parse ( ) . ok ( ) ?;
895
+ let parent_span_id = parts. next ( ) ?. parse ( ) . ok ( ) ?;
896
+ let parent_sampled = parts
897
+ . next ( )
898
+ . and_then ( |sampled| u8:: from_str_radix ( sampled, 16 ) . ok ( ) )
899
+ . map ( |flag| flag & 1 != 0 ) ;
900
+
901
+ Some ( SentryTrace ( trace_id, parent_span_id, parent_sampled) )
902
+ }
903
+
861
904
impl std:: fmt:: Display for SentryTrace {
862
905
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
863
906
write ! ( f, "{}-{}" , self . 0 , self . 1 ) ?;
@@ -890,6 +933,26 @@ mod tests {
890
933
assert_eq ! ( parsed, Some ( trace) ) ;
891
934
}
892
935
936
+ #[ test]
937
+ fn parses_traceparent ( ) {
938
+ let trace_id = protocol:: TraceId :: from_str ( "4bf92f3577b34da6a3ce929d0e0e4736" ) . unwrap ( ) ;
939
+ let parent_trace_id = protocol:: SpanId :: from_str ( "00f067aa0ba902b7" ) . unwrap ( ) ;
940
+
941
+ let trace =
942
+ parse_w3c_traceparent ( "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" ) ;
943
+ assert_eq ! (
944
+ trace,
945
+ Some ( SentryTrace ( trace_id, parent_trace_id, Some ( true ) ) )
946
+ ) ;
947
+
948
+ let trace =
949
+ parse_w3c_traceparent ( "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00" ) ;
950
+ assert_eq ! (
951
+ trace,
952
+ Some ( SentryTrace ( trace_id, parent_trace_id, Some ( false ) ) )
953
+ ) ;
954
+ }
955
+
893
956
#[ test]
894
957
fn disabled_forwards_trace_id ( ) {
895
958
let headers = [ (
0 commit comments