What Is TraceIdRatioBased Sampling in OpenTelemetry?

What Is TraceIdRatioBased Sampling in OpenTelemetry?

A plain-English guide to the sampler that keeps a fixed fraction of your traces by looking at the trace ID. You will learn how it decides, why every service agrees without talking, where it falls short, and how to choose a ratio you can defend.

Imagine a school that wants to know how students feel about lunch. Asking all two thousand students every day would be exhausting, and most answers would repeat each other. So the school picks a fixed fraction, say one student in ten, and asks only those. If the picking is fair, the answers from those students tell the school nearly everything it needs to know, at a tenth of the effort.

Tracing faces the same situation. A busy system can produce millions of traces every hour, and storing and searching all of them is expensive. Sampling is the practice of keeping only some traces. The TraceIdRatioBased sampler is one of the simplest and most widely used ways to do it. You give it a ratio, such as 0.1 for one trace in ten, and it keeps about that fraction.

The clever part is how it picks. It does not roll a dice. It looks at the trace’s own ID and turns that into a yes or no. Because every service sees the same trace ID, every service reaches the same answer, with no coordination. This guide assumes you know nothing and explains each new word the first time it appears, always with an everyday comparison.

1The Short Answer: One Page Before the Long Story

If you only have two minutes, this chapter gives you the whole idea. The remaining chapters explain why it works and how to use it well.

TraceIdRatioBased is a built-in OpenTelemetry sampler. A sampler is the part of the SDK that decides, when a new span starts, whether its trace should be recorded and exported or thrown away. TraceIdRatioBased makes that decision using two things only: the trace ID, a long random number that names the trace, and a ratio between zero and one that you configure.

In simple terms, it treats the trace ID as a number, checks whether that number falls inside the lowest fraction of all possible numbers, and keeps the trace if it does. With a ratio of 0.25, about a quarter of all trace IDs fall inside that range, so about a quarter of traces are kept. The decision depends only on the ID and the ratio, which means the same trace gets the same answer everywhere.

0 to 1
the ratio you choose, where 0.1 means about one trace in ten
Same ID
gives the same answer in every service with the same ratio
Head
the decision is made when the trace begins, before its outcome is known
QuestionAnswer in one line
What does it decide?Whether a trace is recorded and exported
What does it look at?Only the trace ID and the configured ratio
Is it random each time?No. It is deterministic, so the same ID always gives the same answer
Does it know if a request fails?No. It decides at the start, before the outcome
Usually used with?A ParentBased wrapper, so child services follow the root decision
Everyday Analogy

Think of a library that keeps a copy of every book whose catalog number ends in 0, which is one book in ten. No librarian needs to flip a coin or ask a colleague. Anyone holding a catalog number can instantly tell whether the book is kept. TraceIdRatioBased works like that, with the trace ID as the catalog number.

i
Tip

Remember this phrase: a fixed share, chosen by the ID, decided at the start. It captures the strength, which is simplicity and agreement, and the weakness, which is that it cannot favor interesting traces.

2Why Sampling Exists: The Problem of Too Much Data

Before learning how to keep fewer traces, it helps to see why anyone would throw data away on purpose.

A trace is the story of one request as it moves through your system. It is made of spans, where each span is one timed step, such as “check the cart” or “query the database”. A single request in a system of many small services can easily create twenty or fifty spans.

Now multiply. If a service handles one thousand requests per second and each creates thirty spans, that is thirty thousand spans every second, which is about 2.6 billion per day. Each span carries a name, timestamps, identifiers, and attributes, so it may weigh a kilobyte or more. At one kilobyte each, that is roughly 2.6 terabytes of trace data per day from a single modest service. Storing it, indexing it, and searching it costs real money, and sending it uses network and processor time inside your applications.

Most traces look alike

The second half of the story is that most of that data is boring. If ninety-nine requests out of a hundred are healthy and fast, their traces teach you almost the same lesson each time. Keeping one in ten of them still shows you what normal looks like, and costs a tenth as much. The interesting traces, which are the slow ones and the broken ones, are a small minority, and you would like to keep as many of those as you can.

The trade you are making

Sampling trades completeness for cost. You give up the ability to look up any individual request, and in return you pay less and stay fast. A good sampling plan makes that trade deliberately, so you know what you gave up and what you kept.

Everyday Analogy

A weather agency does not measure the air at every square meter of the country. It places stations at chosen spots and builds an accurate picture from them. Nobody complains that the forecast ignored their back garden, because the picture is still good enough to decide whether to carry an umbrella.

i
Good to Know

The numbers above are round examples chosen to show the scale. Real sizes depend on how many attributes and events your spans carry and on how well your backend compresses them.

3Core Vocabulary You Need

A short list of words appears in every sampling conversation. Learn these once and the rest of the guide reads easily.

TermPlain meaningEveryday picture
TraceThe whole story of one request across servicesA full receipt of a shopping trip
SpanOne timed step inside a traceOne line on that receipt
Trace IDA long random number that names the traceA tracking number on a parcel
Root spanThe first span of a trace, with no parentThe front door entry in a visitor log
SamplerThe component that decides to record or drop a traceThe person at the door picking who gets a survey
SampledMarked to be recorded and exportedChosen for the survey
RatioThe fraction of traces to keep, from 0 to 1One in ten means 0.1
Head samplingDeciding at the start of a traceChoosing survey takers at the entrance
Tail samplingDeciding after the whole trace is seenChoosing after reading all the answers
Context propagationPassing trace information from service to serviceThe parcel label that travels with the parcel
DeterministicAlways gives the same output for the same inputA calculator, not a dice

Two ideas hiding in the table

First, sampling is decided per trace, not per span. The goal is to keep whole stories, not random sentences from them. If you kept a random half of the spans from every trace, no trace would be readable. Good sampling keeps a trace in full or drops it in full.

Second, a sampled trace is a trace that is recorded and sent onward. An unsampled trace may still be created in a lightweight form so that its identifiers can travel to other services, but its details are not kept. This difference between “still travels” and “is kept” becomes important when you meet the ParentBased wrapper later.

Everyday Analogy

A relay race baton always passes from runner to runner, even in a practice lap that nobody films. The camera crew films only the laps that were marked as recorded. The baton is the trace context, and the filming decision is the sampling flag.

i
Tip

When you read documentation, ask which of these words a sentence is about. Many confusions come from mixing up head and tail sampling, or the sampler and the exporter.

4Where the Sampler Sits in the Pipeline

The sampler works at the very beginning of a span’s life. Seeing the whole path shows how much work sampling saves.

flowchart LR
    CODE["Application code starts a span"] --> TR["Tracer"]
    TR --> SAM{"Sampler decides"}
    SAM -- "drop" --> NOOP["Span is not recorded or exported"]
    SAM -- "record and sample" --> SP["Span records data"]
    SP --> PROC["Span processor"]
    PROC --> EXP["Exporter"]
    EXP --> BE["Collector or backend"]
Figure 1: The sampler decides at span start, before any recording, processing, or exporting happens

Reading the picture

Your application code asks the tracer to start a span. Before anything else happens, the tracer asks the sampler a question: “Should this trace be recorded?” If the answer is no, the span becomes an almost empty placeholder. It records no attributes, creates no events, and never reaches the processor or the exporter. If the answer is yes, the span records its data as usual and flows down the pipeline toward the backend.

This position at the very front is what makes sampling powerful for cost. A dropped trace saves everything downstream: the memory for attributes, the work in the span processor, the effort of packing and compressing, the network trip, and the storage at the end. Dropping data late, for example in the backend, saves only storage.

What the sampler can see

When it decides, the sampler is handed a small set of facts: the parent context if any, the trace ID, the span name, the span kind such as server or client, the attributes known at the start, and any links. It does not see how long the span will take, whether it will fail, or what its children will do, because none of that has happened yet. This is the heart of what “head sampling” means.

Everyday Analogy

A bouncer at a club door decides who comes in based on what they can see at the door. They cannot know who will cause trouble later. The decision is cheap and early, and that is both its strength and its limit.

i
Good to Know

Processors and exporters, which you may know from other guides, come after the sampler. The sampler decides what exists. The processor decides when to ship. The exporter decides how and where.

5The Sampler Contract: Three Possible Answers

Every sampler, built in or custom, gives one of a small set of answers. Understanding them explains how unsampled traces behave.

Answer 1

Drop

Do not record this span and do not export it. The trace flag says “not sampled”, so downstream services know too. Nothing is kept.

Answer 2

Record only

Create a full span that collects data, but do not mark it as sampled. Local processors can see it, yet it is not exported by the standard exporting processors, and the flag stays off.

Answer 3

Record and sample

Create a full span and mark the trace as sampled. It flows to the exporter and the flag tells downstream services to do the same.

What the sampler also returns

Besides the decision, a sampler can return a few extra attributes to add to the span, and it can update the trace state, which is a small bag of vendor-specific key-value pairs that travels with the trace. Simple samplers like TraceIdRatioBased usually add nothing extra. Newer, more advanced samplers use the trace state to record the sampling probability so that backends can later correct their counts.

The sampled flag

The decision turns into a single bit in the trace context called the sampled flag. When a service calls another service, it sends this flag along in a header, and the receiving service reads it. In the common W3C Trace Context format, the header is called traceparent and ends with two hexadecimal digits of flags, where the last bit means sampled. This is how a decision made once at the front door can be respected by every service behind it.

DecisionData collected?Exported?Flag sent downstream
DropNoNoNot sampled
Record onlyYesNo, by standard exporting processorsNot sampled
Record and sampleYesYesSampled
Everyday Analogy

At a concert, the film crew can ignore a song, take notes for the band’s own use, or film it for broadcast. The stage manager hangs a sign saying “broadcast” or not, so every camera and sound engineer knows what to do. The sampled flag is that sign.

i
Tip

TraceIdRatioBased uses only the first and third answers. It either drops the trace or records and samples it. The in-between answer is for special cases and custom samplers.

6The Built-In Samplers: Where TraceIdRatioBased Fits

OpenTelemetry ships with a small family of samplers. Meeting the whole family makes it clear what TraceIdRatioBased is for.

Simplest

AlwaysOn

Keeps every trace. Perfect for development and low traffic, expensive at scale.

Simplest

AlwaysOff

Keeps nothing. Useful for switching tracing off without removing instrumentation.

Fraction

TraceIdRatioBased

Keeps a fixed fraction chosen by the trace ID. The subject of this guide.

Wrapper

ParentBased

Follows the parent’s decision when there is one, and uses another sampler for traces that begin here.

How they combine

The first three are leaf samplers, which make a decision by themselves. ParentBased is a composite sampler, which wraps other samplers. A typical production setup combines them: ParentBased, with TraceIdRatioBased as the choice for new traces, and with the default behavior of following the parent for continuing traces. Many SDKs use a parent-based always-on arrangement as their default when you set nothing.

SamplerLooks at parent?Typical use
AlwaysOnNoDevelopment, tests, low traffic
AlwaysOffNoDisabling tracing quietly
TraceIdRatioBasedNoFixed percentage sampling at the root
ParentBasedYesRespecting upstream decisions in multi-service systems

The important detail about the parent

TraceIdRatioBased ignores the parent completely. It looks at the trace ID and the ratio, nothing else. If a service receives a request whose upstream already decided “sampled”, a bare TraceIdRatioBased sampler may still say “drop”, if the ID happens to fall outside its ratio, which can leave holes in the trace. This is why the ParentBased wrapper exists, and why it deserves its own chapters.

Everyday Analogy

A building has three simple door rules: everyone in, nobody in, or every tenth person in. A fourth rule says “if a tenant brought you, follow the tenant’s choice, and otherwise use the building rule”. The first three rules are simple. The fourth rule combines them.

!
Watch Out

Using a bare TraceIdRatioBased sampler in a service that is called by other services is a classic source of partial traces. Prefer the parent-based combination in such places.

7How TraceIdRatioBased Works: The Core Idea

The idea is small enough to explain with one picture of a number line.

A trace ID is just a big number

A trace ID in OpenTelemetry is sixteen bytes long, which is 128 bits. It is usually written as thirty-two hexadecimal characters. Hexadecimal is a way of writing numbers using the digits 0 to 9 and the letters a to f. Underneath, it is simply a very large number. The ID generator inside the SDK picks it at random, so across many traces the numbers are spread evenly over the whole range, much like random lottery tickets.

A ratio is a slice of the number line

Picture the range of all possible IDs as a long ruler. A ratio of 0.1 means “take the first tenth of the ruler”. The sampler converts your ratio into a threshold, which is a particular position on the ruler. If a trace’s ID, turned into a position, lands before the threshold, the trace is kept. If it lands after, the trace is dropped.

flowchart LR
    R["Ratio 0.25 chosen by you"] --> TH["Threshold at one quarter of the ruler"]
    ID["Trace ID read as a number"] --> CMP{"Is the ID below the threshold?"}
    TH --> CMP
    CMP -- "yes" --> KEEP["Record and sample"]
    CMP -- "no" --> DROP["Drop"]
Figure 2: The trace ID is compared with a threshold made from the ratio

Why this keeps about the right amount

Because IDs are random and evenly spread, any slice of the ruler holds about the same share of traces as its share of the ruler. A quarter of the ruler holds about a quarter of the traces. This is the same reasoning that makes lottery numbers fair: no ticket is more likely than another, so a fixed slice catches a predictable fraction.

The result is a decision that is cheap, because it is one comparison of two numbers. It needs no memory of earlier traces, no shared counter, and no talk with other services.

Everyday Analogy

Imagine a ruler one meter long, with every raffle ticket mapped to a point along it. The prize draw says that any ticket landing in the first twenty-five centimeters wins. Nobody needs to roll a dice, and every judge, holding the same ruler and the same ticket, agrees on the answer.

i
Good to Know

The exact way each language reads the ID and builds the threshold differs in small details, and the specification has historically left room for implementations here. The shape of the idea is the same everywhere.

8The Decision Step by Step

Here is exactly what happens inside the sampler each time a span starts. The steps are few, and each is fast.

1

Receive the facts

The tracer passes the sampler the trace ID, parent context, span name, kind, attributes, and links.

2

Take part of the trace ID

Many implementations use the lower 64 bits of the 128-bit ID, which are the last eight bytes. They read those bytes as one large number.

3

Compare with the threshold

The threshold was computed once when the sampler was created, by multiplying the ratio by the largest possible value of that number. The sampler checks whether the number is below it.

4

Return the decision

Below the threshold means record and sample. Otherwise it means drop.

5

Set the flag

The tracer records the result in the span’s trace flags, which will be sent to any service the request calls next.

Why only part of the ID

Using the lower 64 bits is a practical choice. A 64-bit number fits a standard integer type in most languages, so the comparison is fast and simple. It is also common for systems to generate IDs with a random lower half, even when other parts carry extra meaning. Some trace ID formats, such as those that place a timestamp in the first part, would give uneven results if the sampler read that part. Reading the lower bytes avoids this trap. The details differ by implementation and are covered by the language SDKs, so do not assume your SDK uses exactly these bytes without checking.

The description string

Samplers have a human-readable description that shows up in debugging output. For this sampler, it contains the name and the ratio, for example TraceIdRatioBased{0.100000}. Seeing this in logs is a quick way to confirm the ratio your service actually uses, which is handy when environment variables may have been overridden.

Everyday Analogy

Think of a coat check where the attendant looks only at the last two digits of a ticket. A ticket ending in 00 to 24 goes to the front rack. The attendant does not need to know who owns the coat, only the last digits, and the rule is quick to apply.

i
Tip

A deterministic rule that uses a small part of a random number is a very common trick in distributed systems. It lets many machines agree without talking.

9Why Determinism Is the Superpower

The decision depends only on the ID and the ratio. That single fact is behind almost every advantage of this sampler.

Agreement without conversation

Suppose a request passes through five services, and every one of them uses TraceIdRatioBased with a ratio of 0.1. Each service sees the same trace ID, so each one reaches the same answer. There is no need for the services to ask one another. If the first service decided to keep the trace, the second, third, fourth, and fifth would also decide to keep it, even if the flag was lost on the way. This gives you whole traces instead of fragments.

Repeatable behavior

Because there is no dice, the sampler behaves the same way every time. If you replay a trace ID through the sampler, you get the same answer. This is good for testing and reasoning. You can write a test that feeds known IDs to the sampler and checks the expected decisions.

No shared state

Many other sampling approaches need counters or coordination, such as a service that tracks how many traces were kept in the last second. TraceIdRatioBased keeps no state at all. Two copies of a service running on two machines make consistent choices without talking, and a restarted service behaves exactly like it did before.

flowchart TB
    ID["Trace ID 5b8e... same in every service"] --> A["Service A with ratio 0.1"]
    ID --> B["Service B with ratio 0.1"]
    ID --> C["Service C with ratio 0.1"]
    A --> DA["Same decision"]
    B --> DB["Same decision"]
    C --> DC["Same decision"]
Figure 3: One trace ID and one ratio give one decision, everywhere

Where agreement stops

The agreement holds only when the services use the same ratio, the same way of reading the ID, and the same ID. If two services use different ratios, or use different language SDKs that read the ID differently, they can disagree. This is one reason to rely on the parent’s flag as the main way of keeping traces whole, and to treat the deterministic agreement as a useful backup.

Everyday Analogy

Everyone in a village agrees on whether a given date is a market day because the rule is written on the calendar, such as the first Saturday of each month. Nobody needs a town crier. If one village uses a different calendar, they will disagree.

!
Watch Out

Never rely on ratio-based agreement alone across services that use different ratios or different languages without testing. Always add the parent-based wrapper so the flag is the leading authority.

10The Fine Print: Trace IDs Must Be Random

The fairness of the whole scheme depends on one assumption. If it fails, the numbers you get can be quietly wrong.

The sampler assumes that trace IDs are spread evenly over their range. OpenTelemetry’s default ID generator produces random IDs, so this is normally true. Problems appear when something else creates the IDs. A custom generator might include a counter or a timestamp. A different tracing system, an older one, or a gateway might create IDs with patterns. If the part of the ID that the sampler reads is not random, the share of traces kept can drift far from your ratio.

An example of the failure

Suppose a custom generator builds IDs whose last bytes come from a counter that increases by one per trace. Then the number read by the sampler also increases steadily. With a ratio of 0.1, the sampler’s threshold is fixed, so as the counter passes it, the sampler would keep nothing for a long time, or everything for a long time, depending on where the counter began. Your carefully chosen ratio would produce a very different outcome from the one you expected.

The standards are catching up

The W3C Trace Context standard recommends that trace IDs be random and, in its newer revisions, describes which part of the ID is guaranteed to be random so that samplers can rely on it. OpenTelemetry’s specification has also been evolving toward sampling methods that use an explicit random value carried in the trace state, so that the assumption does not depend on how the ID was made. Because these details are still moving, check your SDK’s current documentation for the status of the older TraceIdRatioBased and any newer probability-based samplers before you rely on fine points.

ID sourceSafe for ratio sampling?Why
OpenTelemetry default generatorYesRandom bits throughout
Custom generator using countersNoPatterns skew the share
IDs created upstream by another systemCheck firstDepends on how that system builds IDs
Timestamp prefix with random suffixUsually yes if the sampler reads the random partDepends on which bytes are read
Everyday Analogy

A raffle is fair only if tickets are shuffled. If the organizer hands out tickets in order, and the prize goes to the first quarter of the numbers, all winners will be the early arrivals. The rule is fine, and the shuffling was the missing step.

i
Tip

After deployment, compare the share of traces actually kept with the ratio you set. If you set 0.1 and keep 0.03 or 0.4, suspect the IDs, a mixed configuration, or another sampler in the path.

11Edge Cases: Ratios of Zero, One, and Nonsense

The ratio is a number between zero and one. What happens at the ends, and outside them, is worth knowing before an odd value reaches production.

Ratio valueMeaningTypical behavior
1.0 or higherKeep every traceBehaves like AlwaysOn
0.5Keep about halfHalf of IDs fall below the threshold
0.01Keep about one in a hundredCommon for very busy services
0.0 or lowerKeep nothingBehaves like AlwaysOff
Not a number or unreadable textA configuration mistakeSDK may fall back to a default or log a warning, and the behavior varies

What the values at the ends tell you

A ratio of one is a handy way to say “keep everything” while still using the same configuration style as other environments. A ratio of zero is a quiet way to turn off tracing for a service while keeping trace identifiers moving. With zero, the sampler says drop, so no data is kept, yet the context still travels so that downstream services can follow the flag.

Mistakes with percentages

A common mix-up is writing a percentage where a ratio is expected. A setting of 10 is read as ten, which is above one, and therefore means “keep everything”. A person who meant ten percent sees a flood of data and a large bill. Another version is writing 0.1 when the system expects a percentage, such as some Collector settings, which would mean a tenth of a percent. Always check the unit named in the setting.

Very small ratios

Ratios like 0.0001, which is one in ten thousand, are valid and are used for enormous systems. The sampler still needs a decent amount of traffic to behave predictably. At one hundred traces per day, a ratio of 0.0001 would keep a trace only about once every hundred days, which is probably not what anyone wants. Pick small ratios only when traffic is huge.

Everyday Analogy

A tap has “fully open”, “fully closed”, and many positions in between. A tap labeled in liters per minute should not be set using a number meant for percent open. The label on the dial matters as much as the dial.

!
Watch Out

Unit confusion is one of the most common sampling mistakes. Ratio means a fraction from zero to one, not a percentage from zero to one hundred. Read the setting’s description every time.

12Head Sampling and What It Cannot Know

TraceIdRatioBased is a head sampler. That label explains its biggest strength, which is cheapness, and its biggest weakness, which is blindness.

Head sampling means the decision is made at the head, or start, of the trace. At that moment the system knows almost nothing about what will happen. It does not know whether the request will be slow, whether it will fail, or whether the customer is important. TraceIdRatioBased uses only the ID, so it is blind to all of these, by design.

The strength: it is cheap and saves everything

Because the decision happens first, unsampled traces cost almost nothing. No data is collected, no memory is used, and nothing is sent. The savings extend through the whole pipeline. This is why head sampling is so popular for very large systems.

The weakness: it treats all traces alike

Suppose one request in a thousand fails with a rare, serious error. With a ratio of 0.1, only about one tenth of those failing traces is kept. Nine out of ten rare failures leave no trace at all. The sampler did not choose to ignore errors. It simply could not see them, because they had not happened yet at the moment of the decision.

flowchart LR
    START["Request begins"] --> HEAD{"Head sampler decides now"}
    HEAD -- "kept" --> RUN1["Request runs and is fully traced"]
    HEAD -- "dropped" --> RUN2["Request runs and is not traced"]
    RUN1 --> OUT1["Outcome is known only afterwards"]
    RUN2 --> OUT2["A failure here leaves no trace"]
Figure 4: The decision comes before the outcome, so a failing request may fall on the dropped side

Who should accept this trade

Head sampling by ratio suits teams that mainly want to understand normal behavior, spot broad trends, and keep costs predictable. If you must keep every error trace, or every very slow trace, you need a different tool, called tail sampling, which comes later in this guide. Many real systems combine both.

Everyday Analogy

A lighthouse keeper who decides at dusk to record only one in ten ships passing at random will miss many of the interesting events, like a ship in trouble. A keeper who waits and records after seeing which ship signals for help gets better data, at the cost of watching everything until then.

i
Good to Know

Blindness is not a flaw in the implementation. It follows from deciding early. Every head sampler shares it, from the simplest to the most elaborate.

13The ParentBased Wrapper: Following the Boss

In real systems, TraceIdRatioBased almost never works alone. It is placed inside a wrapper that respects decisions made earlier in the trace.

The ParentBased sampler asks a first question: does this span have a parent? If it does, the sampler copies the parent’s decision. If the parent was sampled, this span is sampled. If the parent was not, this span is not. Only when there is no parent, which means this is the root of a new trace, does it fall back to a different sampler, called the root sampler. You choose TraceIdRatioBased as that root sampler.

flowchart TB
    START["Span starts"] --> HASP{"Does it have a parent context?"}
    HASP -- "no, this is a root" --> ROOT["Use the root sampler: TraceIdRatioBased"]
    HASP -- "yes" --> REM{"Is the parent remote or local?"}
    REM -- "remote and sampled" --> RS["Sample"]
    REM -- "remote and not sampled" --> RN["Drop"]
    REM -- "local and sampled" --> LS["Sample"]
    REM -- "local and not sampled" --> LN["Drop"]
Figure 5: ParentBased copies the parent’s decision and uses the ratio sampler only for new roots

Why this wrapper matters

Without it, every service in a chain applies its own ratio rule to every span, even when an earlier service already made a decision. With it, the decision is made once, at the root, and every later span simply follows. The trace is either kept whole or dropped whole. This fits the most important goal of sampling, which is to keep complete stories.

The default behavior of the wrapper

The wrapper has separate settings for four cases: remote parent sampled, remote parent not sampled, local parent sampled, and local parent not sampled. A remote parent is a span in another service, and a local parent is a span in the same program. The usual defaults are to follow the parent in all four cases, which is what you want almost always.

Everyday Analogy

In a company, the first manager decides whether a project is a priority. Everyone who works on that project afterwards follows the decision without holding their own vote. A fresh project from nowhere is decided by the usual rule, which is the ratio.

i
Tip

If you remember one configuration sentence from this guide, make it this one: parent-based, with TraceIdRatioBased as the root sampler.

14Reading the Decision Table

A table makes the four parent cases and the root case easy to see together. Keep it handy when debugging odd results.

SituationParentBased with ratio root does thisWhy
No parent, the request just arrived with no trace contextAsk TraceIdRatioBasedThis is a new root, so the ratio rule applies
Remote parent, sampled flag onSampleAn upstream service already decided to keep the trace
Remote parent, sampled flag offDropAn upstream service decided to drop the trace
Local parent, sampledSampleChild spans follow the parent span in the same program
Local parent, not sampledDropChild spans follow the parent span in the same program

An example with three services

Take a request that goes from a gateway to an orders service, and then to a payments service. All three use ParentBased with a root ratio of 0.1. The gateway receives a request with no trace context. It is a root, so the ratio rule applies. Suppose the ID falls below the threshold. The gateway samples the trace and sends the flag on. The orders service sees a remote parent with the flag on, so it samples. Payments does the same. The trace is whole.

In another request, the ID falls above the threshold. The gateway drops the trace and sends the flag as off. The other two services see the flag off and drop their spans. Nobody wastes effort, and no half-trace appears.

A request that arrives with context already attached

Now imagine that the gateway receives a request from a mobile application that already carries a trace context with the flag on. The gateway is no longer a root. It has a remote parent that is sampled, so it samples, regardless of its own ratio. This is a feature when the caller is trusted, and a risk when it is not, as the security chapter explains.

Everyday Analogy

A relay team where only the first runner draws a lot to see whether the race is filmed. After that, everyone looks at the flag on the baton. A runner who joins mid-race with a flagged baton obeys the flag, whether or not they would have drawn the same lot.

i
Good to Know

With this arrangement, the effective sampling rate of the whole system is the ratio at the roots. Ratios configured on non-root services do not matter for traces that arrive with a parent.

15Turning It On: Configuration Without Code

You usually choose the sampler through settings rather than by writing logic. Knowing the names saves guessing.

The environment variables

OpenTelemetry defines two standard environment variables for samplers. One, named OTEL_TRACES_SAMPLER, picks the sampler by a name. The other, named OTEL_TRACES_SAMPLER_ARG, gives it an argument such as the ratio. The names that matter here are shown below.

Sampler name settingMeaningArgument
always_onKeep every traceNone
always_offKeep nothingNone
traceidratioTraceIdRatioBased aloneThe ratio, such as 0.1
parentbased_always_onFollow the parent, keep rootsNone
parentbased_always_offFollow the parent, drop rootsNone
parentbased_traceidratioFollow the parent, ratio for rootsThe ratio, such as 0.1

The setting you probably want

For most services, the right choice is the parent-based version of the ratio sampler, with the ratio as the argument. This matches the wrapper pattern from the previous chapters. The default when you set nothing is generally the parent-based always-on arrangement, which keeps everything that starts here and follows what arrives. That surprises people who expected sampling to be off by default, and who later discover large volumes.

Setting it in code instead

All SDKs let you choose a sampler when creating the tracer provider, using the same building blocks: a ratio sampler wrapped by a parent-based sampler. Code settings are useful when the choice depends on the environment or on logic. Settings from environment variables are easier for operations teams, since they change without a rebuild. If both exist, check your SDK’s rule for which wins.

Everyday Analogy

A thermostat can be set with a dial on the wall, or by an app. The dial is the quick switch for anyone in the house, and the app is for programmed schedules. Both control the same heating, and you should know which one the system trusts more.

!
Watch Out

Names and handling of these settings can differ slightly between languages and agents, and a typo may silently fall back to a default. After changing the sampler, confirm the effective setting by checking startup logs or the sampler’s description string.

16Choosing a Ratio: The Cost Arithmetic

The ratio is a business decision wearing a technical coat. A few simple multiplications turn it into something you can argue about.

The volume formula

The number of spans you keep per second is the number of requests per second, times the average spans per trace, times the ratio. For example, one thousand requests per second, with twenty spans per trace, at a ratio of 0.05, keeps one thousand times twenty times 0.05, which is one thousand spans per second. At a ratio of one, you would keep twenty thousand. The ratio scales cost directly.

Cost drivers to multiply by

Storage

Bytes per span

Multiply kept spans by their average size and by the number of days you retain them.

Ingest

Vendor charges

Many backends charge by volume ingested or by spans per month. Sampling reduces this at once.

Network

Data transfer

Sending spans across zones or out of a cloud costs money and bandwidth.

Compute

Processing in services

Dropped spans cost almost nothing in the application and exporters.

How to pick

Begin with a budget. If you can afford to store five hundred spans per second, and your traffic would produce twenty thousand, the ratio is five hundred divided by twenty thousand, which is 0.025. Then ask whether 0.025 gives you enough examples to answer your questions. If you rarely need individual traces and mostly want trends, a very low ratio is fine. If your engineers hunt individual bugs every day, you may need a higher ratio, or a smarter strategy such as tail sampling for errors.

The right ratio is the lowest one that still lets your engineers answer the questions they actually ask.
Everyday Analogy

A household sets a food budget first and then decides how many restaurant meals fit in it. The ratio is the number of restaurant meals, and the budget is the cost limit. Few people start by deciding how many meals they want regardless of cost.

i
Tip

Revisit the ratio when traffic changes. A ratio that was fine at one thousand requests per second may be wasteful at ten thousand, because cost scales with traffic while the usefulness of extra similar traces does not.

17A Worked Example With Made-Up Numbers

The following story is invented to show the arithmetic from start to finish. The company and figures are not real.

The made-up company: “Marigold Tickets”

Marigold Tickets sells event tickets. At peak, its services handle 2,000 requests per second. An average trace has 25 spans. The tracing vendor charges by ingested volume, and the team can afford about 1,000 spans per second at peak.

Step 1: the full volume

At full capture, the volume is 2,000 requests times 25 spans, which is 50,000 spans per second at peak. That is fifty times the budget.

Step 2: the ratio

To fit within 1,000 spans per second, the team needs a ratio of 1,000 divided by 50,000, which is 0.02. They configure parent-based with a root ratio of 0.02 on the entry services.

Step 3: what they get

Out of 2,000 requests per second, about 40 traces are kept each second at peak. Over an hour of peak traffic, that is about 144,000 traces, which is plenty to study normal behavior, to compare versions, and to find slow endpoints. At night, with 100 requests per second, the same ratio keeps only about 2 traces per second, still adequate for trends.

Step 4: what they lose

A rare error happens about 30 times per hour. At a ratio of 0.02, the team expects to keep 0.6 of those traces per hour, which means a typical hour holds no trace of the error at all. This is the head-sampling gap. The team decides to add tail sampling for errors in a Collector, as a second layer, and keeps the 0.02 ratio for ordinary traffic.

Measure (made-up)No samplingRatio 0.02
Spans per second at peak50,000About 1,000
Traces kept per second at peak2,000About 40
Rare errors kept per hour (30 occur)30About 0.6 on average
Cost relative to full capture100 percentAbout 2 percent
i
Good to Know

This pattern, a low ratio for everything plus a separate path to keep errors, is common. The ratio sampler handles the bulk cheaply, and a smarter component keeps the special cases.

18The Math of Rare Events and Precision

Sampling is a game of chance, and a little probability tells you what to expect. No advanced mathematics is needed.

Will I see at least one example?

If each trace is kept with probability p, the chance that a particular trace is not kept is one minus p. If an event happens n times, the chance that none of its traces is kept is that value multiplied by itself n times. The chance that at least one is kept is one minus that.

RatioEvent occurrencesChance of keeping at least one trace
0.0150About 40 percent
0.01100About 63 percent
0.01300About 95 percent
0.130About 96 percent
0.110About 65 percent

The lesson is that low ratios are good at showing common patterns and poor at showing rare ones. If a problem happens only a few dozen times per day, a one percent ratio may well miss it entirely.

How close is the kept share to the ratio?

Because the process is random-like, the actual share fluctuates slightly. For one million traces at a ratio of 0.1, you expect about 100,000 kept. The typical wobble, called a standard deviation, is about 300, which is only 0.3 percent of the expected number. So with large traffic, the share is very close to the ratio. With small traffic, such as one thousand traces, the wobble is about ten out of a hundred expected, which is ten percent, a much bigger relative swing. Do not be alarmed by noisy numbers on small volumes.

Everyday Analogy

Flip a fair coin one thousand times and you will see close to five hundred heads, though rarely exactly. Flip it ten times and you might see seven heads and think the coin is unfair. More flips make the result settle closer to the true share.

i
Tip

Before judging whether the sampler “works”, look at several thousand traces. Small samples mislead, and so do per-minute counts on a quiet service.

19Different Ratios in Different Services

Real organizations rarely have one tidy setting everywhere. What happens when two services in the same trace use different ratios?

With the parent-based wrapper

If every service uses the parent-based wrapper, only the root’s ratio matters for traces that begin at that root. Services deeper in the chain follow the flag, so their own ratios are used only when they happen to start a new trace themselves, such as when a background job begins with no parent. This is clean and predictable, and it is the recommended arrangement.

Without the wrapper

If services use a bare ratio sampler, each applies its own ratio to the same trace ID. A service with ratio 0.5 and another with 0.1 will often disagree. Because the rule is “keep if the ID is below the threshold”, and a lower ratio means a lower threshold, the 0.1 service keeps only traces that the 0.5 service also keeps, assuming both read the ID in the same way. So the traces from the 0.1 service form a subset of the other’s. In traces kept by the 0.5 service but not the 0.1 service, you will see spans from the first and a hole where the second should appear.

flowchart LR
    subgraph REQ["One request with trace ID X"]
      A["Service A ratio 0.5"] --> B["Service B ratio 0.1"]
    end
    A --> DA{"ID below 0.5 threshold?"}
    B --> DB{"ID below 0.1 threshold?"}
    DA -- "yes" --> KA["A spans kept"]
    DB -- "no" --> DR["B spans dropped, hole in trace"]
Figure 6: A trace kept by the 0.5 service can have a hole where the 0.1 service dropped its part

When differences are intentional

Sometimes you want a downstream service to keep more of its own traces, for example a service under investigation. The parent-based wrapper blocks this when traces arrive from upstream, because the flag wins. If you really need a different rate in the middle, consider a separate, deliberate mechanism, such as a custom sampler or a Collector rule, and accept the possible partial traces knowingly.

Everyday Analogy

Two photographers cover the same parade. One photographs every second float, and the other photographs every tenth float, using the same float numbers. The second photographer’s pictures are all among the first photographer’s choices, but most of the first photographer’s pictures have no partner. Two albums, with different coverage, do not combine into a full story.

!
Watch Out

The subset behavior described here depends on both services reading the trace ID in the same way. Do not depend on it across different languages or versions without testing.

20Partial Traces: The Broken Story Problem

The worst outcome of bad sampling is not less data. It is data that misleads. Partial traces are the main example.

A partial trace is a trace missing some of its spans. In a trace viewer, you see a child span whose parent never arrived, or a gap where a service should appear. The viewer may draw the tree with a broken top, or may label missing parents as unknown. A reader might wrongly conclude that a service was never called, or that time vanished between two steps.

Common causes

Cause

Bare ratio samplers with different ratios

Services disagree and keep different pieces of the same trace.

Cause

A service that ignores the flag

An old library or custom code that does not read the incoming context starts a new trace, breaking the chain.

Cause

Lost context in queues or threads

The sampled flag is not carried through a message queue or a background thread, so the next step makes its own decision.

Cause

Drops later in the pipeline

A full processor queue, a Collector refusal, or a backend limit drops some spans after sampling said yes.

Why partial traces are worse than none

Missing traces simply mean less data, and you know to be careful. A partial trace appears legitimate and may be used for a conclusion. An engineer might blame a service for a delay that actually happened in an unseen service. Backends try to cope by showing placeholders or waiting for late spans, but they cannot invent what was never sent.

The cure

Use the parent-based wrapper everywhere, make sure context travels through every hop including queues, keep all services on the same sampling plan, and watch for drops downstream of the sampler. The next chapter explains the context part in more detail.

Everyday Analogy

A jigsaw puzzle with a few missing pieces is still obviously a puzzle. A photograph with a patch cut out and replaced by a different picture is far more confusing, because it looks complete. Partial traces are the second kind.

i
Tip

Make a habit of looking at a handful of traces from every new service you onboard. A quick look tells you whether the story is whole before you trust the dashboards built on top.

21Context Propagation: How the Decision Travels

The decision made at the root reaches the other services through a small piece of text attached to each call. Following it once makes the whole system clear.

sequenceDiagram
    participant U as User
    participant G as Gateway
    participant O as Orders service
    participant P as Payments service
    U->>G: Request with no trace context
    Note over G: New root, TraceIdRatioBased decides
    G->>O: Call with traceparent flag sampled
    Note over O: Remote parent sampled, so sample
    O->>P: Call with traceparent flag sampled
    Note over P: Remote parent sampled, so sample
    P-->>O: Response
    O-->>G: Response
    G-->>U: Response
Figure 7: The gateway decides once, and the flag in the traceparent header carries the decision to every service

What is inside the header

In the common W3C Trace Context format, the header named traceparent has four parts separated by dashes: a version, the trace ID, the ID of the calling span, and a set of flags. The last bit of the flags is the sampled flag. When a service makes a call, its OpenTelemetry instrumentation fills in this header automatically. When a service receives a call, the instrumentation reads it and passes the information to the sampler as the parent context.

Where propagation breaks

Propagation can fail in several ordinary ways. A proxy might strip unknown headers. A message queue might not carry headers unless the instrumentation copies the context into the message properties. A background job might start in a new thread without the context. A service using a different propagation format, such as an older one, might not understand the header. Each failure makes the next service see “no parent” and behave as a new root, which then uses the ratio, producing a new trace or a disconnected fragment.

Unsampled traces still carry their ID

Even when a trace is dropped, its context still travels so that downstream services can respect the decision. The flag says “not sampled”, the ID is still present, and the downstream spans are created in a lightweight form. This is why dropped traces still cost a little: a header on every call and a tiny object per span.

Everyday Analogy

A parcel carries a label through many hands, and each handler reads the label to know what to do. If someone repackages the parcel and loses the label, the next handler has no instruction and treats it as new. The label is only useful if it stays attached through every hand-off.

i
Tip

List every hop in your system, including proxies, queues, schedulers, and batch jobs, and check that each one passes the context along. Gaps in this list explain most unexplained partial traces.

22Metrics and Sampling: Keeping Your Counts Honest

Sampling affects any number you compute from traces. If you forget this, your charts will quietly understate reality.

Suppose you derive a chart of requests per second from the stored spans. If only two percent of traces are kept, the chart shows two percent of the real traffic. A dashboard that says “40 requests per second” when the true figure is 2,000 will mislead anyone who forgets about sampling. Latency percentiles computed from a sample are less affected, if the sample is fair, but rare slow requests are underrepresented, and the high percentiles are noisier.

Three ways to keep numbers honest

1

Measure with real metrics, not traces

Use OpenTelemetry metrics, such as a counter of requests and a histogram of durations, recorded in your code for every request. Metrics are cheap and are not sampled, so they show full volume and accurate percentiles.

2

Compute span metrics before sampling

A Collector component can turn spans into request, error, and duration metrics before a sampler drops any. Since it sees all spans, the numbers are complete, and only the stored trace examples are sampled.

3

Scale by the sampling rate

If you must count from sampled spans, multiply by the inverse of the ratio. A count of 400 at a ratio of 0.02 estimates 20,000 real events. This works only when the ratio is known and constant.

Advanced approach: carry the probability

More recent OpenTelemetry designs record the sampling probability in the trace state of each sampled span, so a backend can correct its counts per span even when ratios differ across services or change over time. These designs are still maturing, so treat this as a direction rather than a given, and check the current status in your tools.

Everyday Analogy

A pollster who surveys one household in fifty and reports the number of households that said yes must multiply by fifty to estimate the whole country. A pollster who forgets to do so announces that only a tiny number of households exist.

!
Watch Out

Do not alert on request counts or error counts derived from sampled traces. The alert will fire or stay silent for reasons that depend on your sampling ratio, not on your system. Use unsampled metrics for alerts.

23Logs and Sampling: Links to Traces That Do Not Exist

Logs and traces are often linked by the trace ID. Sampling can break that link in a way that surprises people.

OpenTelemetry log records can carry the trace ID and span ID of the span that was active when the log was written. This lets a viewer jump from a log line to its trace. But if the trace was not sampled, the trace does not exist in the backend. The log line still holds the ID, the link is still shown, and clicking it finds nothing.

How teams handle this

  • Log the sampled flag too. Many setups include the trace flags in the log record, so a viewer can show the link only for sampled traces, and avoid dead links.
  • Accept the dead link. For many teams, a link that sometimes leads nowhere is a small price and is explained in a short note in the log viewer.
  • Choose logs differently. Some teams keep every log line but sample traces, since logs for errors are valuable on their own. They set logging levels so the key lines are always kept.
  • Make interesting traces sticky. A tail-sampling component keeps all error traces, so error logs usually have a working trace link.

A note about sampled logs

The sampler described here decides about traces, not logs. Logs are not dropped by TraceIdRatioBased. If you need to reduce log volume, use other means, such as log levels, filters, or a Collector processor. Mixing up the two leads to surprise on both sides: traces missing when logs exist, and logs flowing when traces were reduced.

Everyday Analogy

A diary entry says “see photo 4812”, but only one in ten photos was developed. The reference is correct, but the photo is not on the shelf. The diary is complete, the album is thinner, and a note saying “photo not developed” would spare readers a fruitless search.

i
Good to Know

Sampling choices ripple outward to every tool that shows traces. When you change a ratio, tell the people who use the log viewer and dashboards, so they are not surprised by missing links.

24Sampler Versus Span Processor: Two Different Jobs

Newcomers often confuse the sampler with the span processor, since both sit in the same pipeline and both affect how much data leaves your program.

QuestionSamplerSpan processor
When does it act?When a span startsWhen a span starts or ends
What does it decide?Whether the trace is recorded at allWhen recorded spans are handed to the exporter
Can it remove data?Yes, by dropping whole tracesNo for the standard ones, they only batch and forward
Example choicesAlwaysOn, TraceIdRatioBased, ParentBasedSimple, Batch
Effect on costCuts volume in every later stepControls delay, queueing, and network efficiency

They work together

Sampling reduces how many spans reach the processor. The Batch processor then packs those spans efficiently. If you sample too little and send too much, the processor’s queue fills and begins to drop spans in an uncontrolled way, which is the worst kind of sampling, because it ignores the trace structure and can produce partial traces. A good setup uses the sampler to cut volume on purpose, so the processor and exporter never have to drop anything by accident.

Why order matters

Sampling must come first. If you let everything through and then drop spans at the processor, you pay the cost of creating them, and you lose the property of keeping or dropping whole traces. Deliberate trace-level sampling is both cheaper and cleaner than accidental span-level dropping.

Everyday Analogy

A factory chooses which items to produce, which is the sampler, and a shipping crew decides how to pack and send what was made, which is the processor. Making too many items and hoping the shipping crew throws away the extras wastes materials and delivers broken sets.

i
Tip

If you ever see the processor dropping spans, ask first whether the sampler could have removed them earlier. A lower root ratio is often the cleanest fix.

25Sampling in the Collector: A Second Place to Decide

Sampling does not have to happen inside your application. The OpenTelemetry Collector can sample too, and the two places complement each other.

The Collector is a separate program that receives telemetry, changes it, and forwards it. It has a component often called the probabilistic sampler processor, which keeps a configured percentage of traces based on a hash of the trace ID. It follows the same idea as TraceIdRatioBased: a deterministic function of the ID, so the same trace gets the same decision. It has its own settings, such as a percentage rather than a ratio, and an optional seed for the hash. Settings and names have changed across releases, so read the documentation of the version you run.

Why sample in the Collector

Benefits of the Collector

  • One central place to change the rate without redeploying applications
  • Works for services in any language, including ones with weak SDK support
  • Saves backend cost and storage
  • Can combine with other rules, such as tail sampling

Limits compared with the SDK

  • Spans have already been created, processed, and sent over the network
  • Application and network costs are not reduced
  • Needs capacity in the Collector to receive everything first
  • Hash behavior may not match the SDK’s, so mixing both can confuse rates

Choosing between them

Sampling in the SDK saves effort at the source and is the best way to cut application and network costs. Sampling in the Collector gives central control and saves backend costs. Many organizations do the broad cut in the SDK with a modest ratio and then apply targeted rules in the Collector. If you use both for the same purpose, remember that the rates multiply. An SDK ratio of 0.5 followed by a Collector percentage of 20 keeps about ten percent of traces, not twenty.

flowchart LR
    APP["Application SDK with ParentBased and TraceIdRatioBased"] --> COL["Collector"]
    COL --> PS["Probabilistic or tail sampling processor"]
    PS --> BE["Backend"]
    APP -. "dropped here costs nothing downstream" .-> X["Unsampled spans"]
    PS -. "dropped here still cost application and network" .-> Y["Unkept spans"]
Figure 8: Sampling in the SDK saves the most. Sampling in the Collector saves backend cost and allows central control
Everyday Analogy

A newspaper can decide which stories to write, which is SDK sampling, or decide in the editor’s office which written stories to print, which is Collector sampling. The first saves reporters’ time. The second keeps control in one place. Many papers do both.

!
Watch Out

Remember that rates multiply when you sample in two places. Write down the overall rate you expect, and check it against measured numbers.

26Tail Sampling: Deciding After the Story Ends

If TraceIdRatioBased is blind to outcomes, tail sampling is the opposite. It waits until it has seen the whole trace and then decides.

A tail sampler holds the spans of each trace in memory for a short time, usually inside a Collector, until it believes the trace is complete. Then it applies rules: keep every trace containing an error, keep every trace slower than a limit, keep traces from a certain customer, and keep a small ratio of everything else. This lets you keep nearly all of the interesting traces while discarding most of the boring ones.

flowchart TB
    IN["Spans arrive from many services"] --> BUF["Buffer spans by trace ID"]
    BUF --> WAIT["Wait for the decision time"]
    WAIT --> RULES{"Apply rules to the whole trace"}
    RULES -- "has an error" --> KEEP["Keep"]
    RULES -- "slower than limit" --> KEEP
    RULES -- "none of the above" --> RATIO{"Random share"}
    RATIO -- "chosen" --> KEEP
    RATIO -- "not chosen" --> DROP["Drop"]
Figure 9: A tail sampler buffers whole traces and applies rules before keeping or dropping them

The price of seeing the whole story

Advantages

  • Keeps nearly all error and slow traces
  • Can use any property of the finished trace
  • Reduces volume while preserving the interesting parts

Costs

  • Needs memory to hold traces while waiting
  • All spans of a trace must reach the same Collector, which complicates scaling
  • Adds delay before traces become visible
  • A wrong wait time may cut traces short and make wrong decisions

The scaling difficulty

Because the sampler needs every span of a trace in one place, a group of Collectors must route spans by trace ID, so that all spans of one trace go to the same instance. This is often done with a first layer of Collectors that forwards by trace ID to a second layer that does the tail sampling. It works, but it is more to build, run, and watch than a ratio in an SDK.

Why TraceIdRatioBased still has a place

Tail sampling cannot reduce the cost of creating and sending spans, since all of them must reach the Collector first. Head sampling with a ratio reduces that cost at the source. This is why many large systems pair a modest head ratio, to tame volume, with a tail sampler, to rescue the interesting traces from what remains. The next chapter explains this combination and its catch.

Everyday Analogy

Tail sampling is like a film editor who watches all the raw footage and keeps the best scenes. The result is excellent, and it needs a big room, many hours, and every reel in one place. Head sampling is like the director deciding in advance to film only some scenes, which is cheaper and may miss the best moment.

i
Good to Know

The details of tail sampling components, such as available rules and configuration names, evolve with each release. Check the current documentation before relying on a specific feature.

27Combining Head and Tail Sampling Wisely

The two styles can work as a team, but only if you understand how they interact. Otherwise one quietly cancels the other.

The catch

If the SDK uses a ratio of 0.1, then ninety percent of traces are dropped at the source. They never reach the Collector, so the tail sampler cannot rescue an error trace among them. The tail sampler can only choose among the traces it receives. Therefore, the overall chance of keeping an error trace is at most the head ratio, however clever the tail rules are.

Three common arrangements

ArrangementHow it worksGood forMain drawback
Head ratio onlySDK keeps a fixed fractionSimple cost control, trend analysisMisses most rare errors
Tail sampling onlySDK keeps everything and the Collector decidesMaximum insight into errors and slow tracesHigh network and Collector cost
Head ratio high, then tailSDK keeps a large share such as half and the Collector narrows downBalance of cost and error coverageStill some loss, and extra components to run
Always-on for important flows, ratio for the restA custom sampler or separate rules choose by route or customerProtecting critical pathsMore configuration to maintain

Making the arrangement explicit

Write down, in plain words, the overall plan: what share of ordinary traces you keep, what you do to keep errors, and where each step runs. Include the multiplication of rates. A plan that lives only in people’s heads will drift when someone changes one piece without knowing the others.

Everyday Analogy

If a first clerk throws away nine of every ten applications before a second clerk reads them, the second clerk cannot save a good application from the discarded pile, no matter how sharp their eyes. The first clerk’s rule sets the ceiling.

i
Tip

If error coverage is important, make the head ratio high enough, or exempt critical routes from ratio sampling, before building tail sampling. Otherwise the investment is limited by the earlier step.

28Beyond a Flat Ratio: Custom and Rate-Based Ideas

A single ratio treats every trace alike and scales with traffic. Sometimes you want something a little smarter.

Different ratios for different routes

A health-check endpoint called every second adds no insight and creates huge volume. A checkout endpoint is precious. A custom sampler can look at the span name or attributes known at start, such as the route, and apply different ratios: very low for health checks, high for checkout, and moderate for the rest. Since the sampler sees attributes only at the start, it can use only information that exists then, such as the route and the method, not the result.

Rate limiting instead of ratios

A ratio keeps cost proportional to traffic. During a traffic spike, your cost rises with it. A rate-limiting sampler instead keeps at most a fixed number of traces per second, so cost stays flat. It needs state, namely a counter or a token bucket, so it is not deterministic by ID and does not agree across services without extra coordination. Some tracing systems offer remote-controlled sampling, where a central service tells each application what rates to use. The built-in OpenTelemetry list is shorter, and these ideas typically come from extensions or vendors, so check what your tools provide.

Choosing what to build

Do not build a custom sampler because it sounds powerful. Start with a parent-based ratio and see whether it meets the need. Many problems that look like they need a custom sampler are better solved by excluding noisy endpoints from instrumentation, or by sending errors through a tail sampler.

Idea

Route-based ratios

Low for noisy endpoints, high for critical ones. Uses only start-time facts.

Idea

Rate limiting

Fixed traces per second regardless of traffic. Needs state and is not ID-deterministic.

Idea

Remote-controlled rates

A central service changes rates without redeploying. Offered by some systems and vendors.

Idea

Debug override

Force sampling for a request marked as a debug request, with safeguards against abuse.

Everyday Analogy

A museum might photograph every visitor to the special exhibit, one in twenty visitors to the gift shop, and none in the corridor. Different places deserve different attention, and a single rule across the whole building would be wasteful or blind.

!
Watch Out

Any custom sampler runs on every span start, in the hot path of your application. Keep it fast, and keep it free of network calls and blocking work.

29Security and Privacy Considerations

Sampling looks like a cost tool, but it touches security in three ways: who can force sampling, what is kept, and what the sampled data reveals.

Outsiders forcing your decision

With the parent-based wrapper, a service obeys the sampled flag of an incoming request. If your public gateway accepts a trace context from the internet, any caller can set the flag to “sampled” on every request. A malicious or buggy client could then force you to keep all of its traffic, raising your volume and cost, and could even attempt to flood the system. Callers can also pick trace IDs they choose, which is why ID-based rules should not be treated as a secret or a protection.

Defenses at the edge

  • Ignore or reset untrusted context. At the public edge, start a fresh trace and do not accept the caller’s flag, or accept it only from known, trusted callers.
  • Use different settings for edge and internal services. The parent-based wrapper can be set to ignore remote parents at the edge.
  • Limit volume. A rate limit or a Collector-level cap protects the backend from a flood of forced samples.

What sampled data reveals

A sampled trace can contain sensitive information in its attributes, such as user identifiers, query text, or addresses. Sampling reduces how much of this is stored but does not remove it from the traces that remain. Keep sensitive values out of spans, and mask them in a processor or Collector, regardless of the ratio.

Sampling is not anonymization

Some people think that keeping a small share of traces makes the data safe. It does not. One sampled trace can still expose one customer’s details. Apply the same access control to sampled data as to any other telemetry.

Everyday Analogy

A hotel’s front desk decides which visitors to log. If any visitor could simply announce “log me”, the logbook would fill with strangers’ names. The desk should accept such requests only from people it trusts, and it should never write passwords in the book at all.

i
Tip

Review the entry points to your system and decide, one by one, whether each should honor an incoming sampling flag. This is a short review that prevents a long bill.

30Monitoring the Sampler Itself

A sampler works silently. To trust it, you need a few numbers that tell you it is doing what you intended.

Check

Observed share

Divide kept traces by total requests, using unsampled request metrics. The result should be close to the ratio at the roots.

Check

Spans per trace

A sudden drop suggests partial traces. A rise suggests a change in the code or an unexpected extra instrumentation.

Check

Orphan spans

Spans whose parent never arrived. Rising orphans point to propagation failures or downstream drops.

Check

Pipeline drops

Processor queue drops, Collector refusals, and backend limits. They remove data that sampling said to keep.

Where to get the data

Request counts come from regular metrics, not from traces. Kept traces come from the backend or from Collector metrics that count spans received and exported. Orphan counts are sometimes shown by the backend. If not, sample some traces by hand each week. Drops come from the SDK’s diagnostic output where available, and from Collector metrics about refused data.

Alerting suggestions

Alert if the observed share drifts far from the ratio for a long time, since it suggests a broken ID source, a mixed configuration, or a change in another sampler. Alert if pipeline drops continue for several minutes. Do not alert on small differences in short windows, since randomness alone causes them, as the earlier math showed.

Everyday Analogy

A pollster checks that the survey group matches the real population, in age and region, before trusting the findings. If the group is lopsided, the numbers are wrong even if every individual answer was honest. Watching the observed share is the same check.

i
Good to Know

A quick sanity check after any change is to look at one hour of data and confirm that the observed share is within a reasonable distance of the ratio. If it is, the plan is probably working.

31What Goes Wrong: Failure Scenarios

Understanding the common ways a sampling setup fails helps you spot them early.

FailureWhat you observeLikely cause
Far too much dataHigh bills, huge volumeDefault parent-based always-on, ratio setting ignored or mistyped, ratio above one
No data at allEmpty trace searchRatio zero, always-off set, or a parent upstream says not sampled
Skewed shareKept share far from ratioNon-random trace IDs, or other sampling downstream
Partial tracesGaps and orphan spansBare ratio samplers, lost context, drops after sampling
Missed rare errorsIncidents with no tracesLow ratio, no tail sampling
Different environments disagreeStaging shows everything, production shows littleDifferent configuration in each environment
Forced oversamplingSudden spike with one sourceEdge honors a caller’s sampled flag

The quiet failures are the worst

Almost none of these produce an error message. The system continues to run, the dashboards continue to draw, and the only sign is that the data is not what you assumed. This is why the monitoring ideas of the previous chapter matter. A short weekly check of the observed share and a quick look at a few traces catch most of these problems early.

Everyday Analogy

A bathroom scale that is slightly off does not beep or flash. It keeps showing a number, and you trust it. You find out only when you compare it with another scale. Sampling setups need a second scale in the form of independent request metrics.

!
Watch Out

Never assume that a sampling change took effect everywhere just because one service shows the new behavior. Confirm per service and per environment.

32Good Patterns

These patterns are the repeated habits of teams that run sampling calmly.

Pattern

Parent-based with a ratio root

Decide once at the root, and let everyone follow the flag. Keeps traces whole.

Pattern

One written sampling plan

A short page that states the ratio, where it applies, any Collector rules, and who owns the plan.

Pattern

Unsampled metrics for numbers

Counts, error rates, and percentiles come from real metrics, never from sampled traces.

Pattern

Error rescue

A tail sampler or a higher ratio on critical routes keeps the traces that matter most.

Pattern

Trusted edge

The public edge starts fresh traces and does not blindly honor incoming flags.

Pattern

Environment-driven settings

Development keeps everything. Staging keeps much. Production keeps a measured share.

Why the written plan matters

Sampling decisions are easy to make and easy to forget. A new engineer sees a ratio of 0.02 in a configuration file and has no idea why. A one-page plan explains that 0.02 came from a budget of one thousand spans per second at peak, and that error traces are rescued by a Collector rule. This turns a mystery number into a decision that can be reviewed when conditions change.

Everyday Analogy

A kitchen with labeled shelves, written recipes, and a clear closing checklist runs smoothly even when staff change. These patterns are the labels and recipes of sampling.

i
Tip

Put the written plan next to the configuration in version control, so that changes to one prompt a glance at the other.

33Anti-patterns

Each of these looks reasonable at first and causes pain later.

AP-1Avoid

Bare ratio sampler in every service. Different services decide independently, and any mismatch yields partial traces.

AP-2Avoid

Counting from sampled traces. Dashboards of request volume and error rate built on stored traces understate reality and change with the ratio.

AP-3Avoid

Expecting ratio sampling to catch errors. It is blind to outcomes. A rare error will usually be missed at a low ratio.

AP-4Avoid

Sampling twice without a plan. An SDK ratio and a Collector percentage multiply, and nobody remembers the final rate.

AP-5Avoid

Honoring every caller’s sampled flag. Outsiders can inflate your volume and cost.

AP-6Avoid

Using a percentage where a ratio is expected. A value of 10 is above one and keeps everything, causing a surprising bill.

AP-7Avoid

Non-random trace IDs with ratio sampling. Patterns in IDs skew the kept share far from the ratio.

Everyday Analogy

Anti-patterns are shortcuts that skip one safety step, like crossing a road without looking. Most days nothing happens, and one day the cost is large.

34Best Practices and Common Mistakes

This is the checklist to keep near your configuration files.

Best practices

  • Use the parent-based wrapper with TraceIdRatioBased as the root sampler in services that are called by others.
  • Choose the ratio from a budget, using the volume formula, and write the reasoning down.
  • Use unsampled metrics for counts, rates, and alerts.
  • Make sure context passes through every hop, including proxies, queues, and background jobs.
  • Keep services on the same SDK family and the same ID generation where possible, and test mixed environments.
  • Rescue errors with a tail sampler or a higher ratio on critical routes if rare failures matter.
  • Control the sampled flag at the public edge.
  • Monitor the observed share and pipeline drops.
  • Revisit the ratio when traffic or budget changes.

Common mistakes and their cures

MistakeSymptomCure
Forgetting the default keeps everythingHigh volume right after rolloutSet the sampler explicitly in every environment
Mixing percent and ratioFar more or far fewer traces than expectedCheck the unit in the setting description
Different ratios on non-root servicesConfusion about the true rateUse parent-based and rely on the root ratio
No propagation through queuesDisconnected traces for asynchronous workCopy the context into message properties
Alerting on sampled countsFalse alarms or silenceAlert on unsampled metrics
Judging the ratio from a small sampleWrong conclusion about fairnessLook at thousands of traces
Everyday Analogy

Pilots read checklists not because they forget how to fly, but because skilled people also skip steps under pressure. A sampling checklist protects against small oversights in the same way.

i
Tip

Change one sampling setting at a time and watch the observed share before and after. Several changes at once make it impossible to tell which one did what.

35Real-World Style Examples

These stories are invented to illustrate common situations. They are not reports about real companies.

Example one: the bill that doubled

A small team adds OpenTelemetry to ten services and never sets a sampler. The default keeps every trace that starts in a service. Within two weeks, their tracing bill is more than double their forecast. They set parent-based with a root ratio of 0.05, and the bill falls to a twentieth. They learn that “no sampler configured” does not mean “no data kept”.

Example two: the holes in the traces

A company sets a ratio of 0.2 in a gateway and 0.1 in a billing service, both using bare ratio samplers. Engineers notice that many traces have a billing service span missing. The gateway keeps one in five and billing keeps one in ten, and billing’s kept traces are a subset of the gateway’s. They switch both to parent-based, and the holes disappear.

Example three: the missing incident

A service with a ratio of 0.01 has a rare bug that fails about forty requests per day. During an incident review, the team finds that none of the failing requests has a trace. The math shows they expected to keep less than half of one failing trace per day. They add a tail sampler in the Collector, with a rule to keep all error traces, and raise the head ratio for the checkout routes.

Example four: the public flood

A public gateway honors incoming trace context. A partner’s integration sends every request with the sampled flag on, around 400 requests per second. The team’s trace volume jumps by thirty percent overnight. They configure the gateway to ignore remote parents from the public network and to start its own traces with the normal ratio. Volume returns to normal.

Everyday Analogy

Each story is like a lesson from a driving instructor: one rule, one mistake, one fix. The same few lessons repeat across many drivers and many roads.

i
Good to Know

All four examples are fictional and simplified. In real incidents, several causes often overlap, so confirm your diagnosis with measured data.

36Troubleshooting: The Share Does Not Match My Ratio

When the number of kept traces does not match your ratio, work through the path of a decision from start to finish.

flowchart TB
    START["Kept traces do not match the ratio"] --> A{"Does the sampler description show the expected ratio?"}
    A -- "no" --> A1["Fix the environment variable or code setting and restart"]
    A -- "yes" --> B{"Is the sampler parent-based?"}
    B -- "no" --> B1["Switch to parent-based so roots decide"]
    B -- "yes" --> C{"Do requests arrive with a sampled flag from callers?"}
    C -- "yes" --> C1["Check which callers set it and whether to trust them"]
    C -- "no" --> D{"Are trace IDs random?"}
    D -- "no" --> D1["Fix the ID generator or the source of IDs"]
    D -- "yes" --> E{"Is another sampler or limit downstream?"}
    E -- "yes" --> E1["Account for Collector or backend sampling and drops"]
    E -- "no" --> E2["Compare against unsampled request counts and use more data"]
Figure 10: A checklist for a kept share that differs from the configured ratio

Explaining the checklist

Start by confirming what the sampler actually is. The description string tells you the ratio the running process uses. If it differs from your intention, the setting did not take effect, or a different setting won. Next, check whether the service is a root or a follower. A follower copies its parent and ignores its own ratio, so its kept share matches the caller’s, not its own.

Then check whether callers send a sampled flag, and whether you should trust them. Then check the trace IDs, since non-random IDs skew results. Finally, check whether another layer, such as a Collector percentage or a backend limit, is removing data after the SDK sampled it. If none of these explains the gap, compare against unsampled request counts, and use a larger window of data, because small samples fluctuate widely.

Everyday Analogy

When a faucet gives too little water, you check the tap, the pipe under the sink, the main valve, and then the supplier, in that order. You find the first place where the flow is wrong, and that is where the problem lives.

i
Tip

When asking colleagues for help, include the sampler description, the number of services in the path, and whether any Collector sampling is configured. Those three facts usually save a round of questions.

37Frequently Asked Questions

Q1 What is TraceIdRatioBased sampling?

It is an OpenTelemetry sampler that keeps a fixed fraction of traces, chosen by comparing the trace ID with a threshold built from the ratio. The decision is deterministic, so the same trace ID gets the same answer wherever the same ratio is used.

Q2 Is it random?

The choice of which traces are kept looks random because trace IDs are random, but the sampler itself is deterministic. It uses no dice, and it gives the same result for the same ID every time.

Q3 Why do I need ParentBased as well?

Because TraceIdRatioBased ignores the parent. The wrapper makes services follow the root’s decision, keeping traces whole. Use it with the ratio sampler as the root choice.

Q4 What ratio should I use?

Start from your budget: divide the spans per second you can afford by the spans per second you would produce. Then check that the result still gives you enough traces to answer your questions. Adjust when traffic changes.

Q5 Will it keep my error traces?

Only at the same ratio as everything else. It decides before the outcome is known. To keep most errors, add a tail sampler or raise the ratio on critical routes.

Q6 What does the ratio 1.0 or 0.0 mean?

A ratio of one or more keeps every trace, and a ratio of zero or less keeps none, in a typical implementation. Check your SDK for how it handles unusual values.

Q7 What is the default sampler if I set nothing?

Generally a parent-based sampler that keeps roots, which means all traces that start in your service are kept. This can produce large volume, so set the sampler explicitly.

Q8 How do I set it without changing code?

Use the standard environment variables for the traces sampler and its argument, choosing the parent-based ratio option and giving the ratio as the argument. Confirm names in your SDK’s documentation.

Q9 Do my metrics get sampled too?

No. This sampler affects traces only. Metrics and logs follow their own rules. Use metrics for accurate counts and rates.

Q10 Should I sample in the SDK or the Collector?

The SDK saves application and network cost. The Collector offers central control and can do tail sampling. Many teams use both, and should remember that the rates multiply.

Q11 Why are some traces missing spans?

Common causes are bare ratio samplers with different ratios, lost context through queues or proxies, and drops after sampling in processors or Collectors.

Q12 Is TraceIdRatioBased still recommended?

It is widely used and works well for simple cases. The OpenTelemetry project has been developing newer probability-based approaches that carry an explicit random value and the sampling probability. Check the current guidance for your SDK before deciding, because this area is still evolving.

38Summary and Key Takeaways

TraceIdRatioBased sampling keeps a fixed fraction of traces by comparing the trace ID, a random number, with a threshold made from your ratio. Because the decision depends only on the ID and the ratio, it is cheap, needs no shared state, and gives the same answer in every service that uses the same ratio. It is a head sampler, so it decides before the outcome is known and cannot favor errors or slow requests. In practice, you use it inside a parent-based wrapper so that the root decides and everyone else follows, and you complement it with unsampled metrics for honest numbers and, where needed, a tail sampler to rescue the traces that matter most.

Key Takeaways

  • TraceIdRatioBased keeps a chosen fraction of traces by turning the trace ID into a yes or no, so the same ID gets the same answer everywhere.
  • It is a head sampler. It decides at the start, saves the most cost, and is blind to errors and slowness.
  • Use it as the root of a parent-based sampler so that traces stay whole and services follow the upstream flag.
  • Pick the ratio from a cost budget and check that it still gives enough traces for your questions. Rare events need higher ratios or tail sampling.
  • Never compute counts or alerts from sampled traces. Use unsampled metrics, or scale by the known ratio.
  • Watch for non-random IDs, lost context, double sampling, and untrusted callers forcing the sampled flag.
  • Write the sampling plan down, monitor the observed share, and revisit the ratio when traffic changes.