jonahgeorge/jaeger-client-php
Jaeger client library for PHP with OpenTracing support. Create and propagate spans across services, report traces to a Jaeger agent/collector, and integrate distributed tracing into your PHP apps with configurable samplers, reporters, and transports.
Installation
composer require jonahgeorge/jaeger-client-php
Ensure your project uses PHP 8.0+ (recommended) and OpenTracing-compatible dependencies.
Basic Initialization
use Jaeger\Reporter\RemoteReporter;
use Jaeger\Sampler\ConstSampler;
use Jaeger\Sender\UdpSender;
use Jaeger\Tracer;
$reporter = new RemoteReporter(
new UdpSender('http://jaeger-collector:14268/api/traces', 5000)
);
$sampler = new ConstSampler(true); // Sample all traces
$tracer = new Tracer(
'my-service',
$reporter,
$sampler
);
First Use Case: Instrumenting a Request
use OpenTracing\Span;
use OpenTracing\Tracer as OpenTracingTracer;
$span = $tracer->startSpan('process-request');
$tracer->activateSpan($span);
try {
// Business logic here
$span->setTag('http.method', 'GET');
$span->log(['event' => 'request-started']);
} finally {
$span->finish();
}
vendor/jaeger-client-php/src/Jaeger/Tracer.php – Core tracer class.vendor/jaeger-client-php/src/Jaeger/Sampler/ – Sampling strategies.vendor/jaeger-client-php/src/Jaeger/Sender/ – Transport mechanisms (UDP/HTTP).Middleware Integration Use Laravel middleware to auto-instrument HTTP requests:
namespace App\Http\Middleware;
use Closure;
use Jaeger\Tracer;
use OpenTracing\Span;
class JaegerMiddleware
{
public function __construct(private Tracer $tracer) {}
public function handle($request, Closure $next)
{
$span = $this->tracer->startSpan('http-request');
$span->setTag('http.method', $request->method());
$span->setTag('http.path', $request->path());
try {
$response = $next($request);
$span->setTag('http.status', $response->status());
return $response;
} finally {
$span->finish();
}
}
}
Service-Level Instrumentation Wrap database queries, external API calls, or queues:
use OpenTracing\Span;
use OpenTracing\Scope;
public function fetchData()
{
$span = $this->tracer->startSpan('fetch-data');
$scope = $this->tracer->activateSpan($span);
try {
$data = Http::get('https://api.example.com/data');
$span->setTag('http.url', 'https://api.example.com/data');
return $data;
} finally {
$scope->detach();
$span->finish();
}
}
Context Propagation Pass spans across service boundaries (e.g., queues, HTTP clients):
// Producer (e.g., queue job)
$span = $this->tracer->startSpan('process-order');
$this->tracer->inject(
$span->context(),
['HTTP_HEADERS'], // or 'TEXT_MAP'
$carrier = []
);
Queue::push(new OrderProcessedJob($order, $carrier));
// Consumer (e.g., queue worker)
$this->tracer->extract(
SpanContext::createFromBaggage($carrier['X-B3-TraceId'], ...),
'TEXT_MAP'
);
public function register()
{
$this->app->singleton(Tracer::class, function ($app) {
return new Tracer(
'laravel-app',
new RemoteReporter(new UdpSender('jaeger:14268')),
new ConstSampler(false) // Adjust sampling rate
);
});
}
.env for dynamic settings:
JAEGER_AGENT_HOST=jaeger
JAEGER_SAMPLE_RATE=0.1
Log::debug('Processing order', [
'trace_id' => $this->tracer->activeSpan()->context()->traceId(),
]);
Sampling Overhead
ConstSampler(true)) can flood Jaeger with data.ProbabilisticSampler or RateLimitingSampler:
$sampler = new ProbabilisticSampler(0.1); // 10% sampling
http.path).Context Leaks
finally blocks or context managers:
$scope = $this->tracer->activateSpan($span);
try { /* ... */ } finally { $scope->detach(); }
OPENTRACING_DEBUG=1 to log context lifecycle.Transport Failures
$sender = new HttpSender('http://jaeger-collector:14250/api/traces');
jaeger-client-php logs for SenderException.Baggage Propagation
extract()/inject():
$this->tracer->inject($span->context(), ['TEXT_MAP'], $carrier, [
'user_id' => auth()->id(),
]);
putenv('OPENTRACING_DEBUG=1');
jaeger-cli query --service=my-service
span.kind (e.g., server, client).http.method/http.url for HTTP spans.error tag for failed operations.AbstractReporter to batch or filter spans:
class FilteredReporter extends AbstractReporter {
public function report(Span $span) {
if ($span->getTag('sensitive')) return;
parent::report($span);
}
}
Sampler to adjust rates based on conditions:
class ConditionalSampler implements Sampler {
public function isSampled(SpanContext $spanContext) {
return request()->ip() === '127.0.0.1'; // Sample locally
}
}
Debugbar::addCollector(new class {
public function collect() {
return [
'jaeger' => [
'active_span' => $this->tracer->activeSpan()?->operationName(),
],
];
}
});
How can I help you explore Laravel packages today?