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

Laravel Otel Laravel Package

plunkettscott/laravel-otel

OpenTelemetry integration for Laravel that instruments HTTP requests, database queries, queues, and console commands to emit traces, metrics, and logs through OTLP exporters, with middleware, service provider wiring, and publishable config.

View on GitHub
Deep Wiki
Context7

Getting Started

plunkettscott/laravel-otel wires Laravel into the OpenTelemetry PHP SDK, giving you traces, metrics, and log correlation with minimal code changes.

  1. Install and publish config
    composer require plunkettscott/laravel-otel
    php artisan vendor:publish --tag=otel-config
    
  2. Point it at a collector — this package exports OTLP; it does not ship a backend. Set in .env:
    OTEL_SERVICE_NAME=my-laravel-app
    OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
    OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
    OTEL_TRACES_EXPORTER=otlp
    
  3. Look here first, in this order:
    • config/otel.php — service name, exporters, sampler, and the list of enabled watchers.
    • The package service provider — shows which framework events get auto-instrumented.
    • The watcher classes — the best documentation of what attributes each span carries.
  4. First use case: boot a local collector (Grafana otel-lgtm or otel/opentelemetry-collector + Jaeger is fastest), hit a route that does a DB query and dispatches a job, and confirm the request span, child query spans, and queue span all appear under one trace. That single smoke test validates endpoint, protocol, propagation, and flushing at once.

Implementation Patterns

Lean on auto-instrumentation first. Most of the value is in the watchers you enable in config — HTTP requests, DB queries, queue jobs, cache/Redis, and scheduled commands. Turn on one watcher at a time and inspect the span tree in your backend before writing any manual code.

Manual spans for domain work. Wrap business operations so they show up as named children rather than anonymous time inside a request:

$tracer = app(\OpenTelemetry\API\Trace\TracerInterface::class);

$span = $tracer->spanBuilder('invoice.generate')->startSpan();
try {
    $span->setAttribute('invoice.id', $invoice->id);
    // ...
} finally {
    $span->end();
}

Prefer a small action/middleware wrapper over sprinkling try/finally through controllers.

Propagate context into queued work. Queue spans are only useful if the trace continues across the job boundary. Verify a dispatched job's span shares the trace_id of the dispatching request; if it doesn't, the queue watcher isn't registering the job event or your queue driver bypasses the normal dispatch path.

Scheduled tasks. The ScheduleWatcherOptions object configures how scheduled commands are traced — span naming and the attributes attached to each run. The v0.4.2 release (Fix ScheduleWatcherOptions) corrects how those options are applied. If you set naming or attribute options on this object and saw them silently ignored, that fix is your reason to upgrade; if you don't trace the scheduler, the patch is inert for you.

Log correlation. Once traces are active, push trace_id/span_id into the log context (a Monolog processor or a logging channel tap) so you can pivot from a log line in your aggregator straight to the trace in Tempo/Jaeger.

Sampling by environment. Sample everything locally, and use a ratio or parent-based sampler in production. Keep the sampler decision in config driven by env, not hardcoded.

Testing. Disable the exporter in phpunit.xml (OTEL_SDK_DISABLED=true or a null exporter) so the suite doesn't block on a network endpoint, and assert on behaviour rather than emitted spans — span assertions are brittle against SDK upgrades.

Gotchas and Tips

  • Protocol/endpoint mismatch is the #1 failure. 4317 is gRPC, 4318 is HTTP. Setting http/protobuf against :4317 (or vice versa) typically fails quietly — no spans, no exception. If your backend is empty, check this before anything else.
  • Spans vanish in short-lived processes. The batch processor needs a flush at shutdown. Artisan commands, queue workers, and Octane workers can drop spans if the SDK isn't shut down cleanly. For CLI-heavy code paths, prefer the simple processor or confirm the package registers a terminating flush.
  • config:cache shadows env(). If your config/otel.php reads env vars, changes to .env won't apply until php artisan config:clear. Always re-cache after editing OTel settings in deploy scripts.
  • ScheduleWatcherOptions behaviour changed in 0.4.2. This is a bug fix, not a breaking change, but the effective configuration of your scheduler spans may differ from what you observed on 0.4.1. If you tuned scheduler options against the buggy behaviour, re-check your span names and attributes after upgrading.
  • Cardinality will hurt you. Never put raw user IDs, URLs with identifiers, or exception messages into metric attributes. Keep those on spans; keep metrics to low-cardinality dimensions like route template and status code.
  • Exception recording isn't automatic for manual spans. Use $span->recordException($e) and set the status explicitly, or your custom spans will look healthy while the request 500s.
  • Extension points: custom watchers for framework events the package doesn't cover, and container bindings to swap the exporter/processor — both are cleaner than forking. Bind replacements in a service provider rather than editing vendor config.
  • Treat this as 0.x. At 0.4.x the config keys and watcher APIs can shift between minor versions. Pin the version in composer.json, read the changelog before each bump, and keep manual instrumentation behind small wrappers so SDK churn is a one-file change.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource