@@ -37,7 +37,8 @@ export const DEBUG_FLAG_KEY = Context.createKey(
37
37
const VALID_TRACEID_REGEX = / ^ ( [ 0 - 9 a - f ] { 16 } ) { 1 , 2 } $ / i;
38
38
const VALID_SPANID_REGEX = / ^ [ 0 - 9 a - f ] { 16 } $ / i;
39
39
const INVALID_ID_REGEX = / ^ 0 + $ / i;
40
- const VALID_SAMPLED_VALUES = [ true , 'true' , '1' ] ;
40
+ const VALID_SAMPLED_VALUES = [ true , 'true' , '1' , 1 ] ;
41
+ const VALID_UNSAMPLED_VALUES = [ 0 , '0' , 'false' , false ] ;
41
42
42
43
function isValidTraceId ( traceId : string ) : boolean {
43
44
return VALID_TRACEID_REGEX . test ( traceId ) && ! INVALID_ID_REGEX . test ( traceId ) ;
@@ -47,6 +48,18 @@ function isValidSpanId(spanId: string): boolean {
47
48
return VALID_SPANID_REGEX . test ( spanId ) && ! INVALID_ID_REGEX . test ( spanId ) ;
48
49
}
49
50
51
+ function isValidParentSpanID ( spanId : string | undefined ) : boolean {
52
+ return spanId === undefined || isValidSpanId ( spanId ) ;
53
+ }
54
+
55
+ function isValidSampledValue ( sampled : string | undefined ) : boolean {
56
+ return (
57
+ sampled === undefined ||
58
+ VALID_SAMPLED_VALUES . includes ( sampled ) ||
59
+ VALID_UNSAMPLED_VALUES . includes ( sampled )
60
+ ) ;
61
+ }
62
+
50
63
function parseHeader ( header : unknown ) {
51
64
return Array . isArray ( header ) ? header [ 0 ] : header ;
52
65
}
@@ -56,24 +69,78 @@ function parseHeader(header: unknown) {
56
69
* Based on: https://github.com/openzipkin/b3-propagation
57
70
*/
58
71
export class B3Propagator implements HttpTextPropagator {
72
+ _getHeaderValue ( carrier : unknown , getter : GetterFunction , key : string ) {
73
+ const header = getter ( carrier , key ) ;
74
+ return parseHeader ( header ) ;
75
+ }
76
+
77
+ _getTraceId ( carrier : unknown , getter : GetterFunction ) : string {
78
+ const traceId = this . _getHeaderValue ( carrier , getter , X_B3_TRACE_ID ) ;
79
+ if ( typeof traceId === 'string' ) {
80
+ return traceId . padStart ( 32 , '0' ) ;
81
+ }
82
+ return '' ;
83
+ }
84
+
85
+ _getSpanId ( carrier : unknown , getter : GetterFunction ) : string {
86
+ const spanId = this . _getHeaderValue ( carrier , getter , X_B3_SPAN_ID ) ;
87
+ if ( typeof spanId === 'string' ) {
88
+ return spanId ;
89
+ }
90
+ return '' ;
91
+ }
92
+
93
+ _getParentSpanId (
94
+ carrier : unknown ,
95
+ getter : GetterFunction
96
+ ) : string | undefined {
97
+ const spanId = this . _getHeaderValue ( carrier , getter , X_B3_PARENT_SPAN_ID ) ;
98
+ if ( typeof spanId === 'string' ) {
99
+ return spanId ;
100
+ }
101
+ return ;
102
+ }
103
+
104
+ _getDebug ( carrier : unknown , getter : GetterFunction ) : string | undefined {
105
+ const debug = this . _getHeaderValue ( carrier , getter , X_B3_FLAGS ) ;
106
+ return debug === '1' ? '1' : undefined ;
107
+ }
108
+
109
+ _getTraceFlags (
110
+ carrier : unknown ,
111
+ getter : GetterFunction
112
+ ) : TraceFlags | string | undefined {
113
+ const traceFlags = this . _getHeaderValue ( carrier , getter , X_B3_SAMPLED ) ;
114
+ const debug = this . _getDebug ( carrier , getter ) ;
115
+ if ( debug === '1' ) {
116
+ return TraceFlags . SAMPLED ;
117
+ } else if ( traceFlags !== undefined ) {
118
+ if ( VALID_SAMPLED_VALUES . includes ( traceFlags ) ) {
119
+ return TraceFlags . SAMPLED ;
120
+ } else if ( VALID_UNSAMPLED_VALUES . includes ( traceFlags ) ) {
121
+ return TraceFlags . NONE ;
122
+ } else {
123
+ return '' ;
124
+ }
125
+ }
126
+ return ;
127
+ }
128
+
59
129
inject ( context : Context , carrier : unknown , setter : SetterFunction ) {
60
130
const spanContext = getParentSpanContext ( context ) ;
61
131
if ( ! spanContext ) return ;
62
132
const parentSpanId = context . getValue ( PARENT_SPAN_ID_KEY ) ;
63
133
if (
64
134
isValidTraceId ( spanContext . traceId ) &&
65
- isValidSpanId ( spanContext . spanId )
135
+ isValidSpanId ( spanContext . spanId ) &&
136
+ isValidParentSpanID ( parentSpanId )
66
137
) {
67
- if ( parentSpanId ) {
68
- if ( isValidSpanId ( parentSpanId as string ) ) {
69
- setter ( carrier , X_B3_PARENT_SPAN_ID , parentSpanId ) ;
70
- } else {
71
- return ;
72
- }
73
- }
74
138
const debug = context . getValue ( DEBUG_FLAG_KEY ) ;
75
139
setter ( carrier , X_B3_TRACE_ID , spanContext . traceId ) ;
76
140
setter ( carrier , X_B3_SPAN_ID , spanContext . spanId ) ;
141
+ if ( parentSpanId ) {
142
+ setter ( carrier , X_B3_PARENT_SPAN_ID , parentSpanId ) ;
143
+ }
77
144
// According to the B3 spec, if the debug flag is set,
78
145
// the sampled flag shouldn't be propagated as well.
79
146
if ( debug === '1' ) {
@@ -93,36 +160,20 @@ export class B3Propagator implements HttpTextPropagator {
93
160
}
94
161
95
162
extract ( context : Context , carrier : unknown , getter : GetterFunction ) : Context {
96
- const traceIdHeader = getter ( carrier , X_B3_TRACE_ID ) ;
97
- const spanIdHeader = getter ( carrier , X_B3_SPAN_ID ) ;
98
- const parentSpanIdHeader = getter ( carrier , X_B3_PARENT_SPAN_ID ) ;
99
- const sampledHeader = getter ( carrier , X_B3_SAMPLED ) ;
100
- const flagsHeader = getter ( carrier , X_B3_FLAGS ) ;
101
-
102
- const traceIdHeaderValue = parseHeader ( traceIdHeader ) ;
103
- const spanId = parseHeader ( spanIdHeader ) ;
104
- const parentSpanId = parseHeader ( parentSpanIdHeader ) ;
105
- const options = parseHeader ( sampledHeader ) ;
106
- const debugHeaderValue = parseHeader ( flagsHeader ) ;
107
- const debug = debugHeaderValue === '1' ;
108
- const isSampled = VALID_SAMPLED_VALUES . includes ( options ) ;
109
- const traceFlags =
110
- debug || isSampled ? TraceFlags . SAMPLED : TraceFlags . NONE ;
163
+ const traceId = this . _getTraceId ( carrier , getter ) ;
164
+ const spanId = this . _getSpanId ( carrier , getter ) ;
165
+ const parentSpanId = this . _getParentSpanId ( carrier , getter ) ;
166
+ const traceFlags = this . _getTraceFlags ( carrier , getter ) ;
167
+ const debug = this . _getDebug ( carrier , getter ) ;
111
168
112
169
if (
113
- typeof traceIdHeaderValue !== 'string' ||
114
- typeof spanId !== 'string' ||
115
- ( typeof parentSpanIdHeader === 'string' && ! isValidSpanId ( parentSpanId ) )
170
+ isValidTraceId ( traceId ) &&
171
+ isValidSpanId ( spanId ) &&
172
+ isValidParentSpanID ( parentSpanId ) &&
173
+ isValidSampledValue ( traceFlags )
116
174
) {
117
- return context ;
118
- }
119
-
120
- context = context . setValue ( PARENT_SPAN_ID_KEY , parentSpanId ) ;
121
- context = context . setValue ( DEBUG_FLAG_KEY , debug ? '1' : undefined ) ;
122
-
123
- const traceId = traceIdHeaderValue . padStart ( 32 , '0' ) ;
124
-
125
- if ( isValidTraceId ( traceId ) && isValidSpanId ( spanId ) ) {
175
+ context = context . setValue ( PARENT_SPAN_ID_KEY , parentSpanId ) ;
176
+ context = context . setValue ( DEBUG_FLAG_KEY , debug ) ;
126
177
return setExtractedSpanContext ( context , {
127
178
traceId,
128
179
spanId,
0 commit comments