tracking requests across system boundaries with OpenTelemetry
Once a Magento store works with microservices, external APIs, and asynchronous queues, classic logging loses sight of every request the moment it crosses a system boundary. Distributed tracing with OpenTelemetry connects every sub step into one continuous chain and shows exactly where latency comes from.
Table of Contents
- 1. Why logging hits its limits in distributed systems
- 2. Traces, spans, and context: the core concepts
- 3. Integrating the OpenTelemetry PHP SDK into Magento
- 4. Creating custom spans for checkout and price calculation
- 5. Propagating trace context over HTTP and the message queue
- 6. Collector and backend: Jaeger and Tempo compared
- 7. Sampling strategies for high traffic
- 8. Debugging with a real trace chain
- 9. Distributed tracing compared to logs and metrics
- 10. Summary
- 11. FAQ
1. Why logging hits its limits in distributed systems
A single log file per system works fine as long as an application stays monolithic. But once a Magento store works together with a separate pricing service, an external shipping provider, and an asynchronous order export consumer, a single customer request gets scattered across multiple independent log files, each with its own timestamp format and no shared reference point. Distributed tracing solves exactly this problem by attaching a unique trace ID to every request that survives across all involved systems.
Without distributed tracing, debugging a slow request becomes a manual assembly of clues: a developer has to correlate timestamps across different logs by hand and hope the server clocks stay in sync. With a continuous trace, one single view shows the complete chain, from the first HTTP request in the Magento frontend to the last response from an external payment service, including the exact duration of every single sub step.
OpenTelemetry has established itself as the vendor neutral standard for distributed tracing because it is not tied to a single backend. The same instrumentation feeds data to Jaeger, Tempo, or commercial platforms, without rewriting application code when switching vendors. For Magento stores with a growing system landscape, that is a strategically important decision against vendor lock in.
2. Traces, spans, and context: the core concepts
A trace represents a single, complete request across all involved systems. Within a trace, every individual unit of work is a span, say a database query, an HTTP call to an external service, or the execution of a price rule. Every span carries a start and end time, so duration and order can be reconstructed exactly. Spans can nest, so a parent span for the entire checkout request then contains several child spans for individual sub steps.
The trace context is the information that must be passed between systems so a new span attaches to the same trace instead of starting its own. The W3C standard traceparent header carries this information across HTTP boundaries. Without correct propagation of this header, isolated trace fragments emerge that can never be reassembled into a coherent chain, which defeats the entire value of distributed tracing.
3. Integrating the OpenTelemetry PHP SDK into Magento
The OpenTelemetry PHP SDK gets pulled in via Composer and initialized through a central bootstrap class that registers a tracer provider. For Magento, a plugin on the front controller works well because every incoming request is guaranteed to pass through it exactly once, regardless of which route eventually handles it. This central entry point opens the root span for the entire request.
What matters during integration is running the exporter asynchronously with a short timeout configuration, so a slow or unreachable collector never delays the actual customer request. An OTLP exporter over UDP, or a local sidecar collector that buffers and forwards spans, reliably decouples instrumentation from the actual request cycle.
<?php
declare(strict_types=1);
namespace Mironsoft\Observability\Plugin;
use Magento\Framework\App\FrontControllerInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\ResponseInterface;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\API\Trace\TracerInterface;
/**
* Opens the root span for every incoming request at the front controller
* boundary, ensuring every route is captured under a distributed trace.
*/
class TracingFrontControllerPlugin
{
/**
* @param TracerInterface $tracer OpenTelemetry tracer instance.
*/
public function __construct(private readonly TracerInterface $tracer)
{
}
/**
* Wraps request dispatch in a root span named after the request path.
*
* @param FrontControllerInterface $subject Original front controller.
* @param callable $proceed Original dispatch method.
* @param RequestInterface $request Incoming HTTP request.
* @return ResponseInterface
*/
public function aroundDispatch(
FrontControllerInterface $subject,
callable $proceed,
RequestInterface $request
): ResponseInterface {
$span = $this->tracer->spanBuilder('magento.request')
->setSpanKind(SpanKind::KIND_SERVER)
->setAttribute('http.target', $request->getPathInfo())
->startSpan();
$scope = $span->activate();
try {
return $proceed($request);
} finally {
$scope->detach();
$span->end();
}
}
}
4. Creating custom spans for checkout and price calculation
The root span alone only shows the total duration of a request, without revealing which sub step is responsible. Meaningful distributed tracing requires critical code paths to create their own child spans, say price calculation at checkout or the call to the shipping provider. These spans automatically inherit the trace context of the active root span as long as they are created within the same execution.
A proven pattern is attaching attributes to every span that matter for later analysis, such as the number of cart items or the shipping method used. These attributes later make it possible to filter for patterns directly in the trace interface, such as every slow checkout trace with more than ten items, without opening each trace individually.
<?php
declare(strict_types=1);
namespace Mironsoft\Observability\Service;
use OpenTelemetry\API\Trace\TracerInterface;
/**
* Wraps shipping rate calculation in a child span with useful attributes
* for later filtering in the trace backend.
*/
class ShippingRateSpan
{
/**
* @param TracerInterface $tracer OpenTelemetry tracer instance.
*/
public function __construct(private readonly TracerInterface $tracer)
{
}
/**
* Executes the given callback inside a named, attributed span.
*
* @param callable $callback Actual shipping rate calculation.
* @param int $itemCount Number of cart items, attached as a span attribute.
* @return mixed The callback's return value.
*/
public function wrap(callable $callback, int $itemCount): mixed
{
$span = $this->tracer->spanBuilder('shipping.calculate_rate')
->setAttribute('cart.item_count', $itemCount)
->startSpan();
$scope = $span->activate();
try {
return $callback();
} finally {
$scope->detach();
$span->end();
}
}
}
5. Propagating trace context over HTTP and the message queue
For synchronous HTTP calls to external services, attaching the traceparent header to the outgoing request is enough, and most OpenTelemetry instrumentations for common HTTP clients handle this automatically. It gets trickier with asynchronous messages over RabbitMQ, since there is no HTTP header through which the context could travel automatically.
The solution is to explicitly serialize the trace context as part of the message payload or as a custom message header field before writing the message to the queue. The consumer reads this field on receipt and continues the trace context instead of starting a new, isolated trace. Without this explicit step, every asynchronous processing step inevitably breaks the trace chain, which is a frequent problem particularly around order exports and stock synchronization.
6. Collector and backend: Jaeger and Tempo compared
The OpenTelemetry collector receives spans from the application, optionally processes them further, say through batching or filtering, and forwards them to a storage backend. Jaeger is the most established open source solution for distributed tracing, with a mature web interface for visualizing trace chains as a waterfall diagram. Grafana Tempo takes a different approach and stores traces more cheaply by forgoing a full search index in favor of trace ID based access.
For Magento operators who already use Grafana for metrics and logs, Tempo offers the advantage of a unified interface across all three observability pillars. Those who value detailed, searchable trace analysis above all benefit from Jaeger's more mature search capability over span attributes and tags.
7. Sampling strategies for high traffic
Fully tracing every single request on a high traffic Magento store generates significant data volume and network load to the collector. Head based sampling decides whether a request gets traced right at its start, usually via a fixed percentage. Tail based sampling, in contrast, first collects all spans of a trace and only then decides, based on criteria like error status or total duration, whether the complete trace gets kept.
For distributed tracing in Magento, tail based sampling is particularly valuable because it guarantees that every failed or unusually slow trace gets kept, while normal, fast requests are only stored as a sample. This combination drastically reduces storage needs without losing the traces that matter most for debugging.
8. Debugging with a real trace chain
In practice, the value of distributed tracing shows most clearly with intermittent performance problems that only appear in classic metrics as a slight increase in the average. A trace chain for a single slow checkout request can reveal that the root span takes two seconds, of which 1.7 seconds fall on a single span for tax calculation, which in turn is waiting on an external tax service.
Without this granularity, a developer would likely suspect Magento's own price calculation first and waste valuable time on the wrong hypothesis. Distributed tracing shortens this kind of debugging from hours to minutes, because the answer is directly visible in the structure of the trace instead of having to be reconstructed from scattered clues.
9. Distributed tracing compared to logs and metrics
Distributed tracing replaces neither logs nor metrics, but adds a dimension neither tool can deliver alone: the causal order and duration of individual steps across system boundaries.
| Tool | Answers | Limit | Ideal for |
|---|---|---|---|
| Logs | What happened at a specific point | No connection across system boundaries | Detailed information about an event |
| Metrics | How much, how often, over what period | No insight into individual requests | Trend analysis and alerting |
| Distributed tracing | Exactly where a request spent its time | Requires instrumentation in every system | Latency and error analysis across boundaries |
The three pillars complement each other best when trace IDs also get written into structured logs. That lets you jump directly from a noticeable metric alert to the associated traces, and from there to the detailed log entries of every single span, without manually correlating timestamps.
Mironsoft
Magento observability and architecture for distributed systems
Making latency visible across system boundaries?
We integrate OpenTelemetry into your Magento store, connect traces across microservices and message queues, and set up Jaeger or Tempo for real latency analysis.
SDK integration
OpenTelemetry PHP SDK cleanly wired into Magento's front controller
Context propagation
Trace context reliably passed across HTTP and message queues
Backend selection
Jaeger or Tempo, matched to your existing observability stack
10. Summary
Distributed tracing with OpenTelemetry closes the gap that classic logging and metrics leave open in distributed Magento architectures. Traces consist of nested spans that stay connected through a propagated trace context, even when a request travels from Magento through an external pricing service to an asynchronous message queue consumer. Correctly propagating the traceparent header over HTTP and explicitly passing the context over message queues are the most critical technical steps.
Tail based sampling ensures that exactly the most meaningful traces, namely failed or unusually slow ones, get reliably kept, while storage needs for the mass of normal requests stay under control. Once distributed tracing is cleanly integrated into a Magento store, debugging latency problems across system boundaries shrinks from hours to minutes.
Distributed Tracing in Magento — The key takeaways
Traces and spans
A trace consists of nested spans, each with its own start and end time, connected through the trace context.
Context propagation
traceparent header for HTTP, explicit serialization of context for asynchronous message queue messages.
Sampling
Tail based sampling reliably keeps failed and slow traces while significantly reducing overall data volume.
Backend choice
Jaeger for mature search, Tempo for a unified interface with an existing Grafana stack.