2
2
3
3
declare (strict_types=1 );
4
4
5
- namespace OpenTelemetry \API \ Trace \ Propagation ;
5
+ namespace OpenTelemetry \Extension \ Propagator \ B3 ;
6
6
7
7
use OpenTelemetry \API \Trace \AbstractSpan ;
8
8
use OpenTelemetry \API \Trace \SpanContext ;
14
14
use OpenTelemetry \Context \Propagation \TextMapPropagatorInterface ;
15
15
16
16
/**
17
- * B3Multi is a propagator that supports the specification for the header
18
- * "b3" used for trace context propagation across service boundaries.
19
- * (https://github.com/openzipkin/b3-propagation)
17
+ * B3Multi is a propagator that supports the specification for multiple
18
+ * "b3" http headers used for trace context propagation across service
19
+ * boundaries.
20
+ * (https://github.com/openzipkin/b3-propagation#multiple-headers)
20
21
*/
21
22
final class B3MultiPropagator implements TextMapPropagatorInterface
22
23
{
@@ -27,7 +28,7 @@ final class B3MultiPropagator implements TextMapPropagatorInterface
27
28
*
28
29
* @see https://github.com/openzipkin/b3-propagation#traceid-1
29
30
*/
30
- public const TRACE_ID = 'X-B3-TraceId ' ;
31
+ private const TRACE_ID = 'X-B3-TraceId ' ;
31
32
32
33
/**
33
34
* The X-B3-SpanId header is required and is encoded as 16 lower-hex characters.
@@ -36,7 +37,7 @@ final class B3MultiPropagator implements TextMapPropagatorInterface
36
37
*
37
38
* @see https://github.com/openzipkin/b3-propagation#spanid-1
38
39
*/
39
- public const SPAN_ID = 'X-B3-SpanId ' ;
40
+ private const SPAN_ID = 'X-B3-SpanId ' ;
40
41
41
42
/**
42
43
* The X-B3-ParentSpanId header must be present on a child span and absent on the root span.
@@ -45,7 +46,7 @@ final class B3MultiPropagator implements TextMapPropagatorInterface
45
46
*
46
47
* @see https://github.com/openzipkin/b3-propagation#parentspanid-1
47
48
*/
48
- public const PARENT_SPAN_ID = 'X-B3-ParentSpanId ' ;
49
+ private const PARENT_SPAN_ID = 'X-B3-ParentSpanId ' ;
49
50
50
51
/**
51
52
* An accept sampling decision is encoded as X-B3-Sampled: 1 and a deny as X-B3-Sampled: 0.
@@ -57,7 +58,7 @@ final class B3MultiPropagator implements TextMapPropagatorInterface
57
58
*
58
59
* @see https://github.com/openzipkin/b3-propagation#sampling-state-1
59
60
*/
60
- public const SAMPLED = 'X-B3-Sampled ' ;
61
+ private const SAMPLED = 'X-B3-Sampled ' ;
61
62
62
63
/**
63
64
* Debug is encoded as X-B3-Flags: 1.
@@ -66,12 +67,14 @@ final class B3MultiPropagator implements TextMapPropagatorInterface
66
67
*
67
68
* @see https://github.com/openzipkin/b3-propagation#debug-flag
68
69
*/
69
- public const DEBUG_FLAG = 'X-B3-Flags ' ;
70
+ private const DEBUG_FLAG = 'X-B3-Flags ' ;
70
71
71
72
private const IS_SAMPLED = '1 ' ;
73
+ private const VALID_SAMPLED = [self ::IS_SAMPLED , 'true ' ];
72
74
private const IS_NOT_SAMPLED = '0 ' ;
75
+ private const VALID_NON_SAMPLED = [self ::IS_NOT_SAMPLED , 'false ' ];
73
76
74
- public const FIELDS = [
77
+ private const FIELDS = [
75
78
self ::TRACE_ID ,
76
79
self ::SPAN_ID ,
77
80
self ::PARENT_SPAN_ID ,
@@ -107,17 +110,24 @@ public function inject(&$carrier, PropagationSetterInterface $setter = null, Con
107
110
return ;
108
111
}
109
112
113
+ // Inject multiple b3 headers
110
114
$ setter ->set ($ carrier , self ::TRACE_ID , $ spanContext ->getTraceId ());
111
115
$ setter ->set ($ carrier , self ::SPAN_ID , $ spanContext ->getSpanId ());
112
- $ setter ->set ($ carrier , self ::SAMPLED , $ spanContext ->isSampled () ? self ::IS_SAMPLED : self ::IS_NOT_SAMPLED );
116
+
117
+ $ debugValue = $ context ->get (B3DebugFlagContextKey::instance ());
118
+ if ($ debugValue && $ debugValue === self ::IS_SAMPLED ) {
119
+ $ setter ->set ($ carrier , self ::DEBUG_FLAG , self ::IS_SAMPLED );
120
+ } else {
121
+ $ setter ->set ($ carrier , self ::SAMPLED , $ spanContext ->isSampled () ? self ::IS_SAMPLED : self ::IS_NOT_SAMPLED );
122
+ }
113
123
}
114
124
115
125
public function extract ($ carrier , PropagationGetterInterface $ getter = null , Context $ context = null ): Context
116
126
{
117
127
$ getter ??= ArrayAccessGetterSetter::getInstance ();
118
128
$ context ??= Context::getCurrent ();
119
129
120
- $ spanContext = self ::extractImpl ($ carrier , $ getter );
130
+ $ spanContext = self ::extractImpl ($ carrier , $ getter, $ context );
121
131
if (!$ spanContext ->isValid ()) {
122
132
return $ context ;
123
133
}
@@ -133,39 +143,40 @@ private static function getSampledValue($carrier, PropagationGetterInterface $ge
133
143
return null ;
134
144
}
135
145
136
- if ($ value === ' 0 ' || $ value === ' 1 ' ) {
137
- return (int ) $ value ;
146
+ if (in_array ( strtolower ( $ value), self :: VALID_SAMPLED ) ) {
147
+ return (int ) self :: IS_SAMPLED ;
138
148
}
139
-
140
- if (strtolower ($ value ) === 'true ' ) {
141
- return 1 ;
142
- }
143
- if (strtolower ($ value ) === 'false ' ) {
144
- return 0 ;
149
+ if (in_array (strtolower ($ value ), self ::VALID_NON_SAMPLED )) {
150
+ return (int ) self ::IS_NOT_SAMPLED ;
145
151
}
146
152
147
153
return null ;
148
154
}
149
155
150
- private static function extractImpl ($ carrier , PropagationGetterInterface $ getter ): SpanContextInterface
156
+ private static function extractImpl ($ carrier , PropagationGetterInterface $ getter, Context & $ context ): SpanContextInterface
151
157
{
152
158
$ traceId = $ getter ->get ($ carrier , self ::TRACE_ID );
153
159
$ spanId = $ getter ->get ($ carrier , self ::SPAN_ID );
154
160
$ sampled = self ::getSampledValue ($ carrier , $ getter );
161
+ $ debug = $ getter ->get ($ carrier , self ::DEBUG_FLAG );
155
162
156
163
if ($ traceId === null || $ spanId === null ) {
157
164
return SpanContext::getInvalid ();
158
165
}
159
166
160
- // Validates the traceId, spanId and sampled
167
+ // Validates the traceId and spanId
161
168
// Returns an invalid spanContext if any of the checks fail
162
169
if (!SpanContext::isValidTraceId ($ traceId ) || !SpanContext::isValidSpanId ($ spanId )) {
163
170
return SpanContext::getInvalid ();
164
171
}
165
172
166
- $ isSampled = ($ sampled === SpanContext::SAMPLED_FLAG );
173
+ if ($ debug && $ debug === self ::IS_SAMPLED ) {
174
+ $ context = $ context ->with (B3DebugFlagContextKey::instance (), self ::IS_SAMPLED );
175
+ $ isSampled = SpanContext::SAMPLED_FLAG ;
176
+ } else {
177
+ $ isSampled = ($ sampled === SpanContext::SAMPLED_FLAG );
178
+ }
167
179
168
- // Only traceparent header is extracted. No tracestate.
169
180
return SpanContext::createFromRemoteParent (
170
181
$ traceId ,
171
182
$ spanId ,
0 commit comments