Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

OpenTelemetry: The Observability Standard

By Kokil Thapa | Last reviewed: September 2026

Production failures rarely announce themselves with a single log line. A slow checkout on a Laravel eCommerce platform might involve PHP-FPM, MySQL, Redis, a payment gateway, and a queue worker spread across two servers. Without a shared observability layer, each team instruments differently and you chase symptoms instead of causes. OpenTelemetry: The Observability Standard exists to fix that fragmentation. It gives you one vendor-neutral way to emit traces, metrics, and logs from any language and ship them to any backend. This guide explains what that standard actually means, how the pieces fit together, and how to adopt it on real PHP and Laravel stacks without rewriting your app.

What Makes OpenTelemetry the Observability Standard?

Before OpenTelemetry, observability was a patchwork. You picked a vendor APM agent for traces, Prometheus exporters for metrics, and whatever logging stack your host provided. Switching backends meant re-instrumenting code. Merging trace IDs with log lines required custom glue. Cross-service requests broke context at language boundaries.

OpenTelemetry (OTel) merged OpenTracing and OpenCensus into one CNCF project. It standardises three signal types under one specification:

  • Traces — request paths across services, with spans linked by trace and span IDs
  • Metrics — counters, gauges, and histograms with consistent naming conventions
  • Logs — structured log records that can carry trace context for correlation

The standard covers more than data shapes. It defines SDK lifecycle, context propagation headers (traceparent, tracestate), semantic conventions for HTTP and database spans, and OTLP (OpenTelemetry Protocol) for wire transport. Any compliant backend accepts the same export format. That is why teams treat OpenTelemetry as the observability standard rather than yet another monitoring tool.

OpenTelemetry Observability StandardYour AppLaravel / PHPOTel SDKAuto + manualOTLP ExportgRPC or HTTPBackendsAny vendorThree Unified SignalsTracesSpans + contextMetricsCounters + histosLogsTrace-linked
OpenTelemetry observability standard: one SDK layer exports traces, metrics, and logs via OTLP to any compatible backend.

In practice, the standard matters most when you outgrow a single-server Laravel app. On booking systems like Adventure Third Pole Trek, a user action may touch web, queue, mail, and payment APIs. OpenTelemetry keeps one trace ID across those hops. That single thread of context is the core value proposition behind the observability standard.

How Does OpenTelemetry Collect Traces, Metrics, and Logs?

OTel separates concerns into layers. Understanding each layer saves you from misconfiguring exports or duplicating instrumentation.

API and SDK

The API defines interfaces your code calls: start a span, record an attribute, increment a counter. The SDK implements those interfaces, manages sampling, batches exports, and handles shutdown. Language-specific SDKs exist for PHP, Node.js, Python, Go, Java, and others. You add the SDK via Composer for PHP or npm for JavaScript frontends.

Instrumentation libraries

Auto-instrumentation wraps common frameworks without editing every controller. For PHP, packages instrument PSR-18 HTTP clients, PDO, and Guzzle. For Laravel, community packages hook into HTTP kernel events, queue dispatch, and Eloquent queries. Manual instrumentation still belongs in business-critical paths where auto hooks miss domain context — payment callbacks, webhook handlers, or multi-step legal workflows on a legal-tech portal.

Collectors and exporters

The OpenTelemetry Collector is an optional but powerful middle tier. It receives OTLP, applies processors (filter, batch, redact PII), and forwards to one or more backends. Exporters are pluggable: OTLP to Grafana Tempo, Prometheus remote write, or vendor endpoints. See the official OpenTelemetry signals documentation for the canonical signal definitions.

OTel Signal Collection PipelineInstrumentRecordBatchOTel SDKSampler + processorResource attrsCollectorOptional relayDirect OTLPSkip collectorJaegerTempoPrometheusVendor APM
OpenTelemetry pipeline: SDK batches signals, optionally routes through a Collector, and exports to multiple observability backends simultaneously.

Context propagation is the piece most teams underestimate. When Service A calls Service B, the active span context must travel in outbound HTTP headers. Without it, you get orphaned spans and useless trace trees. The W3C Trace Context specification defines the header format OTel uses by default.

How Do You Instrument a Laravel Application with OpenTelemetry?

Laravel 12 and Laravel 13 apps on PHP 8.3 or PHP 8.5 follow the same general pattern. You install the OpenTelemetry PHP SDK, register a service provider, configure an OTLP exporter, and enable auto-instrumentation for HTTP and database calls. The steps below reflect patterns I've used on production Laravel applications.

Step 1: Install dependencies

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

composer require --dev open-telemetry/opentelemetry-auto-laravel

Pin versions in composer.lock and test upgrades in staging. OTel PHP packages move quickly, and breaking changes in beta APIs have caught teams off guard during support and maintenance cycles.

Step 2: Configure environment variables

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

Set OTEL_RESOURCE_ATTRIBUTES to include deployment.environment=production and service.version from your Git tag. Resource attributes attach to every span and make dashboards filterable.

Step 3: Add manual spans for domain logic

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

$tracer = Globals::tracerProvider()->getTracer('app.checkout');
$scope = $tracer->spanBuilder('process_payment')->startSpan()->activate();

try {
    $span = Span::getCurrent();
    $span->setAttribute('payment.gateway', 'khalti');
    $span->setAttribute('order.id', $order->id);
    $this->paymentService->charge($order);
} catch (\Throwable $e) {
    Span::getCurrent()->recordException($e);
    Span::getCurrent()->setStatus(StatusCode::STATUS_ERROR);
    throw $e;
} finally {
    $scope->detach();
    Span::getCurrent()->end();
}

Wrap payment gateways, webhook handlers, and queue jobs first. These paths fail silently or intermittently, and generic HTTP spans rarely expose enough detail. For deeper walkthroughs, see our guide on how to instrument an app with OpenTelemetry.

Step 4: Correlate logs with trace IDs

Configure Monolog to inject trace_id and span_id into every log record. When a user reports a failed booking at 14:32 NST, you search logs by trace ID and jump straight to the flame graph. A JSON formatter tool helps validate structured log output during local testing.

On shared hosting without a Collector sidecar, point OTLP directly at a managed backend or run the Collector as a systemd service on the same Ubuntu box. I've deployed this pattern alongside Apache and PHP-FPM on Linux system administration engagements where Docker was not available.

OpenTelemetry vs Vendor SDKs: Which Should You Choose?

Vendor agents from Datadog, New Relic, or Elastic APM ship fast and include polished dashboards. They also create lock-in. Re-instrumenting fifty microservices because your contract ended is expensive. OpenTelemetry trades some out-of-box polish for portability.

CriteriaOpenTelemetry (OTLP)Vendor-native SDK
Vendor lock-inLow — swap backends without code changesHigh — proprietary APIs per vendor
Time to first traceModerate — SDK + Collector setupFast — install agent, auto-discover
Multi-language consistencySame spec across PHP, Node, Go, JavaVaries — different agents per language
Self-hosted optionJaeger, Tempo, Prometheus stackOften requires vendor SaaS
Dashboard maturityDepends on chosen backendPolished vendor UI out of the box
Cost at scalePay for storage/compute you controlPer-host or per-span SaaS pricing

My default recommendation for new custom software projects: instrument with OpenTelemetry from day one, export to a backend that matches budget and ops capacity. Small teams often start with Grafana Cloud free tier or self-hosted Jaeger on the same VPC. Enterprise clients with existing Datadog contracts can still use OTel — Datadog accepts OTLP ingestion natively.

OTel vs Vendor SDK DecisionNeed portability?Yes: Use OTelNo: Vendor OKOTel PathOTLP exportMulti-backendNo rewritesVendor PathFast setupLocked APIsSwitch cost high
Choosing OpenTelemetry observability standard over vendor SDKs when multi-service portability and backend flexibility matter.

How Do You Export OpenTelemetry Data to Jaeger or Prometheus?

Export configuration determines whether your observability investment pays off. A misconfigured sampler drops the traces you need most — the rare 502 errors during payment callbacks.

Collector configuration example

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 5s
    send_batch_size: 512
  memory_limiter:
    limit_mib: 256

exporters:
  otlp/jaeger:
    endpoint: jaeger:4317
    tls:
      insecure: true
  prometheus:
    endpoint: 0.0.0.0:8889

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp/jaeger]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheus]

Run the Collector as a sidecar in Kubernetes, a Docker Compose service locally, or a standalone binary on Ubuntu. Point Laravel's OTEL_EXPORTER_OTLP_ENDPOINT at the Collector, not directly at Jaeger, unless you are prototyping. The Collector lets you fan out to multiple backends and redact sensitive attributes before export.

Sampling strategy

Head-based sampling decides at trace start whether to keep the entire trace. Tail-based sampling waits until the trace completes and keeps errors or slow requests. Production Laravel apps with moderate traffic often use parent-based always-on sampling in staging and probabilistic sampling (1–10%) in production. Always sample payment and auth paths regardless of global rate.

For a full Jaeger setup walkthrough, read our post on distributed tracing with OpenTelemetry and Jaeger. For multi-region deployments, pair OTel with the patterns in multi-cloud observability for metrics, logs, and traces.

Distributed Trace: Checkout FlowPOST /checkout (420 ms)Eloquent: insert order (85 ms)Redis: cache cart (12 ms)HTTP: payment API (280 ms)Queue: send receipt (45 ms)Mail: SMTP send (38 ms)trace_id: abc123
OpenTelemetry distributed trace showing nested spans across database, cache, payment API, and queue in a Laravel checkout request.

What Are Common OpenTelemetry Mistakes in Production?

Teams adopt the observability standard and still miss incidents because of operational gaps, not missing features.

  1. No resource attributes — spans without service.name or deployment.environment become unfilterable noise in shared backends.
  2. 100% sampling in production — full trace capture on high-traffic APIs increases cost and Collector memory pressure. Tune sampling deliberately.
  3. Broken context across queues — Laravel queue jobs run in separate processes. Inject trace context into job payloads or use OTel's context serialization helpers.
  4. PII in span attributes — never attach emails, phone numbers, or card data to spans. Use opaque IDs and redact in the Collector.
  5. No shutdown hook — PHP-FPM workers recycle. Flush pending spans on terminating middleware or you lose tail spans.
  6. Ignoring metrics and logs — traces alone do not replace RED metrics (rate, errors, duration) or structured logs. Use all three signals.

These mistakes show up during testing and optimization reviews more often than during initial development. Treat observability like deployment: test it in staging under load before launch week.

Connect OTel with broader ops practices. Pair trace alerts with Prometheus Alertmanager rules. For API-heavy platforms, combine trace data with API rate limiting and abuse prevention metrics. Teams exploring automated incident response should read about AIOps for modern infrastructure.

On enterprise application development projects, I define observability acceptance criteria alongside functional requirements. Every new API endpoint ships with a span, a counter, and a structured log line. That discipline prevents the "we'll add monitoring later" debt that makes post-launch debugging painful.

For microservice architectures, the observability standard becomes essential. Read observability for microservices for service graph patterns. If you run a service mesh, observability with a service mesh covers sidecar-based trace propagation that complements OTel.

Managed observability pricing varies. Self-hosted Jaeger on a Rs 5,000/month (~USD 37) VPS handles moderate Laravel traffic. Grafana Cloud and vendor SaaS tiers scale with span volume. Budget for storage retention — 7-day trace retention suits most debugging; 30-day retention helps trend analysis.

The CNCF graduated OpenTelemetry in 2024, signalling production readiness. The CNCF OpenTelemetry project page tracks release cadence and ecosystem growth. The OTLP specification lives in the OpenTelemetry organisation on GitHub and remains the stable export contract across SDK versions.

Key Takeaways

  • OpenTelemetry unifies traces, metrics, and logs under one vendor-neutral observability standard with OTLP export.
  • Instrument Laravel apps via Composer SDK packages, environment variables, and manual spans on payment and queue paths.
  • Run an OpenTelemetry Collector to batch, redact PII, and fan out to Jaeger, Prometheus, or vendor backends.
  • Choose OTel over proprietary agents when multi-service portability and backend flexibility outweigh dashboard convenience.
  • Configure sampling, resource attributes, and log correlation before production — not after the first outage.
  • Pair distributed traces with RED metrics and structured logs for complete observability coverage.

People Also Ask

Is OpenTelemetry ready for production in 2026?

Yes. OpenTelemetry graduated from the CNCF and ships stable SDKs for major languages including PHP. Large organisations run OTel in production across thousands of services. PHP auto-instrumentation is less mature than Java or Node.js, so plan manual spans for critical business paths.

Does OpenTelemetry replace Prometheus or Grafana?

No. OpenTelemetry collects and exports signals. Prometheus stores metrics. Grafana visualises them. Jaeger or Tempo stores traces. OTel replaces proprietary collection agents, not storage or dashboard tools. You still choose backends that fit your ops model.

Can OpenTelemetry work on shared hosting without Docker?

Partially. You need the PHP extension or pure-PHP SDK plus outbound HTTPS to an OTLP endpoint. Shared hosts that block long-running processes or outbound gRPC limit full Collector deployments. VPS or cloud instances with PHP 8.3+ and Composer 2.10 support the complete setup.

How does OpenTelemetry relate to Laravel Telescope?

Telescope is a local debugging tool for Laravel requests, jobs, and queries during development. OpenTelemetry exports telemetry to production-grade backends with cross-service trace correlation. Use Telescope for local debugging and OTel for staging and production observability. They complement each other.

Ship Observability That Survives Vendor Changes

OpenTelemetry: The Observability Standard gives your team one instrumentation layer that outlasts backend contracts and hosting moves. Start with HTTP and database auto-instrumentation on your Laravel app. Add manual spans on payments and webhooks. Export via OTLP to Jaeger or Grafana. Expand to metrics and log correlation once traces prove value.

If you want help designing observability into a new platform or retrofitting traces onto an existing API development project, contact us for a practical architecture review. You can also browse the portfolio for examples of production Laravel systems built with operational reliability in mind, or explore speed optimization services that pair performance work with measurable telemetry.

Frequently Asked Questions

OpenTelemetry is the CNCF observability standard: vendor-neutral APIs, SDKs, and OTLP export for traces, metrics, and logs to any compatible backend.

Yes. OpenTelemetry graduated from the CNCF in 2024. PHP auto-instrumentation is less mature than Java or Node.js, so validate in staging under load before production rollout.

OpenTelemetry itself is free. Backends cost separately — self-hosted Jaeger on a Rs 5,000/month (~USD 37) VPS handles moderate Laravel traffic.

Before OpenTelemetry, teams mixed vendor APM agents, Prometheus exporters, and host logging stacks — switching backends meant re-instrumenting code. OTel merged OpenTracing and OpenCensus into one CNCF project defining trace, metric, and log shapes, SDK lifecycle, W3C context propagation headers, semantic conventions, and OTLP wire transport. Any compliant backend accepts the same export format, which is why teams treat it as the standard rather than another monitoring tool.

Traces map request paths across services using spans linked by trace and span IDs. Metrics provide counters, gauges, and histograms with consistent naming conventions. Logs are structured records that can carry trace context so you correlate log lines with flame graphs. Using all three together — not traces alone — gives complete observability coverage alongside RED metrics and structured logging.

OTel separates instrumentation into layers. Your code calls the API; the SDK handles sampling, batching, and export shutdown. Auto-instrumentation libraries wrap PSR-18 HTTP clients, PDO, Guzzle, and Laravel kernel, queue, and Eloquent events. An optional OpenTelemetry Collector receives OTLP, applies processors to filter, batch, or redact PII, and forwards to Jaeger, Prometheus, or vendor endpoints. Context propagation via traceparent and tracestate headers keeps spans linked across service boundaries.

On Laravel 12 or Laravel 13 with PHP 8.3 or PHP 8.5, install open-telemetry/opentelemetry, open-telemetry/exporter-otlp, and open-telemetry/sdk via Composer, plus open-telemetry/opentelemetry-auto-laravel for auto hooks. Set OTEL_SERVICE_NAME, OTEL_TRACES_EXPORTER=otlp, OTEL_EXPORTER_OTLP_ENDPOINT, and OTEL_PHP_AUTOLOAD_ENABLED=true. Add manual spans around payment gateways, webhook handlers, and queue jobs where auto-instrumentation misses domain context. Configure Monolog to inject trace_id and span_id into every log record.

Core variables include OTEL_SERVICE_NAME for service identification, OTEL_TRACES_EXPORTER=otlp, OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf, and OTEL_EXPORTER_OTLP_ENDPOINT pointing at your Collector or backend. Enable auto-instrumentation with OTEL_PHP_AUTOLOAD_ENABLED=true and set OTEL_PROPAGATORS=tracecontext,baggage for W3C header propagation. Add OTEL_RESOURCE_ATTRIBUTES with deployment.environment and service.version from your Git tag so every span is filterable in shared dashboards.

Vendor agents from Datadog, New Relic, or Elastic install fast and include polished dashboards, but they create lock-in and vary across languages. OpenTelemetry trades some out-of-box polish for portability — instrument once, export via OTLP, swap backends without code changes. My default for new custom projects: start with OpenTelemetry and export to Grafana Cloud free tier or self-hosted Jaeger. Enterprise teams with Datadog contracts can still use OTel because Datadog accepts OTLP ingestion natively.

The Collector is an optional middle tier that receives OTLP on gRPC port 4317 or HTTP port 4318, runs processors like batch, memory_limiter, and PII redaction, then fans out to multiple backends simultaneously. Point Laravel's OTEL_EXPORTER_OTLP_ENDPOINT at the Collector rather than directly at Jaeger unless prototyping. Run it as a Kubernetes sidecar, Docker Compose service, or standalone binary on Ubuntu alongside Apache and PHP-FPM when Docker is unavailable.

Configure the Collector with OTLP receivers, batch and memory_limiter processors, an otlp/jaeger exporter for traces, and a prometheus exporter on port 8889 for metrics. Set OTEL_EXPORTER_OTLP_ENDPOINT to the Collector address. Use parent-based always-on sampling in staging and probabilistic sampling at one to ten percent in production. Always sample payment and auth paths regardless of global rate so rare checkout failures remain visible in Jaeger flame graphs.

Head-based sampling decides at trace start whether to keep the entire trace; tail-based sampling waits until completion and keeps errors or slow requests. In practice, use parent-based always-on sampling in staging and probabilistic one-to-ten-percent sampling in production to control Collector memory and storage cost. Override the global rate for payment and auth paths — those fail intermittently and generic HTTP spans rarely expose enough detail for debugging checkout or webhook failures.

Spans without service.name or deployment.environment become unfilterable noise. One-hundred-percent sampling on high-traffic APIs increases cost and Collector memory pressure. Laravel queue jobs lose context unless you inject trace IDs into payloads. Never attach emails, phone numbers, or card data to spans — use opaque IDs and redact in the Collector. PHP-FPM workers recycle without shutdown hooks, dropping tail spans. Traces alone do not replace RED metrics or structured logs — ship all three signals from day one.

Configure Monolog to inject trace_id and span_id into every structured log record using a JSON formatter during local testing. When a user reports a failed booking at a specific time, search logs by trace ID and jump straight to the matching flame graph in Jaeger or Grafana Tempo. OpenTelemetry's log signal is designed to carry the same trace context as spans, eliminating the custom glue teams previously built to merge vendor trace IDs with application log lines.

When Service A calls Service B, the active span context must travel in outbound HTTP headers using W3C Trace Context — traceparent and tracestate by default via OTEL_PROPAGATORS=tracecontext,baggage. Without propagation you get orphaned spans and useless trace trees. Laravel queue jobs run in separate processes, so inject trace context into job payloads or use OTel context serialization helpers. On multi-service booking systems, one trace ID follows web, queue, mail, and payment API hops end to end.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: