Skip to content

Commit 293e65c

Browse files
authored
Propagate Trace Context Level 2 random flag (#1731)
* Propagate Trace Context Level 2 random flag in `TraceContextPropagator` * Propagate Trace Context Level 2 random flag in SDK `SpanBuilder`
1 parent 79afe4f commit 293e65c

File tree

5 files changed

+52
-20
lines changed

5 files changed

+52
-20
lines changed

src/API/Trace/Propagation/TraceContextPropagator.php

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use OpenTelemetry\Context\Propagation\PropagationGetterInterface;
2020
use OpenTelemetry\Context\Propagation\PropagationSetterInterface;
2121
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
22+
use function sprintf;
2223

2324
/**
2425
* TraceContext is a propagator that supports the W3C Trace Context format
@@ -34,7 +35,8 @@ final class TraceContextPropagator implements TextMapPropagatorInterface
3435
{
3536
public const TRACEPARENT = 'traceparent';
3637
public const TRACESTATE = 'tracestate';
37-
private const VERSION = '00'; // Currently, only '00' is supported
38+
private const VERSION = 0x00; // Currently, only '00' is supported
39+
private const SUPPORTED_FLAGS = TraceFlags::SAMPLED | TraceFlags::RANDOM;
3840

3941
public const FIELDS = [
4042
self::TRACEPARENT,
@@ -72,7 +74,13 @@ public function inject(&$carrier, ?PropagationSetterInterface $setter = null, ?C
7274
}
7375

7476
// Build and inject the traceparent header
75-
$traceparent = self::VERSION . '-' . $spanContext->getTraceId() . '-' . $spanContext->getSpanId() . '-' . ($spanContext->isSampled() ? '01' : '00');
77+
$traceparent = sprintf(
78+
'%02x-%s-%s-%02x',
79+
self::VERSION,
80+
$spanContext->getTraceId(),
81+
$spanContext->getSpanId(),
82+
$spanContext->getTraceFlags() & self::SUPPORTED_FLAGS,
83+
);
7684
$setter->set($carrier, self::TRACEPARENT, $traceparent);
7785

7886
// Build and inject the tracestate header
@@ -128,33 +136,22 @@ private static function extractImpl($carrier, PropagationGetterInterface $getter
128136
}
129137

130138
// Return invalid if the trace version is not a future version but still has > 4 pieces.
131-
$versionIsFuture = hexdec($version) > hexdec(self::VERSION);
139+
$versionIsFuture = hexdec($version) > self::VERSION;
132140
if (count($pieces) > 4 && !$versionIsFuture) {
133141
return SpanContext::getInvalid();
134142
}
135143

136-
// Only the sampled flag is extracted from the traceFlags (00000001)
137-
$convertedTraceFlags = hexdec($traceFlags);
138-
$isSampled = ($convertedTraceFlags & TraceFlags::SAMPLED) === TraceFlags::SAMPLED;
139-
140144
// Tracestate = 'Vendor1=Value1,...,VendorN=ValueN'
141145
$rawTracestate = $getter->get($carrier, self::TRACESTATE);
142-
if ($rawTracestate !== null) {
143-
$tracestate = new TraceState($rawTracestate);
144-
145-
return SpanContext::createFromRemoteParent(
146-
$traceId,
147-
$spanId,
148-
$isSampled ? TraceFlags::SAMPLED : TraceFlags::DEFAULT,
149-
$tracestate
150-
);
151-
}
146+
$tracestate = $rawTracestate !== null
147+
? new TraceState($rawTracestate)
148+
: null;
152149

153-
// Only traceparent header is extracted. No tracestate.
154150
return SpanContext::createFromRemoteParent(
155151
$traceId,
156152
$spanId,
157-
$isSampled ? TraceFlags::SAMPLED : TraceFlags::DEFAULT
153+
hexdec($traceFlags) & self::SUPPORTED_FLAGS,
154+
$tracestate,
158155
);
159156
}
160157
}

src/API/Trace/TraceFlags.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
interface TraceFlags
88
{
99
public const SAMPLED = 0x01;
10+
public const RANDOM = 0x02;
1011
public const DEFAULT = 0x00;
1112
}

src/SDK/Trace/SpanBuilder.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,15 @@ public function startSpan(): API\SpanInterface
155155
$samplingDecision = $samplingResult->getDecision();
156156
$samplingResultTraceState = $samplingResult->getTraceState();
157157

158+
$flags = $parentSpanContext->getTraceFlags() & 0x2;
159+
if ($samplingDecision === SamplingResult::RECORD_AND_SAMPLE) {
160+
$flags |= API\TraceFlags::SAMPLED;
161+
}
162+
158163
$spanContext = API\SpanContext::create(
159164
$traceId,
160165
$spanId,
161-
SamplingResult::RECORD_AND_SAMPLE === $samplingDecision ? API\TraceFlags::SAMPLED : API\TraceFlags::DEFAULT,
166+
$flags,
162167
$samplingResultTraceState,
163168
);
164169

tests/Unit/API/Trace/Propagation/TraceContextPropagatorTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,18 @@ public function test_extract_future_version(): void
288288
);
289289
}
290290

291+
public function test_trace_context_level2_random_flag(): void
292+
{
293+
$traceparent = '00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-03';
294+
295+
$context = $this->traceContextPropagator->extract([TraceContextPropagator::TRACEPARENT => $traceparent]);
296+
$this->assertSame(TraceFlags::SAMPLED | TraceFlags::RANDOM, Span::fromContext($context)->getContext()->getTraceFlags());
297+
298+
$carrier = [];
299+
$this->traceContextPropagator->inject($carrier, context: $context);
300+
$this->assertSame($traceparent, $carrier[TraceContextPropagator::TRACEPARENT]);
301+
}
302+
291303
public function test_invalid_traceparent_version_0xff(): void
292304
{
293305
$this->assertInvalid([

tests/Unit/SDK/Trace/SpanBuilderTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44

55
namespace OpenTelemetry\Tests\Unit\SDK\Trace;
66

7+
use OpenTelemetry\API\Trace\Span;
8+
use OpenTelemetry\API\Trace\SpanContext;
79
use OpenTelemetry\API\Trace\SpanContextInterface;
810
use OpenTelemetry\API\Trace\SpanKind;
11+
use OpenTelemetry\API\Trace\TraceFlags;
12+
use OpenTelemetry\Context\Context;
913
use OpenTelemetry\SDK\Common\Attribute\AttributesFactoryInterface;
1014
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
1115
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScope;
@@ -85,4 +89,17 @@ public function test_start_span(): void
8589
$this->assertSame(123456, $span->toSpanData()->getStartEpochNanos());
8690
$this->assertCount(1, $span->toSpanData()->getLinks());
8791
}
92+
93+
public function test_start_span_keeps_trace_random_flag(): void
94+
{
95+
$this->sampler->method('shouldSample')->willReturn(new SamplingResult(SamplingResult::DROP));
96+
$this->idGenerator->method('generateSpanId')->willReturn(self::SPAN_ID);
97+
98+
$parent = SpanContext::create('4bf92f3577b34da6a3ce929d0e0e4736', '00f067aa0ba902b7', TraceFlags::SAMPLED | TraceFlags::RANDOM);
99+
$span = $this->builder
100+
->setParent(Span::wrap($parent)->storeInContext(Context::getCurrent()))
101+
->startSpan();
102+
103+
$this->assertSame(TraceFlags::RANDOM, $span->getContext()->getTraceFlags());
104+
}
88105
}

0 commit comments

Comments
 (0)