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

Opentelemetry Auto Symfony Laravel Package

open-telemetry/opentelemetry-auto-symfony

OpenTelemetry auto-instrumentation for Symfony adds zero-code tracing to your app, capturing HTTP requests, console commands, and framework activity as spans so you can send telemetry to any OpenTelemetry backend.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package and an exporter. The bundle only wires instrumentation; it does not ship a backend. You will usually need the SDK and OTLP exporter too:

    composer require open-telemetry/opentelemetry-auto-symfony \
        open-telemetry/sdk \
        open-telemetry/exporter-otlp
    
  2. Register the bundle in config/bundles.php (verify the exact class name in vendor/open-telemetry/opentelemetry-auto-symfony/src for your pinned version):

    return [
        // ...
        OpenTelemetry\Contrib\Symfony\OtelBundle::class => ['all' => true],
    ];
    
  3. Configure the SDK through environment variables, which is the least surprising path for Symfony deployments:

    OTEL_SERVICE_NAME=my-symfony-app
    OTEL_TRACES_EXPORTER=otlp
    OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
    OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
    OTEL_RESOURCE_ATTRIBUTES=deployment.environment=dev,service.version=1.0.0
    

    If your release uses the OpenTelemetry PHP extension hooks rather than a pure bundle, also install/enable the opentelemetry extension and set OTEL_PHP_AUTOLOAD_ENABLED=true.

  4. Clear the cache and make a request.

    bin/console cache:clear
    bin/console about
    

    Hit a normal route and confirm in your backend that you see an HTTP server span for the route with attributes such as http.request.method, url.path, and the response status code.

Where to look first: the package's README.md, src/OtelBundle.php (or _register.php), and its DependencyInjection configuration. This tells you exactly which Symfony components are auto-instrumented in your version. Then check your OpenTelemetry backend for a single end-to-end trace before adding manual spans.

First real use case: trace one business transaction end to end — browser request → Symfony controller → service layer → Doctrine query → outbound HTTP call. Use that trace to find the slow or missing segment, then add manual spans only where the auto-instrumentation is blind.

Implementation Patterns

Enrich the auto-created request span. Use a kernel event listener to attach domain attributes without creating a second server span:

use OpenTelemetry\API\Trace\Span;
use Symfony\Component\HttpKernel\Event\RequestEvent;

public function onKernelRequest(RequestEvent $event): void
{
    $span = Span::getCurrent();
    if ($span->isRecording()) {
        $span->setAttribute('enduser.id', $event->getRequest()->getUser()?->getUserIdentifier() ?? 'anonymous');
        $span->setAttribute('app.tenant', $event->getRequest()->headers->get('X-Tenant') ?? 'unknown');
    }
}

Instrument the service layer manually. Inject the tracer provider (add an alias in services.yaml if the bundle does not autowire it) and wrap meaningful operations:

use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\API\Trace\StatusCode;
use OpenTelemetry\API\Trace\TracerProviderInterface;

final class OrderService
{
    public function __construct(private TracerProviderInterface $tracerProvider) {}

    public function place(Order $order): void
    {
        $span = $this->tracerProvider
            ->getTracer('app.order')
            ->spanBuilder('order.place')
            ->setAttribute('order.id', $order->id)
            ->startSpan();

        $scope = $span->activate();

        try {
            // business logic
        } catch (\Throwable $e) {
            $span->recordException($e);
            $span->setStatus(StatusCode::STATUS_ERROR, $e->getMessage());
            throw $e;
        } finally {
            $scope->detach();
            $span->end();
        }
    }
}

Propagate context across boundaries. For outbound HTTP calls, inject the W3C traceparent header so the downstream service joins the same trace:

use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;

$carrier = [];
TraceContextPropagator::getInstance()->inject($carrier);

$client->request('GET', $url, ['headers' => $carrier]);

Messenger and long-running consumers. Create one span per handled message, and put the trace context into a StampInterface when dispatching. On the consumer side, extract it and activate the scope before handling the message. Detach and end the span in finally so long-running workers do not leak context between messages.

Console commands. Auto-instrumentation may cover command execution, but the useful span is usually the command's actual work. Add a child span named after the command with console.command and key arguments as attributes. Avoid putting free-form user input directly into span names.

Sampling and environments. Keep 100% sampling locally. In production start with OTEL_TRACES_SAMPLER=parentbased_traceidratio and OTEL_TRACES_SAMPLER_ARG=0.1, then tune. Use resource attributes for environment and version so traces can be filtered.

Testing. Set OTEL_SDK_DISABLED=true in test or use an in-memory exporter. Assert on span names and attributes rather than hitting a real collector.

Gotchas and Tips

  • Maturity risk. This is a read-only split of the upstream contrib repository with very low adoption. Pin the version, read the changelog for the exact release you install, and validate in staging before rolling to production. File issues upstream, not against the read-only mirror.
  • Missing spans usually mean configuration, not code. Check OTEL_SDK_DISABLED, exporter endpoint/protocol, OTEL_PHP_AUTOLOAD_ENABLED if extension-based, and whether the bundle is registered for the current environment. bin/console debug:container is useful for confirming services are present.
  • Clear the Symfony cache after config changes. Bundle registration and env changes are cached; stale container configuration is a common cause of "the bundle does nothing".
  • Batch processor can lose the last spans. In web requests, flush on kernel.terminate; in CLI and workers, call $tracerProvider->shutdown() or register a shutdown function. A fatal error or exit can bypass the batch processor entirely. Use the simple processor in development if you need immediate visibility.
  • Long-running processes need scope hygiene. Messenger workers, RoadRunner, and FrankenPHP worker mode keep the process alive; always detach() scopes and clear any per-request context. Otherwise spans from one message become children of the previous message's trace.
  • Avoid double instrumentation. If the bundle already creates a server span for the kernel, do not add another kernel listener that starts a second one. Look for duplicate spans with the same route before adding custom listeners.
  • Set span status deliberately. A 4xx response is not necessarily an error. Mark 5xx and exceptions as errors; leave client errors unset or record them as attributes.
  • Watch attribute cardinality and PII. Trace attributes can tolerate IDs more than metrics can, but raw URLs, emails, and tokens still leak into your backend. Redact or hash sensitive values.
  • Do not rely on the package alone for outbound calls. Verify whether your version instruments Symfony HttpClient, Guzzle, Doctrine DBAL, and Messenger. If a component is missing, add a small middleware or subscriber rather than assuming the bundle covers it.
  • Use the extension points instead of forking. Custom SpanProcessor, Sampler, and ResourceDetector implementations, or decorating TracerProviderInterface, are cleaner than modifying the bundle. This keeps you upgradeable.
  • Keep the OpenTelemetry bootstrap in one place. If the application already configures a TracerProvider, do not let the bundle silently build a second one. Confirm whether the bundle consumes OpenTelemetry\API\Globals or builds its own provider, and align the rest of the app with that choice.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core