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

Exporter Otlp Laravel Package

open-telemetry/exporter-otlp

OTLP exporter for OpenTelemetry PHP, sending traces over HTTP or gRPC. Configure the HTTP transport with a collector endpoint and content type, or install the gRPC transport package. For production, use the protobuf C extension for significantly faster exporting.

View on GitHub
Deep Wiki
Context7

Getting Started

The OTLP exporter is the plumbing that ships telemetry out of your Laravel app to any OTLP-compatible backend (OTEL Collector, Jaeger, Grafana Tempo, Honeycomb, Datadog OTLP intake, AWS ADOT, etc.). It does not instrument anything on its own — you still need open-telemetry/sdk (and optionally open-telemetry/opentelemetry-laravel or manual instrumentation) to create spans, metrics, and log records.

Minimal install:

composer require open-telemetry/exporter-otlp open-telemetry/sdk google/protobuf
# production: replace the native protobuf lib's runtime with the C extension
pecl install protobuf

Point the SDK at your collector with environment variables (these are the config surface most day-to-day work touches):

OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer%20xxxxx
OTEL_SERVICE_NAME=my-laravel-app

Then wire the exporter into a tracer provider — typically in a service provider:

use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;
use OpenTelemetry\SDK\Trace\TracerProvider;

$transport = (new OtlpHttpTransportFactory())
    ->create('http://collector:4318', 'application/x-protobuf');
$exporter = new SpanExporter($transport);

$tracerProvider = new TracerProvider(
    new BatchSpanProcessor($exporter)
);

First use case worth validating: run a local collector (docker run -p 4318:4318 otel/opentelemetry-collector) with a debug exporter in its pipeline, hit a route, and confirm spans appear. If they don't, you've isolated the problem to the app (SDK provider not registered, span not ended, batch not flushed) rather than the backend.

Where to look first:

  • examples/traces/exporters/otlp_http.php in the opentelemetry-php monorepo — canonical HTTP wiring.
  • The upstream exporter docs page: https://opentelemetry.io/docs/instrumentation/php/exporters/#otlp.
  • The spec's exporter env var section — every OTEL_EXPORTER_OTLP_* variable you rely on is defined there, and this SDK follows it.

Implementation Patterns

HTTP vs gRPC transport. Default to HTTP/protobuf; it works with stock PHP (no ext-grpc), is easy to debug with curl against the collector, and survives most shared hosting/FPM setups. Only reach for gRPC when your backend or platform team mandates it, and budget for pecl install grpc plus composer require open-telemetry/transport-grpc. gRPC does give you better throughput on high-volume services.

Batch, don't broadcast. Use BatchSpanProcessor in web requests — it buffers spans and flushes them off-request, which keeps p99 latency intact in high-traffic apps. Use SimpleSpanProcessor only in tests and short-lived CLI scripts where the process ends immediately and you control the lifecycle.

Signal-specific exporters. The same package gives you SpanExporter, MetricExporter (a PushMetricExporter), and LogExporter. They are independent — you can ship traces to a collector and metrics to a vendor, or emit only traces initially and add metrics later without touching the provider wiring. Since 1.2.0 there's also an OTLP file exporter (OtlpFileExporter), which is invaluable for "I want to see the actual OTLP payload" debugging and for capturing telemetry to disk in environments without a collector.

Singleton the providers, not the tracer. Register TracerProvider (and MeterProvider / LoggerProvider) as singletons in a Laravel service provider, resolve the Tracer from them in request-scoped code. Providers own background state and connections; tracers are cheap.

Headers for managed backends. Almost every SaaS backend authenticates via OTEL_EXPORTER_OTLP_HEADERS. Values must be URL-encoded key=value pairs separated by commas (e.g. x-honeycomb-team=abc123,x-api-key=def). Put this in config/services.php / .env per environment, not in code, and never log the value.

Resource attributes early. OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,service.version=1.2.3 is the cheapest way to get useful correlation in your backend. Set OTEL_SERVICE_NAME too — the collector and most UIs use it as the primary grouping key.

Middleware-style spans, not controller-level ones. A single handle() wrapper that starts a span, tags it with route, HTTP method, user id (hashed), and ends it in a finally gives you coverage for free. Instrument queue jobs and scheduled commands the same way — those are the traces that actually surface production incidents, and they're the ones teams forget.

Sampling at the SDK. Parent-based ratio sampling (OTEL_TRACES_SAMPLER=parentbased_traceidratio, OTEL_TRACES_SAMPLER_ARG=0.1) is set once and works across services because the sampling decision propagates via trace context. Don't try to "sample in the collector" as your first move — it's more expensive and less consistent.

Temporality for metrics. OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE (delta vs cumulative) must match what your backend expects. Cumulative is the default and works with Prometheus-style backends; delta is what some SaaS vendors and high-cardinality counters prefer.

Gotchas and Tips

Native protobuf is a production foot-gun. google/protobuf in pure PHP is dramatically slower and more memory-hungry than ext-protobuf. On a busy Laravel app under load, the difference is visible in CPU profiles. Install the C extension in your production image and verify with php -m | grep protobuf in CI. Watch for version skew: google/protobuf ^4.31 combined with ext-protobuf <4.31 historically triggered a TypeError in serializeToJsonString(); 1.3.1 shipped a guard for it, so pin both together and keep the exporter current.

Endpoints are base URLs. Pass http://collector:4318, not http://collector:4318/v1/traces. The transport appends /v1/traces, /v1/metrics, and /v1/logs per signal. A "404 on export" almost always means someone included the path twice or used the gRPC port (4317) with the HTTP transport.

Headers are URL-encoded. Release 1.0.4 added support for URL-encoded OTEL_EXPORTER_OTLP_HEADERS. If you have a bearer token or key with =, ,, : or spaces, encode the value — otherwise the parser splits it in the wrong place and you get a confusing 401 rather than a config error.

Flush before you exit. BatchSpanProcessor will not necessarily ship queued spans when a PHP-FPM worker finishes. In web requests this is usually fine, but in queue workers, artisan commands, and anything under Laravel Octane you need an explicit forceFlush() in a shutdown/terminating hook. With Octane specifically, remember the singleton provider persists across requests — don't let spans leak between requests and don't recreate the provider per request.

Timeouts are your responsibility. Per-request HTTP timeouts via OTEL_EXPORTER_OTLP_TIMEOUT were added in 1.1.0beta1. Set them low (single-digit seconds) so a slow collector can't stall your app's shutdown path. Pair with OTEL_EXPORTER_OTLP_COMPRESSION=gzip if your network egress is metered or you're shipping verbose spans.

Debug at the collector, not in the app. When telemetry disappears, the fastest triage order is: (1) OtlpFileExporter in a test to confirm the SDK produces records, (2) curl -X POST to the collector's /v1/traces with a fixture, (3) collector debug exporter logs. Roughly 90% of "the exporter is broken" reports are provider registration, missing span->end(), or batch not flushed.

Upgrade for correctness fixes, not just features. Notable fixes worth tracking: JSON trace/span ID encoding (1.0.0beta7), protobuf enums serialized as integers (1.0.1), IS_REMOTE flag for context propagation (1.2.1), histogram min/max in metrics (1.3.3). If you're using span links, distributed propagation, or histograms, older pins produce subtly wrong data in your backend rather than obvious errors.

Extension points. Everything is interface-driven: implement SpanExporterInterface for a custom sink (e.g. dual-write to a vendor during migration), or build on PsrTransportFactory with your own PSR-18 client for mTLS, custom retry/backoff, or proxying. OtlpHttpTransportFactory now forwards all arguments to PsrTransportFactory, so injecting a configured HTTP client works.

Contribute upstream, not here. This repo is a read-only subtree split of open-telemetry/opentelemetry-php/src/Contrib/Otlp. PRs against exporter-otlp are closed; open them against the monorepo. Also note the PHP floor moved to 8.1 in the 1.1 line — check before upgrading on older Laravel apps.

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.
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo