OpenTelemetry Trace Context Propagation [PHP]
This guide covers PHP-specific implementation of context propagation. For a comprehensive overview of context propagation concepts, W3C TraceContext, propagators, and troubleshooting, see the OpenTelemetry Context Propagation guide.
Automatic propagation
OpenTelemetry PHP handles traceparent headers automatically in most scenarios. When using auto-instrumentation libraries, HTTP client libraries automatically inject traceparent headers into outgoing requests, and server libraries automatically extract them from incoming requests.
Auto-instrumentation
# Enable auto-instrumentation
export OTEL_PHP_AUTOLOAD_ENABLED=true
export OTEL_SERVICE_NAME=my-service
php my-application.php
Auto-instrumentation packages for HTTP clients and interfaces automatically inject W3C tracecontext headers to outgoing HTTP requests.
Manual propagation
When automatic instrumentation is not available, you can manually handle traceparent headers using OpenTelemetry's TraceContextPropagator API.
Extracting context
<?php
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
use OpenTelemetry\API\Trace\SpanKind;
// Extract context from incoming request headers
$context = TraceContextPropagator::getInstance()->extract($request->getHeaders());
// Create a new span with the extracted parent context
$span = $tracer->spanBuilder('HTTP ' . $_SERVER['REQUEST_METHOD'])
->setParent($context)
->setSpanKind(SpanKind::KIND_SERVER)
->startSpan();
$scope = $span->activate();
try {
// Your business logic here
processRequest();
} finally {
$span->end();
$scope->detach();
}
Injecting context
<?php
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
use GuzzleHttp\Psr7\Request;
// Create carrier array for headers
$carrier = [];
// Inject current trace context into carrier
TraceContextPropagator::getInstance()->inject($carrier);
// Create request with injected headers
$request = new Request('GET', 'http://example.com/api');
// Add trace headers to request
foreach ($carrier as $name => $value) {
$request = $request->withAddedHeader($name, $value);
}
// Send request
$client->send($request);
Debugging propagation
Logging context
Log incoming traceparent headers and current span context for debugging:
<?php
use OpenTelemetry\API\Trace\Span;
// Log incoming traceparent header
if (isset($_SERVER['HTTP_TRACEPARENT'])) {
error_log('Incoming traceparent: ' . $_SERVER['HTTP_TRACEPARENT']);
}
// Log current span context
$spanContext = Span::getCurrent()->getSpanContext();
if ($spanContext->isValid()) {
error_log(sprintf(
'Current trace context - TraceId: %s, SpanId: %s, Sampled: %s',
$spanContext->getTraceId(),
$spanContext->getSpanId(),
$spanContext->isSampled() ? 'true' : 'false'
));
} else {
error_log('No valid span context found');
}
Validating format
Validate traceparent headers to ensure they follow the W3C specification:
<?php
class TraceparentValidator
{
private const TRACEPARENT_PATTERN = '/^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/';
public static function isValidTraceparent(string $traceparent): bool
{
return !empty($traceparent) && preg_match(self::TRACEPARENT_PATTERN, $traceparent) === 1;
}
public static function parseTraceparent(string $traceparent): array
{
if (!self::isValidTraceparent($traceparent)) {
throw new InvalidArgumentException('Invalid traceparent format: ' . $traceparent);
}
$parts = explode('-', $traceparent);
return [
'version' => $parts[0],
'traceId' => $parts[1],
'spanId' => $parts[2],
'flags' => $parts[3],
'isSampled' => $parts[3] === '01'
];
}
}
Getting trace info
Access current trace context information:
<?php
use OpenTelemetry\API\Trace\Span;
function getTraceInfo(): array
{
$spanContext = Span::getCurrent()->getSpanContext();
if (!$spanContext->isValid()) {
return ['error' => 'No valid span context available'];
}
return [
'traceId' => $spanContext->getTraceId(),
'spanId' => $spanContext->getSpanId(),
'isSampled' => $spanContext->isSampled(),
'isRemote' => $spanContext->isRemote(),
];
}