Distributed Tracing in Magento with OpenTelemetry
AI generated
M2
di.xml
Magento 2 · Observability · OpenTelemetry · Tracing
Distributed Tracing in Magento
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.

19 min read OpenTelemetry · spans · trace context · Jaeger Magento 2.4.x · PHP 8.3

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.

11. FAQ: Distributed Tracing in Magento with OpenTelemetry

1Difference between a trace and a span?
A trace is the complete request, a span a single unit of work within it with its own timing.
2Why is context propagation critical?
Without it, isolated trace fragments emerge that never assemble into a coherent chain.
3How do you integrate OpenTelemetry into Magento?
Via the PHP SDK through Composer, with a plugin on the front controller for the root span.
4Propagate context over a message queue?
Serialize explicitly as part of the payload or header field, read it back by the consumer.
5Head based vs. tail based sampling?
Head decides at start via a fixed rate, tail collects all spans first and decides at the end.
6Why is tail based often better for Magento?
Guarantees failed and slow traces are kept while reducing overall data volume.
7Jaeger vs. Grafana Tempo?
Jaeger offers mature search, Tempo integrates more cheaply into an existing Grafana stack.
8Does tracing replace classic logging?
No, both complement each other best with trace IDs in structured logs.
9Finding the cause of a slow checkout request?
The trace chain shows the dominant span exactly, avoiding false hypotheses from the start.
10Which attributes to attach to spans?
Business relevant values like item count or shipping method, for later targeted filtering.