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 Laravel Laravel Package

open-telemetry/opentelemetry-auto-laravel

Automatic OpenTelemetry instrumentation for Laravel apps. It hooks into the framework to emit traces, metrics, and logs for HTTP requests, database queries, queue jobs, and more, with no manual code changes. Add it to get distributed tracing and observability out of the box.

View on GitHub
Deep Wiki
Context7

Getting Started

Understand what you're actually installing first. This is not a service provider you register in config/app.php. It's a set of _register.php hook definitions discovered at process boot by the native opentelemetry PHP extension, which globs vendor/open-telemetry/opentelemetry-auto-*. No extension → no hooks → no spans → no errors. Verify that before anything else:

pecl install opentelemetry
php -m | grep opentelemetry
php --ri opentelemetry

Minimum viable install:

composer require \
  open-telemetry/sdk \
  open-telemetry/exporter-otlp \
  open-telemetry/opentelemetry-auto-laravel

Then set these in the real process environment (php-fpm pool, systemd unit, Docker env) — not .env, which Laravel reads too late:

OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=my-laravel-app
OTEL_TRACES_EXPORTER=otlp
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

First use case — prove the pipeline before tuning anything. Point at the console exporter locally (OTEL_TRACES_EXPORTER=console, add open-telemetry/exporter-console) and hit one route that runs an Eloquent query. You should see a server span for the route plus child spans for the SQL. That single trace validates extension load, autoload discovery, exporter wiring, and sampler in one shot.

Where to look first:

  • vendor/open-telemetry/opentelemetry-auto-laravel/_register.php and src/LaravelInstrumentation.php — this is the documentation. It lists exactly which Laravel methods are hooked and what attributes each emits. Read it before assuming a span exists.
  • composer show open-telemetry/* — the resolved SDK/exporter versions are what you'll quote in bug reports.

Implementation Patterns

Enrich framework spans at the edges; don't replace them. The package gives you HTTP, DB, queue, and console spans for free. The day-to-day win is adding your own context via a global middleware:

public function handle($request, Closure $next)
{
    $span = \OpenTelemetry\API\Trace\Span::getCurrent();
    $span->setAttribute('enduser.id', $request->user()?->id ?? 'anonymous');
    $span->setAttribute('tenant.id', tenant()->id);
    return $next($request);
}

Span::getCurrent() returns whatever the instrumentation activated, so your app never imports the package directly — good for keeping vendor options open.

Custom spans inside business logic. Use Globals::getTracer() so you inherit the SDK the extension bootstrapped, and always scope-activate:

$tracer = \OpenTelemetry\API\Globals::getTracer('app.billing');
$span = $tracer->spanBuilder('invoice.generate')->startSpan();
$scope = $span->activate();
try {
    // work
} catch (\Throwable $e) {
    $span->recordException($e);
    $span->setStatus(\OpenTelemetry\API\Trace\StatusCode::STATUS_ERROR);
    throw $e;
} finally {
    $scope->detach();
    $span->end();
}

Wrap this in a small helper early — otherwise the boilerplate gets copy-pasted into every service class.

Queued jobs are the sharp edge. Inline (sync) dispatch stays in the same trace. For Redis/SQS/database drivers the worker is a separate process; verify whether the job span is a child or a new root on your version. If orphaned, inject the trace carrier on dispatch and extract it in a job middleware on the worker side.

Console, scheduler, and workers. Artisan commands get spans from the package's console hooks. Long-running processes (queue:work, horizon, schedule:work) interact with the SDK's auto-shutdown — see Gotchas.

Tune per environment. Local: console exporter for zero-infrastructure verification. Production: OTLP with a batch processor and ratio sampling:

OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.05
OTEL_BSP_MAX_EXPORT_BATCH_SIZE=512
OTEL_BSP_SCHEDULE_DELAY=1000

Silence noisy instrumentation without code changes. OTEL_PHP_DISABLED_INSTRUMENTATIONS=laravel disables this package entirely; useful for bisecting whether a span came from here or another auto-* package.

Test against an in-memory exporter, not the collector. Build a Sdk with an in-memory SpanExporter in a test base class, hit a route with $this->get('/orders'), and assert on span names/attributes. This catches the most likely regression: a Laravel upgrade that moves an internal method the hook targets.

Gotchas and Tips

  • .env is too late. The extension and SDK read OTEL_* at process start; Laravel reads .env during bootstrap. Variables in .env silently do nothing. Put them in the php-fpm pool (env[OTEL_...]), Docker, or systemd.
  • Failure is silent. Missing extension, missing OTEL_PHP_AUTOLOAD_ENABLED=true, or a vendor/ path the extension can't glob → zero spans, zero errors. Always confirm with the console exporter before blaming the backend.
  • Never move it to require-dev. The extension discovers the package in vendor/ at runtime. composer install --no-dev in production removes it and you lose all traces with no failure mode.
  • Version matrix is the #1 breakage source. Auto-* packages lag Laravel majors and pin sem-conv/API versions. After a framework upgrade, run composer why-not open-telemetry/opentelemetry-auto-laravel and check the hook targets in _register.php still exist.
  • Octane and long-running workers. Auto-shutdown flushes on process shutdown, which under Octane/Horizon is effectively "never." Build the SDK yourself with setAutoShutdown(false) and flush explicitly; watch for spans that never end and for state bleeding across requests.
  • OTEL_LOG_LEVEL=debug plus the collector's logs split "not instrumented" from "not exported." Do that before touching code.
  • Cardinality and PII. Route params, full SQL statements, and URLs with IDs bloat your backend and can leak data. Check whether db.statement is on by default in your version; redact at the collector rather than patching vendor code.
  • Double instrumentation. Adding Guzzle/PSR-18 auto-instrumentation alongside this can produce duplicate or nested outbound spans. Audit vendor/open-telemetry/opentelemetry-auto-* and disable what you don't need.
  • Health checks and dashboards (/up, /horizon, /telescope) will dominate span volume. Filter them at the collector, not in app code.
  • Extension points worth knowing: a custom SpanProcessor for tail-based enrichment, ResourceInfo for deployment metadata, and baggage for propagating tenant/user IDs across services. The package stops at span creation — everything downstream is standard OpenTelemetry PHP, so the SDK docs apply.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource