Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Zipkin Symfony Laravel Package

jcchavezs/zipkin-symfony

Zipkin integration for Symfony apps that adds distributed tracing to HTTP requests and other components, helping you collect and report spans to a Zipkin server for latency analysis and service dependency visibility.

View on GitHub
Deep Wiki
Context7

Getting Started

This bundle wires the openzipkin/zipkin PHP library into Symfony's DI container so you get a configured Zipkin\Tracing service out of the box, without hand-rolling reporters and samplers.

As of 3.1.0 (current release) the package supports PHP 7.4, 8.0 and 8.1, and pins the underlying openzipkin/zipkin library at 3.x. PHP 8.2/8.3 and Symfony 6/7 are not covered by the CI matrix — verify before adopting on a modern stack.

Minimal setup:

  1. composer require jcchavezs/zipkin-symfony (check the exact composer name in the release tarball — the repo is zipkin-instrumentation-symfony; the vendor/package string has historically differed from the repo slug).
  2. Register ZipkinBundle in config/bundles.php (needed on Symfony < Flex auto-registration; verify against your Symfony version).
  3. Create config/packages/zipkin.yaml:
zipkin:
    service_name: my-service
    endpoint: '%env(ZIPKIN_ENDPOINT)%'   # e.g. http://localhost:9411/api/v2/spans
    sampler:
        type: always                     # bound + rate for production
  1. Spin up Zipkin locally to verify:
docker run -d -p 9411:9411 openzipkin/zipkin
  1. Inject Zipkin\Tracing somewhere and create your first span:
public function indexAction(Tracing $tracing)
{
    $span = $tracing->getTracer()->nextSpan()->withName('homepage.render');
    $span->start();
    $span->tag('user.id', (string) $user->getId());
    // ... work ...
    $span->finish();
}

Where to look first: ZipkinBundle.php and DependencyInjection/Configuration.php in the package source — that tells you exactly which services are registered and which config keys are actually supported. The openzipkin/zipkin 3.0 docs cover the underlying Tracing/Tracer/Span API, which is where the real work happens.

First realistic use case: wrap a slow controller action or an outbound HTTP call, tag it with a couple of low-cardinality attributes, and confirm it appears in the Zipkin UI. Once you see one trace end-to-end, the API model clicks.

Implementation Patterns

Manual spans around a unit of work. This is the only instrumentation you can rely on; the bundle does not magically trace everything.

$span = $tracing->getTracer()->nextSpan()->withName('report.export');
$span->start();
try {
    $rows = $repository->export($params);
    $span->tag('rows', (string) count($rows));
    return $rows;
} catch (\Throwable $e) {
    $span->tag('error', 'true');
    $span->tag('error.message', $e->getMessage());
    throw $e;
} finally {
    $span->finish();
}

Outbound HTTP calls. Wrap Guzzle/PSR-18/Symfony HttpClient in one place (a shared decorator or middleware) so every external call becomes a client span with the target host as the span name and B3 headers injected:

$span = $tracing->getTracer()->nextSpan();
$span->setKind(Kind\CLIENT);
$child = $tracing->getTracer()->getCurrentSpan(); // parent = currently active span

Keep B3 (X-B3-TraceId, X-B3-SpanId, X-B3-ParentSpanId, X-B3-Sampled) consistent — single-header vs multi-header must match on both sides, or the downstream service starts a new trace instead of joining yours.

Inbound request context. Without a listener that reads the incoming B3 headers and calls SpanContext::createFromRemoteParent(...), incoming traces will not link to the sender. If you need true distributed tracing, add a small kernel request listener yourself — the bundle does not ship cross-service context propagation for free.

DBAL / Doctrine. Instantiate a middleware that opens a span per SQL statement with tags db.statement (bounded length), db.instance, and db.type. Register it in doctrine.dbal config. Keep the statement tag low-cardinality-safe by hashing or truncating if queries are highly variable.

Sampling strategy by environment. Always-on in dev, bounded in prod:

# config/packages/prod/zipkin.yaml
zipkin:
    sampler:
        type: bound
        rate: 0.05

Binary always/never for staging, ratio for production — this is the single biggest lever on reporter load and collector cost.

Console commands and Symfony Messenger. Wrap command handling in a span; for Messenger, capture the current trace context in the message envelope (a stamp with trace id/span id), then reconstruct the remote parent in the handler. This gives you async trace continuity across queues — a custom middleware on your side, not built into the bundle.

Gotchas and Tips

  • 3.1.0 is a maintenance/chore release, not a feature release. Two changes only: PHP 8.0/8.1 added to the support matrix, and the dependency moved to openzipkin/zipkin 3.0. No new config keys, no new instrumentation, no deprecations announced.
  • The Zipkin 3.0 bump is the one thing that can bite you. If you also depend on openzipkin/zipkin directly, or you wrote a custom reporter/sampler against the 2.x API (constructor signatures, Http reporter options, SpanContext factories), reconcile your code with 3.0 before upgrading. Composer conflicts here surface as an unresolvable dependency graph rather than a runtime error, so read the composer why-not output.
  • PHP 8.2/8.3 remain unsupported. The dependency bump does not widen the matrix beyond 8.1. On a modern Ubuntu/Heroku/Forge image you may hit deprecation noise or outright failures. Budget an afternoon to smoke-test, and be prepared to fork or vendor small fixes.
  • Maintenance signal is still weak. The last tagged releases were 3.0.1 (Dec 2021) and now 3.1.0; 27 stars, zero dependents. Treat it as a thin convenience wrapper you may end up owning — the amount of code (bundle + DI config) is small enough to take over.
  • You must flush before the process exits. The HTTP reporter accumulates spans; if the worker dies or the request finishes before a kernel.terminate flush, you silently lose data. Wire a kernel.terminate listener or a shutdown function to call $reporter->flush().
  • Reporter failures must not break the app. If Zipkin is down, the reporter should log and drop, not throw. Wrap reporter construction or verify its error handler path — losing tracing is acceptable, losing the request is not.
  • endpoint is the collector, not the UI. It is http://zipkin:9411/api/v2/spans. Pointing at :9411/ silently fails.
  • local_service_name is required and is what shows up as the service in the UI. Make it match your deployable (orders-api, not backend).
  • Tags are not logs. High-cardinality values (user ids, request ids, full URLs with query strings) blow up index size in the collector. Prefer a small tag set and route details to logs.
  • Never put PII or secrets in tags or span names. Trace data is copied to a collector and often retained longer than logs.
  • Span lifecycle discipline. start() / finish() in try/finally; tag() after finish() is a silent no-op in most implementations. Use Tracer::getCurrentSpan() to nest rather than passing spans through every function signature.
  • Extension point without forking: the bundle's service definitions are typically public-ish and parameter-driven — override zipkin.reporter or zipkin.sampler service definitions in services.yaml to swap in your own reporter (e.g., a log reporter for local debugging, or an OTLP bridge). Confirm aliases in ZipkinBundle/Resources/config/services.xml.
  • Debugging tips: first check ZIPKIN_ENDPOINT reachability with curl; then confirm the sampler is always in dev; then confirm finish() is being called; then check the reporter flush. After the 3.1.0 upgrade, also composer show openzipkin/zipkin to confirm you actually resolved to 3.x and not a stale pinned 2.x.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo