What Is Tail-Based Sampling in OpenTelemetry?

What Is Tail-Based Sampling in OpenTelemetry?

Learn how to wait until a request has finished before deciding whether its trace is worth keeping, so that the slow, broken, and surprising requests are saved while the boring ones are thrown away, and understand what it costs to do that well.

Picture a shop with fifty security cameras recording around the clock. Storing every hour of footage forever would be absurdly expensive, so the owner has to decide what to keep. One approach is to flip a coin at the start of every hour: heads, keep the hour, tails, delete it. It is cheap and simple, but when a robbery happens, there is a good chance the coin said “delete” for exactly that hour. A smarter approach is to wait until the end of the day, watch for anything unusual, and keep only the clips where something interesting happened.

Those two approaches are the heart of this guide. Deciding at the start, without knowing how things will turn out, is called head-based sampling. Waiting until the story is finished and then deciding is called tail-based sampling. OpenTelemetry supports both, but they behave very differently, and the second one brings real engineering challenges along with its power. We will build the idea from first principles and then learn how to run it safely in production.

1The Problem: Too Much Telemetry

Why anyone needs to throw tracing data away in the first place.

Distributed tracing records the journey of each request through your system as a trace, made of many small timed steps called spans. A single checkout click in a busy online shop might create twenty or thirty spans as it passes through the gateway, the cart, the payment service, the inventory service, and the database. That is useful detail when something goes wrong, because you can see exactly where the time was spent or where the error began.

The trouble is volume. A system that handles five thousand requests per second and produces twenty spans per request creates a hundred thousand spans every second. Each span has a name, timestamps, and a handful of attributes, so storing and indexing them costs real money. Networks must carry them, backends must ingest them, and engineers must search through them. At some scale, keeping every trace becomes either unaffordable or unusable, and sometimes both.

5,000
requests per second in a busy system
20
spans created by each request
100,000
spans produced every second

The sensible answer is to keep only a portion of the traces. This is called sampling. The hard part is choosing which portion, because not all traces are equally valuable. Ninety-nine percent of requests are healthy and nearly identical to each other. The one percent that failed or crawled are the ones engineers actually need. Any sampling method that treats them all the same wastes budget on the boring majority and risks losing the precious few.

Simple Analogy

Think of a newspaper editor with a thousand photographs from a football match and room for ten. Picking ten at random would likely give ten photos of fans queuing for snacks. A good editor looks through them all and picks the goals, the injuries, and the celebrations. Tail-based sampling is that editor, and head-based sampling is the random draw.

2Sampling Basics You Need First

A shared vocabulary for the rest of the guide.

Term 1

Trace

The complete record of one request as it travels through every service involved, made of many spans joined together by a shared trace identifier.

Term 2

Span

One timed step inside a trace, such as a database query or an outgoing call. It has a start, an end, a status, and attributes.

Term 3

Root Span

The very first span of a trace, created where the request enters the system. Every other span descends from it.

Term 4

Sampler

A piece of logic inside the SDK that decides, when a span is created, whether it should be recorded and exported.

Term 5

Sampling Decision

The yes or no answer about keeping a trace. Once made, it is usually final, because dropped data cannot be recovered.

Term 6

Collector

A separate OpenTelemetry service that receives telemetry, processes it, and forwards it to a backend. It is where tail-based sampling normally lives.

The goal of sampling

Sampling is not about collecting less information for its own sake. It is about spending a limited budget of storage, network, and attention on the information most likely to be useful. A good sampling strategy keeps the interesting traces, keeps enough ordinary traces to understand normal behaviour, and keeps the total within budget.

Why whole traces matter

A trace is only helpful when it is complete. If a sampling method keeps the span from the gateway but drops the span from the database, the story has a hole in it. Both head-based and tail-based sampling try to keep or drop whole traces together rather than individual spans, which is why the decision is tied to the trace identifier and not to single spans.

i
Remember

Sampling decides what to keep. It does not decide how spans are created. Your application still does the work of creating spans unless the decision is made early enough to skip it, which only head-based sampling can do.

3A Quick Look at Head-Based Sampling

The simple approach that tail-based sampling improves upon.

In head-based sampling, the decision is made at the very beginning of the trace, when the root span is created. The sampler inside the SDK looks at a few facts available at that moment, such as the trace identifier or the name of the operation, and answers yes or no. If the answer is no, the SDK can avoid recording the spans at all, saving the work of building and exporting them.

OpenTelemetry SDKs ship with several built-in samplers. One keeps everything, one drops everything, and one keeps a fixed percentage of traces based on the trace identifier. A fourth kind follows the parent: if the incoming request already carries a decision from an upstream service, the sampler simply obeys it. This is how the decision, made once at the entry point, spreads to every other service. It travels inside the trace context header as a flag that says whether the trace is sampled.

Advantages

  • Very cheap, because decisions need no buffering
  • Dropped traces cost almost nothing to produce or send
  • Simple to configure with a single percentage
  • Stateless, so it scales without coordination
  • The decision spreads automatically through trace context

Disadvantages / Trade-offs

  • Decides before knowing how the request will end
  • Cannot tell an error or slow request from a normal one
  • A rare failure has the same small chance of being kept as anything else
  • Raising the percentage to catch more failures raises cost for everything
Simple Analogy

Head-based sampling is like deciding at the door of a restaurant which diners will be allowed to write a review, before they have eaten anything. You cannot know who will have a terrible experience, so you choose by lottery and hope the unhappy ones are among the chosen.

!
The Core Weakness

Imagine one percent of requests fail, and you keep five percent of traces at random. You will keep only about five percent of the failures too. Ninety-five percent of the things you most wanted to investigate are gone before anyone looked at them.

4So, What Is Tail-Based Sampling?

Deciding at the end of the story instead of the beginning.

Tail-based sampling means the decision to keep or drop a trace is made after the trace, or most of it, has been observed. The system collects the spans, holds them for a short time, looks at the whole picture, and only then applies rules. Did any span report an error? Was the total duration unusually long? Did the request involve a particular customer or feature? If the answer to an interesting question is yes, the trace is kept. If nothing stands out, it may be dropped or sampled at a low rate.

“Head-based sampling guesses before the story is told. Tail-based sampling waits for the ending.”

The word tail refers to the end of the trace, in contrast to the head at its beginning. Because the decision happens at the end, it can use information that did not exist at the start: the final status, the total latency, the number of spans, and the attributes that downstream services added along the way.

AspectHead-based samplingTail-based sampling
When the decision is madeWhen the trace beginsAfter the trace has been observed
Information availableTrace identifier, root span detailsWhole trace including errors, latency, and attributes
Where it runsInside the application SDKUsually in an OpenTelemetry Collector
Resource costVery lowMemory and compute to buffer traces
Can keep all errorsNoYes
Saves work in the applicationYes, dropped spans are never builtNo, spans are built and sent first
Operational complexityLowHigher, needs routing and sizing care
Simple Analogy

Tail-based sampling is like a film editor who watches the whole rough cut before choosing scenes for the trailer. Head-based sampling is like choosing scenes by rolling a die before the film is shot. The editor pays with time and a large room to store the rough footage, but the trailer is far better.

The price of seeing the ending

Waiting is not free. To decide at the end, something has to hold on to all the spans of every trace until the end arrives. That something needs memory, it needs a rule for how long to wait, and it needs to receive all the spans of a single trace in one place. Each of these needs shapes the architecture that the rest of this guide describes.

5How Tail-Based Sampling Works, Step by Step

From the first span arriving to the final keep or drop.

sequenceDiagram
  participant A as Applications
  participant C as Collector sampling stage
  participant B as Backend
  A->>C: Spans of trace 42 arrive from several services
  Note over C: Group spans by trace identifier and start a timer
  A->>C: More spans of trace 42 arrive
  Note over C: Timer ends, apply policies to the whole trace
  alt A policy says keep
    C->>B: Export every span of trace 42
  else No policy says keep
    Note over C: Drop trace 42 and remember the decision
  end
  A->>C: A late span of trace 42 arrives
  Note over C: Look up the remembered decision and act on it
        
FIG 1 — The life of one trace inside a tail sampling stage
1

Applications send everything

The SDKs record and export all spans, or at least a high share of them, to a Collector. Nothing is dropped yet, because the interesting facts are not known yet.

2

The Collector groups by trace

As spans arrive from many services, the sampling stage files each one under its trace identifier, building up a picture of each request in memory.

3

A timer starts

When the first span of a trace arrives, a countdown begins. This waiting period gives the slower services time to deliver their spans.

4

Policies evaluate the whole trace

When the timer ends, the stage runs a list of rules against everything it has gathered, looking at errors, duration, attributes, and size.

5

Keep or drop

If the rules say keep, all spans of the trace are sent on to the backend together. If not, they are discarded and their memory is freed.

6

Remember the decision

The outcome is cached for a while so that any span that arrives late can be handled consistently with its trace.

i
The Key Insight

Nothing about this process needs the applications to know what the sampling rules are. Teams can change the rules centrally in the Collector without redeploying a single service, which is one of the practical reasons organisations like this approach.

6Where It Runs: The Collector Tail Sampling Processor

The component that does the waiting, grouping, and deciding.

Tail-based sampling in OpenTelemetry is implemented by a component of the Collector known as the tail sampling processor. Processors are building blocks that sit in the middle of a Collector pipeline: data comes in from receivers, passes through processors that can modify, filter, or group it, and then leaves through exporters. The tail sampling processor is distributed in the contrib collection of Collector components, so you need a Collector build that includes it.

The processor is configured with a handful of settings that control how long it waits, how much it remembers, and which rules it applies. Understanding these settings in plain language is more important than memorising their exact names, because names and defaults can differ between versions.

Setting

Decision wait

How long the processor waits after seeing the first span of a trace before it evaluates the rules. A longer wait catches slow traces more completely but uses more memory and delays the result.

Setting

Number of traces

The maximum count of traces held in memory at once. When the limit is reached, the oldest traces may be evaluated early or dropped to make room.

Setting

Expected new traces per second

A hint that lets the processor allocate its internal structures sensibly for your traffic level.

Setting

Decision caches

Remembered keep and drop outcomes for recently decided traces, which allow late spans to be handled in line with their trace.

Setting

Policies

The list of named rules. Each one inspects the trace and votes to keep it or not.

How multiple policies combine

Most setups define several policies, such as one for errors, one for latency, and one that keeps a small random share of everything. In the default behaviour, a trace is kept if any one policy votes to keep it. That means each policy adds to the set of traces you keep, which makes it easy to say “keep all errors, and also all slow traces, and also five percent of the rest”. Newer versions add ways to combine rules more precisely, for example by requiring several conditions together or by explicitly dropping certain traces, so check the documentation for your version.

!
Version Differences

Policy types, setting names, and defaults have changed across releases of the processor. Always read the documentation for the exact Collector version you deploy, and test your configuration with realistic traffic before trusting it in production.

7The Policies: Deciding What Is Interesting

The vocabulary of rules you can apply to a finished trace.

A policy is a named rule that looks at a complete trace and answers a single question: should this one be kept? The processor supports a family of policy types, each aimed at a common reason for caring about a trace. Choosing the right mixture is the creative part of tail-based sampling.

Status code policy

Keeps traces that contain a span with a chosen status, most commonly an error. This is the most popular rule, because failed requests are almost always worth investigating.

Latency policy

Keeps traces whose total duration exceeds a threshold, for example anything slower than two seconds. This finds the slow requests that users complain about.

Attribute policies

Keep traces where a span attribute matches a value or falls in a range. Examples include a particular customer tier, a specific endpoint, a feature flag, or a numeric value such as an order amount above a limit.

Probabilistic policy

Keeps a fixed percentage of the remaining traces, chosen by trace identifier. This gives you a baseline sample of ordinary behaviour so that you can compare healthy requests against broken ones.

Rate limiting policy

Caps the number of spans kept per second. It protects the backend from surges, for example during an outage that makes every request an error.

Span count policy

Keeps traces with a number of spans within a range. Unusually large traces often reveal loops or runaway fan-out, and unusually tiny ones may reveal early exits.

Composite and combined policies

Combine several conditions, apply different rate budgets to different kinds of traffic, or require two conditions to hold together. Newer versions also allow expressions that look at span details in a flexible way.

Question you want answeredPolicy to reach for
Show me everything that failedStatus code policy
Show me everything that was slowLatency policy
Show me traffic for one important customerAttribute policy
Show me what normal looks likeProbabilistic policy
Protect my backend during a stormRate limiting policy
Find runaway or strangely small tracesSpan count policy
i
Always Keep a Baseline

Do not keep only errors and slow traces. Keeping a small random share of healthy traces gives you a reference for what good looks like, which makes it far easier to spot what is different about the bad ones.

8A Worked Example With Real Numbers

The same ten thousand traces, sampled both ways.

Suppose a shop produces ten thousand traces in a short period. Two percent of them contain an error, one percent are very slow but did not fail, and the other ninety-seven percent are ordinary. The team can afford to keep roughly five hundred traces. Let us see what each approach keeps.

Kind of traceTotalKept by head sampling at 5 percentKept by tail policies
Errors200About 10200, all of them
Slow but successful100About 5100, all of them
Ordinary9,700About 485About 485 at 5 percent
All traces10,000About 500About 785
10 of 200
errors kept by head sampling
200 of 200
errors kept by tail sampling
7.85%
share of all traces kept by the tail policies

What the numbers tell us

Head sampling at five percent keeps about five hundred traces, but only around ten of them are errors, and only about five are slow. An engineer investigating an outage sees a tiny, unrepresentative slice of the problem. Tail sampling keeps all two hundred errors and all one hundred slow traces, plus a five percent baseline of the rest, for a total of about 785. The storage bill is only about fifty-seven percent higher than head sampling, but the number of useful traces is more than twenty times greater.

If the team wants to stay at exactly five hundred traces, they can lower the baseline for ordinary traces to about 2.1 percent, which keeps around 200 of the ordinary ones. The total becomes roughly five hundred, yet every error and every slow trace is still present. That is the real prize of tail sampling: you move the budget from the boring majority to the valuable minority.

Simple Analogy

Imagine a teacher who can only read ten essays in depth out of a hundred. Picking ten at random might miss the brilliant one and the one that cheated. Skimming all hundred first and then reading the standouts in depth takes more effort up front but never misses what matters.

!
Numbers Are Illustrative

Real traffic rarely splits into such neat percentages, and errors often cluster in time. During an incident, the share of error traces can jump from two percent to ninety percent, which is why rate limiting policies exist to cap the total.

9The Routing Problem: Every Span of a Trace in One Place

The architectural catch that surprises most newcomers.

To judge a whole trace, a single sampling stage must see all of its spans. This sounds obvious, but in a real system the spans of one trace are produced by many different services, running on many different machines, each sending data to whichever Collector instance happens to be convenient. If you run several Collector instances behind an ordinary load balancer, the spans of one trace get scattered across them. Each instance sees only a fragment, and the decisions it makes are based on incomplete information.

A fragment can mislead badly. One instance may hold the slow database span but not the error span, so it sees no reason to keep the trace. Another instance may hold the error span but not the long duration. Different instances may even make different decisions about the same trace, producing a backend that holds half a trace. The fix is to make sure all spans with the same trace identifier are routed to the same sampling instance.

flowchart LR
  A["Services and SDKs"] --> B["Tier one Collectors"]
  B -->|"Route by trace identifier"| C["Tier two Collector 1 with tail sampling"]
  B -->|"Route by trace identifier"| D["Tier two Collector 2 with tail sampling"]
  B -->|"Route by trace identifier"| E["Tier two Collector 3 with tail sampling"]
  C --> F["Backend"]
  D --> F
  E --> F
        
FIG 2 — A two-tier layout where the first tier routes and the second tier decides

The two-tier pattern

The standard solution is two layers of Collectors. The first layer receives spans from applications and forwards them using a load balancing exporter that picks the destination by trace identifier. Because the same identifier always maps to the same destination, all spans of one trace end up on one second-layer instance. The second layer runs the tail sampling processor and has a complete view of each trace.

1

Applications send to tier one

Any tier-one instance can accept any span. These instances do little work and are easy to scale up and down.

2

Tier one picks a destination by trace identifier

The load balancing exporter uses a consistent method so the same trace identifier always goes to the same backend instance.

3

Tier two buffers and decides

Each tier-two instance owns a share of traces completely, so its policies see whole traces.

4

Tier two exports the keepers

Only the traces that pass the policies are sent on to the observability backend.

Finding the second tier

The load balancing exporter needs to know which second-tier instances exist. It supports several ways of finding them, such as a fixed list, a lookup through DNS, or discovery through an orchestration platform. When instances are added or removed, the mapping from trace identifiers to instances changes, and a few traces in flight at that moment may be split. This is a normal cost of scaling and a reason to avoid frequent resizing of the sampling tier.

!
The Most Common Mistake

Putting the tail sampling processor on several Collector instances behind a plain round-robin load balancer. It appears to work, because data still flows, but the decisions are made on fragments and the results are quietly wrong.

10Time and Memory: Decision Wait, Buffers, and Late Spans

Waiting for the ending costs memory, and the clock never stops.

Holding traces while they finish is the central resource cost of tail sampling. Every span that arrives must stay in memory until its trace is decided. The amount of memory therefore depends on how many traces arrive per second, how large each one is, and how long the processor waits before deciding.

10 KB
example size of one trace of 20 spans
5,000
new traces arriving each second
1.5 GB
buffered during a 30 second wait

Take a moderate example. If one trace of twenty spans takes about ten kilobytes, and five thousand new traces arrive every second, then a thirty second decision wait means about a hundred and fifty thousand traces in memory at once, which comes to around one and a half gigabytes. Real memory use is usually higher than the raw size of the data, because in-memory structures carry extra overhead, so plan with a generous margin. All of this must be spread across the tier-two instances, which is why the second tier is sized for memory rather than for processing speed.

Choosing the decision wait

The wait is a trade-off between completeness and cost. If it is too short, slow services may not have delivered their spans yet, and the processor decides on an incomplete trace. A trace whose error span arrives after the verdict may be dropped because the policy never saw the error. If the wait is too long, memory use grows and the backend sees data later. A good starting point is a little longer than the slowest typical request in your system, and teams then adjust using what they observe.

Long traces and late spans

Some traces last far longer than any reasonable wait, for example a background job that continues for minutes after the request that started it. A decision made after thirty seconds will cut such a trace short. The decision caches help here. When a span arrives after its trace has already been decided, the processor looks up the remembered outcome and either forwards or discards the span accordingly. This keeps the tail of a kept trace from being lost, though it cannot rescue a trace that was wrongly dropped before the important span arrived.

1

Measure your slowest normal request

Use existing tracing data to find the typical upper end of request duration, ignoring truly extreme cases.

2

Set the wait just above it

Give slow services enough time to deliver their spans without holding everything for longer than needed.

3

Size memory from the wait

Multiply traces per second by the wait and by the size of a trace, then add a safety margin for overhead.

4

Protect the process

Use a memory limiting stage ahead of sampling so that a surge slows intake instead of crashing the Collector.

i
Watch for Early Evictions

If the buffer fills before the wait expires, the processor may be forced to decide on traces early or drop them. Monitoring for this condition tells you that either the buffer is too small or the traffic has grown beyond the design.

11Combining Head and Tail Sampling

They are not rivals. Used together, each covers the other’s weakness.

Because tail sampling needs the spans to reach a Collector, it works only on the spans that applications actually send. If an SDK uses head-based sampling to drop ninety percent of traces before export, the Collector never sees those traces, and no tail rule can rescue the errors among them. This is the most important rule for combining the two: whatever the head sampler drops is gone for good.

So there are two common patterns. In the first, applications export everything, and the tail stage does all the sampling. This gives the best results but the highest cost in network traffic and Collector resources. In the second, a gentle head-based sample is applied first, for example to keep half of all traces, and tail sampling refines the half that remains. This reduces load at the cost of losing some interesting traces before the tail stage can see them.

StrategyWhat applications doMain strengthMain weakness
Head onlySample at a low rate in the SDKCheapest to runMisses most errors
Tail onlyExport all traces to CollectorsKeeps every interesting traceHighest network and memory cost
Gentle head plus tailDrop a modest share in the SDKBalances cost and qualitySome interesting traces lost early

A subtle trap with parent-based samplers

Many SDKs default to a sampler that obeys the decision made by the parent span. If the root service has a sampler that keeps only a small share, the sampled flag in the trace context tells every other service to drop the rest. This spreads the head decision across the whole system, which is exactly what you do not want when you plan to use tail sampling. For tail sampling to see everything, the entry-point sampler must keep all traces, and the downstream services must follow that decision.

Metrics must be computed before sampling

Request counts, error rates, and latency distributions are among the most valuable things you can derive from spans. If you compute them after sampling, they will be wrong, because you have thrown away most of the normal traffic. The remedy is to compute metrics from the full stream of spans before the sampling stage, using a Collector component that turns spans into metrics, and then sample the traces for storage afterwards.

flowchart LR
  A["Receive spans"] --> B["Memory limiter"]
  B --> C["Span to metrics step on all spans"]
  C --> D["Tail sampling"]
  D --> E["Export kept traces"]
  C --> F["Export metrics"]
        
FIG 3 — Metrics are taken from every span before sampling removes any
!
Do Not Chart Sampled Counts

If a dashboard counts traces that survived sampling, the number is a function of your sampling rules and not of real traffic. A change in policy would appear as a change in traffic. Always base rates and totals on metrics computed before sampling.

12Reading Sampled Data Without Fooling Yourself

Sampling changes the meaning of the numbers you see.

A sampled set of traces is not a faithful miniature of reality. Tail sampling in particular deliberately over-represents errors and slow requests. If you open your tracing tool and see that half of the traces have errors, that does not mean half of your requests fail. It means your sampling policy kept all the failures and only a trickle of the successes. Reading the data as though it were a random sample leads to badly wrong conclusions.

Simple Analogy

Imagine a museum that exhibits only the strangest objects from a huge collection. A visitor who walks through might conclude that the world is full of oddities. The exhibit is accurate about each object, but it says nothing about how common each kind of object is.

Re-weighting with recorded probability

To estimate real totals from a sample, you need to know how likely each trace was to be kept. A trace kept with a probability of one in twenty stands for about twenty traces. OpenTelemetry has been developing conventions for recording the sampling probability alongside the data, so that backends can scale counts back up correctly. With a mix of policies, some traces are kept with certainty and others with a small probability, so recording that information per trace becomes essential for any accurate arithmetic.

1

Use pre-sampling metrics for totals

Take counts, rates, and percentiles from metrics computed on the full stream of spans.

2

Use sampled traces for investigation

Treat the traces as detailed case files, not as a statistical sample of traffic.

3

Keep a labelled random baseline

If you must estimate proportions from traces, use only the baseline portion whose keep probability is known and uniform.

4

Record how traces were chosen

Where your tools support it, store the sampling probability or the name of the policy that kept each trace, so later analysis can account for it.

i
A Healthy Division of Labour

Let metrics answer how much and how often. Let traces answer why and where. Sampling is acceptable for traces because metrics preserve the totals.

13Advantages and Trade-offs

An honest balance sheet before you commit.

Advantages

  • Keeps all errors, or any outcome you choose to describe
  • Keeps slow requests that users actually notice
  • Lets you target important customers, endpoints, or features
  • Rules can change centrally without redeploying applications
  • Moves the storage budget towards valuable traces
  • Rate limits protect the backend during incidents

Disadvantages / Trade-offs

  • Needs memory to buffer every trace until it is decided
  • Requires a two-tier layout with trace-aware routing
  • Adds a delay before traces appear in the backend
  • Applications still create and send every span
  • Misconfigured waits or routing silently damage results
  • The sampling tier is stateful and harder to scale and restart
ResourceEffect of tail sampling
Application CPUUnchanged, because all spans are still created
Network between applications and CollectorsHigher, since nothing is dropped early
Collector memoryMuch higher, proportional to traffic and wait
Backend storage and ingestLower, since only chosen traces arrive
Engineer timeSaved when finding incidents, spent when operating the tier

When it is worth it

Tail sampling pays off when your volume is high enough that you cannot keep everything, when failures are rare but costly, and when you have the engineering capacity to run a stateful Collector tier. It pays off less when traffic is small enough to store in full, or when your team has no appetite for operating extra infrastructure.

Simple Analogy

Tail sampling is like hiring a night editor for a newsroom. The editor costs salary and needs a desk, but the newspaper stops missing its biggest stories. For a tiny leaflet with three stories a week, the editor is not worth the money.

14Security and Privacy Considerations

The sampling tier sees everything, so it deserves protection.

Before sampling, the Collector tier receives the full, unfiltered stream of spans, including attributes that may contain sensitive information such as user identifiers, internal addresses, or fragments of queries. This is a bigger concentration of data than a backend that only receives the sampled subset, so the sampling tier becomes an attractive target and should be treated as a sensitive system.

Control 1

Encrypt in transit

Use encrypted connections between applications, tier one, tier two, and the backend so that spans cannot be read or altered on the network.

Control 2

Authenticate senders

Accept spans only from known clients so that outsiders cannot flood the tier or inject misleading traces.

Control 3

Redact before storing

Remove or mask sensitive attributes in a processing stage, ideally before the data leaves the sampling tier for the backend.

Control 4

Restrict access

Limit who can reach the Collectors, read their configuration, or view their diagnostic output, since memory contents hold live data.

Sampling rules can be manipulated

Policies that depend on span attributes trust whatever the applications report. If a public-facing client can influence an attribute, such as a custom header that is copied onto a span, an attacker could make their traffic look interesting enough to be kept, or make real problems look boring. Sampling rules should rely on facts that your own services set, not on values controlled by outside callers.

!
Fairness and Bias

Because tail sampling deliberately favours certain traces, the kept data reflects your rules, not reality. Be careful when using sampled traces to make claims about customer behaviour or system health, and document the policies so that later readers understand what the data represents.

15Real-World Uses of Tail-Based Sampling

Where organisations commonly apply it.

The following examples describe patterns that are widely used across the industry. They show how the same machinery of waiting, grouping, and judging can serve very different goals.

E-commerce checkout

An online retailer keeps every trace in which a payment failed, every trace slower than a few seconds, and a small share of the successful ones. When the finance team reports missing orders, engineers can pull the exact failed attempts without having stored a flood of healthy browsing traffic.

Protecting important customers

A software company keeps every trace for its largest enterprise accounts, identified by an opaque account label set by its own gateway. When a key customer reports a problem, there is always a trace to examine.

Rollouts and canaries

During a gradual release, a team keeps all traces that touch the new version, while sampling the old version lightly. This gives complete detail on the thing being tested at a modest cost.

Incident cost control

When an outage turns nearly every request into an error, a rate limiting policy caps the number of kept traces per second. The backend stays healthy and engineers still receive a steady stream of examples.

Hunting rare bugs

A team investigating a once-in-a-million failure keeps every trace that contains a particular error code or that shows an unusual span count, so the rare event is captured the moment it occurs.

Managed alternatives

Some observability vendors and open-source tools offer their own tail-based sampling, sometimes as a managed service, using the same idea of grouping spans and judging whole traces. They remove some of the operational work but still rely on the same principles described here.

i
Pattern to Notice

In every example, the rule is written in terms of outcomes and business meaning, not in terms of a random number. That shift in thinking is the true change that tail sampling brings.

16Design Patterns and Anti-patterns

What works in practice, and the traps that catch experienced teams.

flowchart TD
  A["Can you afford to store every trace?"] -->|Yes| B["Keep everything and skip sampling"]
  A -->|No| C{"Do rare failures matter more than averages?"}
  C -->|No| D["Head-based sampling is probably enough"]
  C -->|Yes| E{"Can you run a stateful Collector tier?"}
  E -->|No| F["Use a managed tail sampling service or gentle head sampling"]
  E -->|Yes| G["Use two-tier tail sampling with pre-sampling metrics"]
        
FIG 4 — A simple path for choosing a sampling approach

Patterns that work

Pattern 1

Two tiers, trace-aware routing

Separate the routing layer from the deciding layer, and route by trace identifier so every sampler sees whole traces.

Pattern 2

Errors, slow, baseline

Combine a rule for failures, a rule for slowness, and a small random share of everything else as the standard starting set.

Pattern 3

Metrics before sampling

Derive request and error metrics from all spans before any trace is dropped, so dashboards stay truthful.

Pattern 4

Guard rails

Add a memory limiter and a rate limiting policy so that surges degrade gracefully instead of crashing the tier.

Pattern 5

Review policies regularly

Revisit thresholds as traffic and latency change, because yesterday’s slow is today’s normal.

Anti-patterns to avoid

ANTI-PATTERN-01 Avoid
Problem

The tail sampling processor runs on several Collector instances behind an ordinary load balancer that spreads spans without regard to trace identifier.

Why It’s Harmful

Each instance sees only fragments of traces, so policies based on errors or total duration decide on partial information. Different instances may make different choices for the same trace, leaving incomplete traces in the backend.

Correct Approach

Add a first tier that routes spans by trace identifier, so each trace lands on exactly one deciding instance.

ANTI-PATTERN-02 Avoid
Problem

Applications apply an aggressive head-based sample, such as one percent, and the Collector then applies tail sampling on what is left.

Why It’s Harmful

Ninety-nine percent of errors are discarded before the tail stage can see them, so the carefully written error policy rescues almost nothing.

Correct Approach

Let applications export all traces, or use only a gentle head sample, and put the real selection in the tail stage.

ANTI-PATTERN-03 Avoid
Problem

Dashboards compute request rates and error percentages from the traces that survived sampling.

Why It’s Harmful

The numbers reflect the sampling rules, not real traffic, and change whenever the rules change. An outage can even look like an improvement if the rate limit starts dropping traces.

Correct Approach

Compute metrics from all spans before sampling and use sampled traces only for investigation.

ANTI-PATTERN-04 Avoid
Problem

The decision wait is set to a few seconds because shorter feels faster, while real requests and background work last much longer.

Why It’s Harmful

Decisions are made before the slow or failing spans arrive, so the very traces you wanted are judged as boring and dropped.

Correct Approach

Base the wait on measured request durations and use the decision caches to handle the late spans that remain.

17Monitoring and Operating the Sampling Tier

A system that decides what you can see must itself be watched closely.

The sampling tier fails in quiet ways. A misrouted trace, a buffer that is too small, or a wait that is too short will not crash anything. They simply cause the wrong traces to be kept, and nobody notices until an important investigation finds an empty search result. The Collector exposes metrics about its own behaviour, and the tail sampling processor reports on things like how many traces were kept and dropped, how many are sitting in memory, how long decisions take, and how many traces were evicted too early or arrived late. Make these part of your standard dashboards.

What to watchWhy it mattersWarning sign
Traces held in memoryShows buffer pressureSteady climb toward the configured limit
Traces dropped too earlyShows buffer overflow forcing early decisionsAny sustained non-zero rate
Decision latencyShows how long traces wait before judgmentRising delay beyond the configured wait
Late span ageShows whether the wait is long enoughMany spans arriving long after decisions
Kept versus dropped counts per policyShows which rules do the workOne policy keeping nearly everything
Collector memory and restartsShows stability of a stateful tierFrequent restarts that lose buffered traces
1

Test policies on recorded traffic

Before changing a rule in production, replay realistic data through a test instance and compare what it keeps with what you expected.

2

Roll out changes gradually

Apply new policies to a single second-tier instance or a small share of traffic first, and watch the keep rate and memory.

3

Alert on silent damage

Alert on early drops, falling keep rates for errors, and a sudden change in total traces exported, not only on process health.

4

Plan restarts carefully

Restarting a second-tier instance loses the traces it holds. Drain and restart one at a time, during quiet periods, and accept that a few traces may be split.

5

Keep a known good test trace

Send a synthetic trace that should always be kept, such as one with a deliberate error, and alert when it fails to appear in the backend.

i
Document the Policies

Write down what each policy keeps and why, who owns it, and when it was last reviewed. Months later, someone will ask why a trace is missing, and the answer should be easy to find.

18Frequently Asked Questions

Short answers to the questions people ask most often.

Q1Where does tail-based sampling happen in OpenTelemetry?

It normally happens in an OpenTelemetry Collector, using the tail sampling processor from the contrib components. Applications export their spans, and the Collector decides which complete traces to keep.

Q2Can the SDK do tail-based sampling by itself?

Not in the usual sense. An SDK only sees the spans of its own service and makes decisions as spans start, so it cannot judge a whole multi-service trace. Whole-trace decisions need a place where all spans meet, which is why Collectors are used.

Q3Does tail sampling reduce the load on my applications?

No. Applications still create and export every span so that the Collector can judge complete traces. Tail sampling reduces what reaches the backend, not what the applications produce.

Q4Why do I need two layers of Collectors?

Because the sampler must see all spans of a trace. The first layer routes spans by trace identifier, and the second layer holds and judges them. Without the routing layer, spans of one trace would scatter across instances.

Q5What happens to spans that arrive after a decision?

The processor can remember recent decisions in caches. A late span is checked against the remembered outcome and is kept or dropped to match its trace. A trace dropped before an important span arrived cannot be recovered.

Q6How long should the decision wait be?

Slightly longer than the slowest normal request in your system, based on measurement rather than guesswork. A longer wait improves completeness but increases memory use and delays traces from reaching the backend.

Q7Can I use head and tail sampling together?

Yes, but anything the head sampler drops never reaches the tail stage. Use a gentle head sample or none at all if catching rare failures matters, and make sure parent-based samplers do not spread a low keep rate to every service.

Q8Will my request and error metrics be wrong after sampling?

They will be wrong if you compute them from sampled traces. Compute metrics from all spans before the sampling stage, and use sampled traces only for investigation.

Q9What if more than one policy matches a trace?

In the default behaviour, a trace is kept when any policy votes to keep it. Newer versions add ways to require several conditions together or to drop explicitly, so confirm the behaviour in the documentation for your version.

Q10Is tail-based sampling always better than head-based sampling?

No. It keeps far better traces, but it costs more memory, more network traffic, and more operational effort. For small systems, or where simplicity matters most, head-based sampling or keeping everything can be the wiser choice.

19Summary and Key Takeaways

Tail-based sampling answers a simple but powerful question: why decide what to keep before you know what happened? By collecting the spans of a trace, waiting for the story to finish, and then applying rules to the complete picture, it lets you keep every failure, every slow request, and every trace that matters to your business, while discarding most of the uneventful majority. In the worked example, the same budget that head sampling spent mostly on healthy traffic kept every error instead.

That power has a price. The sampling tier must hold traces in memory, receive every span of a trace in one place, and be watched carefully, because its failures are silent. Applications still create and send every span, and metrics must be computed before sampling or they will lie. Used with a two-tier layout, sensible waits, guard rails, and good monitoring, tail sampling turns an overwhelming flood of telemetry into a focused collection of the traces you actually need. Like the editor choosing photographs after the match, it works because it waits for the ending.

Key Takeaways

  • The decision comes at the end — tail-based sampling judges a trace after it has been observed, using errors, latency, attributes, and size that did not exist at the start.
  • It runs in the Collector — the tail sampling processor groups spans by trace, waits, applies policies, and keeps or drops whole traces together.
  • Policies describe what is interesting — combine rules for errors, slowness, important attributes, and a small random baseline so you keep both the exceptions and the norm.
  • Routing is mandatory — every span of a trace must reach the same deciding instance, which usually means a first tier that routes by trace identifier and a second tier that samples.
  • Memory and time are the cost — the buffer grows with traffic, trace size, and the decision wait, so size the tier carefully and protect it with a memory limiter and rate limits.
  • Do not let head sampling undo it — whatever an SDK drops early never reaches the tail stage, so keep the SDK sample gentle or off and avoid spreading a low keep rate through parent-based samplers.
  • Compute metrics before sampling — use full-stream metrics for rates and totals, use sampled traces for investigation, and watch the sampling tier closely because its failures are silent.