
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Debugging latency in a distributed PHP application requires more than error logs; you need correlated signals across services. Observability for PHP with OpenTelemetry provides the standardized instrumentation necessary to trace requests from Nginx through your application code, queues, and databases. While earlier versions of the ecosystem were experimental, the 2026 stable releases of the PHP SDK and auto-instrumentation packages now make production-grade tracing reliable and performant. This guide covers the exact configuration needed to instrument a modern PHP stack without degrading throughput.
open-telemetry/opentelemetry-auto-instrumentation package and configuring the OTLP exporter via environment variables. Use the native C extension or FFI for low-overhead hook execution, and manually instrument business logic to correlate traces across HTTP, CLI, and queue workers in frameworks like Laravel.How do you install OpenTelemetry auto-instrumentation for PHP?
The foundation of instrumenting an app with OpenTelemetry in the PHP ecosystem is the auto-instrumentation package. Unlike Java or Go, PHP requires explicit installation of hook libraries because the language runtime does not support bytecode manipulation natively. In 2026, the recommended approach uses Composer to manage dependencies alongside the optional but highly recommended C extension for performance.
Install core packages and extensions
You must install both the SDK and the specific auto-instrumentation hooks for your framework. For a typical Laravel application running on PHP 8.4+, execute the following:
composer require open-telemetry/opentelemetry-auto-instrumentation \
open-telemetry/auto-laravel \
open-telemetry/exporter-otlp \
open-telemetry/transport-grpc
# Install the C extension for zero-cost hook execution (recommended)
pecl install opentelemetry
echo "extension=opentelemetry.so" >> /etc/php/8.4/cli/conf.d/20-opentelemetry.ini
echo "extension=opentelemetry.so" >> /etc/php/8.4/fpm/conf.d/20-opentelemetry.ini If you cannot install PECL extensions due to shared hosting restrictions or container constraints, the SDK falls back to FFI (Foreign Function Interface) or userland hooks. However, be aware that userland hooks add measurable overhead. For any high-traffic production system, especially in cost-sensitive environments common among Nepal-based startups, the C extension is effectively mandatory to keep CPU tax below 3%.
Configure environment variables
OpenTelemetry PHP adheres strictly to the OTel specification for configuration. Avoid hardcoding endpoints in your application source. Instead, inject these variables via your deployment manifest, Dockerfile, or systemd unit:
OTEL_SERVICE_NAME: Identifies your service in traces (e.g.,payment-api,laravel-web).OTEL_EXPORTER_OTLP_ENDPOINT: The full URL of your collector or backend (e.g.,http://otel-collector:4317for gRPC).OTEL_TRACES_EXPORTER: Set tootlpfor standard backends.OTEL_PHP_AUTOLOAD_ENABLED: Set totrueto activate auto-instrumentation hooks.OTEL_RESOURCE_ATTRIBUTES: Add semantic attributes likedeployment.environment=production,host.name=web-01.
When should you add manual spans to PHP applications?
Auto-instrumentation captures infrastructure boundaries—HTTP requests, database queries, Redis calls, and queue jobs. It cannot understand your business logic. When debugging complex workflows, such as a multi-step checkout or a report generation pipeline, you need manual spans to create visibility inside your domain code. This distinction is critical when implementing metrics, logs, and traces compared effectively; traces provide the structural skeleton, while manual spans add the semantic muscle.
Create spans with the global tracer provider
Use the static API to avoid passing tracer instances through every service constructor. This keeps your code clean while maintaining full trace context propagation:
use OpenTelemetry\API\Globals;
use OpenTelemetry\API\Trace\SpanKind;
$tracer = Globals::tracerProvider()->getTracer('order-processing');
$span = $tracer->spanBuilder('calculate-shipping-rates')
->setSpanKind(SpanKind::KIND_INTERNAL)
->setAttribute('shipping.origin', 'Kathmandu')
->setAttribute('shipping.destination', 'Pokhara')
->startSpan();
try {
$rates = $this->shippingService->getRates($origin, $destination);
$span->setAttribute('shipping.rate_count', count($rates));
} catch (\Throwable $e) {
$span->recordException($e);
$span->setStatus(\OpenTelemetry\API\Trace\StatusCode::STATUS_ERROR);
throw $e;
} finally {
$span->end();
} A common mistake I see in audits is failing to call $span->end() in a finally block. If an exception occurs before the span closes, it leaks memory and breaks the parent-child relationship in the trace visualization. Always use try-finally or a dedicated scope manager if your framework supports it.
How does OpenTelemetry PHP compare to legacy monitoring agents?
Many teams in Nepal and South Asia still rely on proprietary APM agents or basic log parsing. Migrating to OpenTelemetry as the observability standard involves trade-offs. Understanding these differences prevents buyer's remorse and helps justify the migration effort to stakeholders accustomed to vendor-specific dashboards.
| Feature | Legacy Proprietary Agent | OpenTelemetry PHP SDK (2026) |
|---|---|---|
| Vendor Lock-in | High; proprietary data formats | None; OTLP is an open CNCF standard |
| Installation Overhead | Opaque binary blob | Transparent Composer deps + optional ext |
| Context Propagation | Often limited to single vendor | W3C Trace Context standard compliant |
| Cost Model | Per-host or per-GB ingestion fees | Free SDK; pay only for backend storage |
| Queue/CLI Support | Frequently broken or unsupported | First-class support via auto-hooks |
| Community & Docs | Vendor support tickets | CNCF community, GitHub, Slack |
In practice, the biggest win for PHP shops is W3C Trace Context propagation. If your PHP app calls a Node.js microservice or receives traffic from an Nginx ingress controller, OpenTelemetry seamlessly stitches those hops into a single trace. Legacy agents often break at these boundaries unless every component uses the same vendor's agent.
What are the performance best practices for PHP tracing?
Instrumentation is useless if it causes the outage you're trying to diagnose. PHP's share-nothing architecture means every request pays the initialization cost. Follow these operational guidelines to maintain SLOs while gaining visibility.
Sampling and batching strategies
Never trace 100% of traffic in production unless you have very low volume. Configure head-based sampling to capture a representative subset while keeping resource usage predictable:
# Sample 10% of requests in production
OTEL_TRACES_SAMPLER=parentbased_tracealways
OTEL_TRACES_SAMPLER_ARG=0.1
# Batch exports to reduce network syscalls
OTEL_BSP_SCHEDULE_DELAY=5000
OTEL_BSP_MAX_EXPORT_BATCH_SIZE=512 For high-traffic e-commerce sites during peak seasons like Dashain or Black Friday, consider implementing a custom sampler that always records errors and slow requests (>2s) while sampling successful fast requests at 1%. This ensures you never miss anomalies while discarding noise.
Avoid high-cardinality attributes
Tagging spans with user IDs, session tokens, or full URLs creates cardinality explosions that crash metric backends and inflate trace storage costs. Stick to low-cardinality semantic conventions: http.route instead of http.url, user.role instead of user.id. If you must store high-cardinality data for debugging, use span events or log correlation rather than indexed span attributes.
How do you verify OpenTelemetry instrumentation locally?
Before deploying to production, validate your setup locally to avoid silent failures. The most effective method is running a local collector with console export or using the official OTel CLI tool.
- Start a local collector: Use Docker to run
otel/opentelemetry-collector-contribwith a debug receiver configured to print spans to stdout. - Set endpoint to localhost: Point
OTEL_EXPORTER_OTLP_ENDPOINTtohttp://localhost:4317. - Trigger representative traffic: Hit key routes, dispatch queue jobs, and trigger error paths.
- Inspect output: Verify span names follow semantic conventions, parent-child relationships are correct, and no sensitive data leaks in attributes.
- Check baggage propagation: Ensure headers like
traceparentappear in outgoing HTTP client calls from your PHP app.
This verification step catches misconfigured samplers, missing extensions, and broken context propagation before they impact production reliability metrics. For teams adopting distributed tracing with OpenTelemetry and Jaeger, this local feedback loop accelerates instrumentation development significantly.
Implementing Sustainable Observability for PHP with OpenTelemetry
Adopting observability for PHP with OpenTelemetry transforms how you diagnose production issues, moving from reactive log grepping to proactive trace analysis. Start with auto-instrumentation to establish baseline visibility, then strategically add manual spans where business complexity demands it. Monitor the overhead of your instrumentation itself—treat your observability pipeline with the same rigor as your application code. If you need help designing a compliant, performant tracing architecture for your PHP stack, reach out to discuss your specific requirements.