Skip to main content
Let’s design a trace collection pipeline for every service running inside a Kubernetes cluster. This pattern helps you answer questions like: a customer clicks “buy” and the checkout flow passes through ten services — which one caused the extra latency?

Scenario: a slow checkout flow

Imagine:
  • A user clicks “buy”.
  • The request flows through ~10 microservices (gateway → auth → cart → inventory → payment → order → …).
  • Checkout used to finish in ~2s but now takes ~3s.
To find the cause you must measure how long each service takes. Each timed operation emitted by a service is called a span.

What is a span and a trace?

  • A span is a single timing record: operation name, start time, duration (or end time), and metadata (attributes, status, events).
  • A trace is a collection of spans that share the same trace ID. All spans produced while handling one request carry the same trace ID so you can reconstruct the full journey.
Example: simplified spans for one trace

Instrument services with OpenTelemetry

Add OpenTelemetry instrumentation to each service. OpenTelemetry (OTel) is the de-facto standard for generating traces and spans across languages and frameworks. Instrumentation can:
  • Automatically create spans for incoming and outgoing requests.
  • Propagate the trace context (trace ID and span context) across service boundaries so downstream services continue the same trace.
  • Enrich spans with attributes (service name, route, HTTP status, etc.).
References:
Make sure your services propagate the OpenTelemetry context (for HTTP, gRPC, etc.) and that sampling is configured consistently. If context propagation or sampling is misconfigured, spans from the same request may not get the same trace ID or may be dropped.

Collector deployment: one per node (DaemonSet)

Run the OpenTelemetry Collector as a Kubernetes DaemonSet so there is one collector instance on every node. Services on the same node forward spans to the local collector (commonly via OTLP over gRPC or HTTP). Benefits:
  • Local aggregation reduces cross-node traffic.
  • Collector performs batching, processing, sampling, and enrichment (adds pod, node, or service resource attributes).
  • Collector exports telemetry to one or more backends.
Key protocols and components:

Long-term storage: Grafana Tempo

For long-term trace storage, use Grafana Tempo. Tempo is a scalable, open-source trace store designed to minimize indexing and to rely on object storage (e.g., Amazon S3). Workflow:
  • Tempo receives traces (from the collector or other agents).
  • Traces are packed into compressed blocks and written to object storage.
  • When you request a trace by trace ID, Tempo fetches the relevant blocks from object storage, reconstructs the spans, and returns them.
Why Tempo?
  • Low-cost storage by leveraging object stores like S3.
  • Scales for large volumes of traces without heavy indexing.
More:

Visualize and explore traces in Grafana

Grafana provides the UI to search, fetch, and display traces from Tempo. With a trace ID (or search criteria), Grafana reconstructs the request timeline and displays spans across services so you can quickly spot which service(s) added latency.
A Grafana trace visualization with the Grafana logo at top, showing service spans (gateway, auth, cart, inventory, payment) and a timeline of request durations (e.g., a 3000ms gateway span).

Components at a glance

How this helps debug latency

  • Metrics (e.g., increased request duration) alert you that something changed.
  • Logs give context about errors or exceptions.
  • Traces show the full request path and which services contributed most to latency.
This pipeline scales:
  • Instrument all services with OpenTelemetry.
  • Deploy a DaemonSet of OpenTelemetry Collectors to receive node-local telemetry.
  • Export to Tempo with object storage for cost-effective long-term retention.
  • Use Grafana for trace exploration and root-cause analysis.

Watch Video