# Workflow: distributed tracing across services

One trace per request across every service is the goal. It breaks at boundaries by default; this workflow hardens each one.

## 1. Enable tracing everywhere, even at low rates

Every service gets tracing enabled, even services you think do not need it. A service with tracing unset breaks inbound trace continuation; a service at `traces_sample_rate=0` still continues incoming traces. Unset is the enemy, 0 is fine.

## 2. Propagate through the infrastructure

The `sentry-trace` and `baggage` headers carry the trace. Audit every proxy, gateway, and WAF between your services and allowlist both headers. Log headers at one boundary during rollout to prove they survive the hop.

## 3. Sample consistently

Use the same sampling strategy in every service, ideally via a shared `traces_sampler`. The sampling decision propagates downstream; inconsistent strategies produce orphan spans and partial traces. Decide once, configure everywhere.

## 4. Name transactions by route pattern

Parameterize IDs out of transaction names in every service (`GET /accounts/[id]`, not `GET /accounts/48291`). High-cardinality names fragment traces, dashboards, and span quota simultaneously.

## 5. Cover manual clients

Auto-instrumentation propagates headers for supported HTTP clients. For hand-rolled clients, inject the propagation headers from the current span context manually. Audit for custom fetch wrappers and queue publishers; they are the usual gaps.

## 6. Roll out boundary by boundary

Start with frontend to backend, verify joined traces, then extend to the next hop. Each boundary gets its own verification before moving on; debugging three broken boundaries at once is miserable.

## Verify

Follow one request through every service in the trace view: a single connected tree, no orphans, sampling decisions consistent. Then check span quota: full-fidelity tracing across a fleet is a budget decision, and the sampler is where it gets made.