open-telemetry/opentelemetry-propagation-server-timing
Propagates OpenTelemetry trace context through the Server-Timing HTTP header, helping PHP applications correlate backend traces with browser and frontend requests for simpler debugging and performance analysis.
Architecture fit
Server-Timing response header so browser DevTools / RUM agents can correlate a client-side resource timing entry with the server-side trace that produced it. That makes it a correlation/UX layer on top of an existing OTel PHP deployment, not a tracing capability in its own right.open-telemetry/sdk + a tracer provider + an exporter are already wired into the app. In a Laravel context that usually means open-telemetry/opentelemetry-auto-laravel (or a hand-rolled middleware stack) is already in place.Illuminate\Http\Response/Symfony Response is not PSR-7, but OTel PHP propagators typically use array carriers (inject(array &$carrier, SpanContext $context)), so the integration surface is a thin middleware that reads the active span context, injects into an array, and copies values onto $response->headers. Low architectural intrusion.Kernel/bootstrap/app.php is the main design constraint.Integration feasibility
tracecontext/baggage, so expect to compose the propagator in code), one middleware, one config flag.Timing-Allow-Origin / Access-Control-Expose-Headers, Octane/streaming handling, and a frontend RUM consumer that actually reads PerformanceResourceTiming.serverTiming.Technical risk
Server-Timing; streaming responses flush headers before the propagator runs. The header can be silently absent with no error signal.Key questions
inject() only, or also extract()? (Affects whether it can be safely dropped into the global propagator list without breaking inbound context.)open-telemetry/sdk ^1.x and PHP 8.1/8.2/8.3 — is there a composer.json constraint matrix, or nothing published?dur (duration), desc (traceparent), or both, and does it support multiple entries per response?StreamedResponse?traceparent verbatim (useful for frontend→backend log join) or an opaque ID (safer)?Stack fit
tracecontext propagation. If tracing is not yet live, this package should be deferred — it is the last 5% of a tracing program, not the first.TraceContext (inbound/outbound) + this Server-Timing propagator (response header only). Keep them as separate bindings so the response behaviour can be toggled independently.performance.getEntriesByType('resource') → serverTiming and forward to your observability backend. Budget for that work explicitly; it is often larger than the backend change.Migration path
curl -I on a local route. Gate: header present with a valid traceparent-derived value on sampled requests only.config('observability.server_timing.enabled') defaulting to false; enable in staging. Validate CORS exposure and CDN passthrough.Compatibility
composer require ...:x.y.z) — do not use ^ on a 0.x contrib package with 1 star.opentelemetry-auto-laravel: two middlewares both touching span lifecycle can conflict; confirm ordering and that the auto-instrumentation's response hook does not already set Server-Timing.Server-Timing is not a CORS-safelisted response header; cross-origin frontends need Access-Control-Expose-Headers: Server-Timing and Timing-Allow-Origin. This is a one-line config change in config/cors.php but is a common silent-failure source.Sequencing
Maintenance
app/Observability/ or a private fork, keep the Composer dependency for the spike only, and assign a named owner.composer outdated alert on open-telemetry/* and a quarterly review of the upstream contrib repo's activity.Support
Scaling
traceparent-derived desc is ~55–80 bytes per response; with Baggage it can grow. Cap header size and exclude Baggage from this header.Failure modes
Server-Timing; appears to work in staging, not in prod. Test through the full edge path.Ramp-up
Overall TPM recommendation: Low-risk, low-cost, low-ceiling capability that is only worth scheduling after tracing is already production-grade. Treat it as a build-in-house candidate (small enough to own outright) rather than a dependency to standardise on, and pair it with a frontend consumer commitment so the header produces a decision-relevant metric rather than bytes on the wire.
How can I help you explore Laravel packages today?