spatie/laravel-open-telemetry
Add OpenTelemetry tracing to Laravel to measure performance and follow requests across dispatched jobs and services. Export traces to tools like Jaeger or Aspecto for end-to-end visibility and debugging. (Package still in development.)
Installation:
composer require spatie/laravel-open-telemetry
php artisan vendor:publish --provider="Spatie\OpenTelemetry\OpenTelemetryServiceProvider"
Publish the config file to adjust exporters (e.g., OTLP, Jaeger, Zipkin).
First Use Case:
Enable OpenTelemetry in config/open-telemetry.php:
'enabled' => env('OPEN_TELEMETRY_ENABLED', false),
Set OPEN_TELEMETRY_ENABLED=true in your .env.
Verify Integration:
Run a request or job. Check your configured exporter (e.g., Jaeger UI at http://localhost:16686) for traces.
config/open-telemetry.php – Define exporters, sampling rate, and service name.app/Http/Middleware/TraceRequests.php – Auto-instrument HTTP requests.Spatie\OpenTelemetry\OpenTelemetryServiceProvider – Bootstraps the tracer.TraceRequests middleware automatically instruments incoming requests. No manual setup required beyond enabling the package.
// app/Http/Kernel.php
protected $middleware = [
// ...
\Spatie\OpenTelemetry\Middleware\TraceRequests::class,
];
traceJob helper or withTrace() method to instrument queue jobs:
use Spatie\OpenTelemetry\Facades\OpenTelemetry;
OpenTelemetry::traceJob('my-job', function () {
// Job logic
});
// OR via facade:
\Spatie\OpenTelemetry\Facades\OpenTelemetry::traceJob('my-job', fn() => $this->handle());
$span = OpenTelemetry::tracer()->startSpan('database-query');
try {
DB::table('users')->get();
} finally {
$span->end();
}
$context = OpenTelemetry::tracer()->getCurrentSpan()->getContext();
OpenTelemetry::tracer()->withContext($context, fn() => $this->callExternalService());
config/open-telemetry.php:
'exporters' => [
'otlp' => [
'endpoint' => env('OTLP_ENDPOINT', 'http://localhost:4318'),
'headers' => [],
],
'jaeger' => [
'endpoint' => env('JAEGER_ENDPOINT', 'http://localhost:14268/api/traces'),
],
],
'enabled_exporters' => ['otlp'], // or 'jaeger', 'zipkin'
'sampling' => [
'rate' => env('OPEN_TELEMETRY_SAMPLING_RATE', 0.1), // 10% of traces
'parentBased' => env('OPEN_TELEMETRY_PARENT_BASED_SAMPLING', false),
],
traceparent). The package auto-injects these headers for outgoing requests.spatie/laravel-query-logger or instrument queries manually:
$span = OpenTelemetry::tracer()->startSpan('query-users');
DB::enableQueryLog();
$users = User::all();
$span->setAttribute('db.query', $users->getQueryLog()[0]['query']);
$span->end();
config(['open-telemetry.enabled' => false]);
Performance Overhead:
0.1) and monitor. Use parentBased sampling for critical paths.config/open-telemetry.php for sampling settings.Exporter Configuration:
config:clear after changes.'debug' => env('OPEN_TELEMETRY_DEBUG', false),
Context Leaks:
withContext() for cross-service calls:
OpenTelemetry::tracer()->withContext($context, fn() => $this->externalCall());
traceparent headers in outgoing requests (use browser dev tools or tcpdump).Job Instrumentation:
OpenTelemetry::traceJob('my-job', fn() => $this->handle());
otel-redis).Middleware Order:
TraceRequests middleware placed after authentication may miss timing for auth logic.TraceRequests as early as possible in the middleware stack:
// app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
\Spatie\OpenTelemetry\Middleware\TraceRequests::class,
// ...
],
];
Enable Debug Mode:
'debug' => true,
This logs trace IDs and span events to Laravel logs.
Check Trace IDs:
public function handle($request, Closure $next)
{
$traceId = OpenTelemetry::tracer()->getCurrentSpan()?->getContext()->getTraceId();
Log::debug('Trace ID', ['trace_id' => $traceId]);
return $next($request);
}
Validate Exporter:
curl -X POST http://localhost:4318/v1/traces -H "Content-Type: application/json" -d '{}'
http://localhost:16686.Sampling Issues:
'sampling' => [
'rate' => 1.0, // Force 100% sampling for debugging
],
Custom Spans:
OpenTelemetry::tracer()->startSpan('custom-event', [
'attribute.key' => 'value',
]);
Exporter Plugins:
Spatie\OpenTelemetry\Contracts\Exporter:
class CustomExporter implements Exporter
{
public function export(array $spans): void
{
// Custom logic (e.g., send to Datadog, New Relic)
}
}
config/open-telemetry.php:
'exporters' => [
'custom' => \App\Exporters\CustomExporter::class,
],
Middleware Hooks:
TraceRequests to add custom attributes:
public function handle($request, Closure $next)
{
$span = OpenTelemetry::tracer()->startSpan('http-request');
$span->setAttribute('http.method', $request->method());
$span->setAttribute('http.path', $request->
How can I help you explore Laravel packages today?