open-telemetry/context
OpenTelemetry Context for PHP: immutable, execution-scoped context propagation for tracing and telemetry. Activate/detach scopes for implicit propagation, with debug warnings for scope leaks. Supports async apps with fiber-based propagation and event loop binding.
Installation:
composer require open-telemetry/context
Ensure PHP 8.1+ is used (fiber support requires PHP 8.1+).
First Use Case: Activate a context scope in a Laravel middleware or controller to propagate trace IDs:
use OpenTelemetry\Context\Context;
use OpenTelemetry\Context\Scope;
public function handle(Request $request, Closure $next): Response
{
$scope = Context::getCurrent()->activate();
try {
return $next($request);
} finally {
$scope->detach();
}
}
Where to Look First:
OpenTelemetry\Context\Context class for API reference.Use middleware to inject and propagate context:
// app/Http/Middleware/TraceMiddleware.php
public function handle($request, Closure $next)
{
$scope = Context::getCurrent()->activate();
try {
return $next($request);
} finally {
$scope->detach();
}
}
Tip: Register this middleware globally in app/Http/Kernel.php.
OTEL_PHP_FIBERS_ENABLED=true and ext-ffi:
// Preload autoloader for non-CLI SAPIs if ffi.enable=preload
require __DIR__ . '/vendor/autoload.php';
bindContext() for callbacks:
$loop->addPeriodicTimer(1, bindContext(function () {
// Context is automatically propagated
}));
Propagate context to Horizon/queue workers:
// app/Providers/AppServiceProvider.php
public function boot()
{
Queue::before(function (JobProcessing $event) {
$scope = Context::getCurrent()->activate();
try {
$event->job->handle();
} finally {
$scope->detach();
}
});
}
Attach metadata (e.g., user_id) to traces:
$context = Context::getCurrent()
->withBaggageItem('user_id', auth()->id());
$scope = $context->activate();
OpenTelemetry\Instrumentation\Guzzle to auto-propagate context.opentelemetry-php/db for SQL trace spans.Pusher/Ably adapters.handle():
public function handle()
{
$scope = Context::getCurrent()->activate();
try {
// Command logic
} finally {
$scope->detach();
}
}
Forgotten detach():
OTEL_PHP_DEBUG_SCOPES_DISABLED disables this).try-finally blocks. For async code, use bindContext() wrappers.Fiber Context Leaks:
OTEL_PHP_FIBERS_ENABLED=true and ensure ext-ffi is enabled.ZTS (Thread-Safe) PHP:
Non-CLI SAPIs with ffi.enable=preload:
vendor/autoload.php before fiber creation.Baggage Size Limits:
user_id, tenant_id).Enable Debug Scopes:
OTEL_PHP_DEBUG_SCOPES_DISABLED=false php artisan your:command
detach() calls in development.Inspect Current Context:
dd(Context::getCurrent()->getBaggage()->all());
Check Fiber Support:
if (!Context::isFiberSupportEnabled()) {
throw new RuntimeException('Fiber context propagation not enabled. Set OTEL_PHP_FIBERS_ENABLED=true.');
}
Custom Context Storage:
OpenTelemetry\Context\ContextStorageInterface for non-standard storage (e.g., Redis).Response Propagator:
ResponsePropagatorInterface (v1.4.0+) to inject context into HTTP responses:
$propagator = new ResponsePropagator();
$propagator->inject($context, $response);
Environment Context:
$context = Context::getCurrent()
->withEnvironment('tenant_id', $tenantId);
TextMap Propagation:
OpenTelemetry\Context\Propagator\TextMapPropagator for custom carrier formats (e.g., gRPC metadata).Disable Debug Scopes in Production:
OTEL_PHP_DEBUG_SCOPES_DISABLED=true php artisan queue:work
exit/die prevents detach().Fiber Preloading:
vendor/autoload.php is preloaded if ffi.enable=preload is set.Baggage Serialization:
$context->withBaggageItem('metadata', json_encode(['key' => 'value']));
How can I help you explore Laravel packages today?