composer require jcchavezs/zipkin-opentracing
.env):
ZIPKIN_ENDPOINT=http://localhost:9411/api/v2/spans
bootstrap/app.php or a service provider:
use OpenTracing\Tracer;
use Jcchavezs\Zipkin\ZipkinTracer;
$tracer = new ZipkinTracer('my-service', [
'collector_endpoint' => env('ZIPKIN_ENDPOINT'),
]);
Tracer::setGlobalTracer($tracer);
use OpenTracing\Span;
use OpenTracing\Tracer;
public function index()
{
$tracer = Tracer::get();
$span = $tracer->startSpan('controller.index');
$span->setTag('http.method', 'GET');
$span->setTag('http.url', '/');
try {
// Business logic here
$span->log(['event' => 'business_logic']);
} finally {
$span->finish();
}
}
Instrument an HTTP request (e.g., using illuminate/http middleware):
use OpenTracing\Tracer;
use OpenTracing\SpanContext;
public function handle($request, Closure $next)
{
$tracer = Tracer::get();
$span = $tracer->startSpan('http.request', [
'childOf' => SpanContext::fromContext($request->get('tracing_context'))
]);
$span->setTag('http.method', $request->method());
$span->setTag('http.url', $request->fullUrl());
try {
$response = $next($request);
$span->setTag('http.status_code', $response->getStatusCode());
return $response;
} finally {
$span->finish();
}
}
Wrap service method calls with spans to visualize dependencies:
public function fetchUserData(UserService $userService)
{
$tracer = Tracer::get();
$span = $tracer->startSpan('service.fetch_user_data');
try {
$user = $userService->getUser(1);
$span->setTag('user.id', $user->id);
return $user;
} finally {
$span->finish();
}
}
Instrument Eloquent queries or raw DB calls:
use OpenTracing\Tracer;
public function getUserWithOrders($userId)
{
$tracer = Tracer::get();
$span = $tracer->startSpan('db.query.user_with_orders');
$span->setTag('db.type', 'mysql');
$span->setTag('db.statement', 'SELECT * FROM users WHERE id = ?');
try {
$user = User::with('orders')->find($userId);
$span->log(['event' => 'query_executed', 'rows' => $user->orders->count()]);
return $user;
} finally {
$span->finish();
}
}
Correlate queue jobs with their parent spans:
use OpenTracing\Tracer;
use Illuminate\Bus\QueueingDispatcher;
public function dispatchJob($job, array $options = [])
{
$tracer = Tracer::get();
$parentSpan = Tracer::getActiveSpan();
$span = $tracer->startSpan('job.dispatch', [
'childOf' => $parentSpan ? $parentSpan->getContext() : null,
]);
$span->setTag('job.class', get_class($job));
try {
return $this->dispatchToQueue($job, $options, $span->getContext());
} finally {
$span->finish();
}
}
Instrument Guzzle or Symfony HTTP clients:
use OpenTracing\Tracer;
use GuzzleHttp\Client;
$client = new Client([
'handler' => HandlerStack::create([
new Middleware\TracingMiddleware(Tracer::get()),
]),
]);
$response = $client->get('https://api.example.com/data');
Pass spans across service boundaries (e.g., gRPC, message queues):
// Extract context from incoming request
$carrier = new HttpHeaders();
$extractor = new ZipkinExtractor();
$context = $extractor->extract($carrier, $headers);
// Inject context into outgoing request
$injector = new ZipkinInjector();
$injector->inject($context, $carrier);
Span Leaks:
try-finally to call $span->finish().Tracer::getActiveSpan() to check for active spans before starting new ones.Sampling Overhead:
$tracer = new ZipkinTracer('my-service', [
'collector_endpoint' => env('ZIPKIN_ENDPOINT'),
'sampler' => new CountingSampler(10), // Sample 1 in 10 traces
]);
Context Propagation Failures:
ZipkinExtractor/ZipkinInjector for HTTP.Tag Limits:
PHP 8+ Compatibility:
opentracing and zipkin dependencies are updated:
composer require opentracing/opentracing:^2.0 openzipkin/zipkin:^3.0
Verify Spans in Zipkin UI:
http://localhost:9411 for traces. Use the "Find Traces" feature to search by operation name or tags.Log Span Contexts:
$spanContext = $span->getContext();
\Log::debug('Span Context', [
'trace_id' => $spanContext->getTraceId(),
'span_id' => $spanContext->getSpanId(),
]);
Check for Malformed Data:
if ($span->getStartTimestamp() > time()) {
throw new \RuntimeException('Invalid span timestamp');
}
Throttling Errors:
429 Too Many Requests, reduce sampling rate or batch spans:
$tracer->send([$span1, $span2]); // Batch sends
Custom Samplers:
OpenTracing\Sampler to control trace sampling:
class ProbabilitySampler implements Sampler {
public function isSampled(array $context = null): bool {
return mt_rand() / mt_getrandmax() < 0.1; // 10% sampling
}
}
Custom Baggage:
$span->setBaggageItem('user.role', 'admin');
Span Filters:
$tracer->setSpanProcessor(new FilteringSpanProcessor(
new ZipkinSpanProcessor(),
function (Span $span) {
return !str_starts_with($span->getOperationName(), 'internal.');
}
));
Custom Reporters:
ZipkinReporter to add pre-send logic (e.g., logging):
class LoggingZipkinReporter extends ZipkinReporter {
public function report(Span $span) {
\Log::debug('Sending span to Zipkin', [
'operation' => $span->getOperationName(),
]);
parent::report($span);
}
}
Async Reporting:
AsyncZipkinReporter to avoid blocking:
$reporter = new AsyncZipkinReporter(
new ZipkinReporter($collectorEndpoint),
new React\EventLoop\Loop()
);
$tracer = new Zipkin
How can I help you explore Laravel packages today?