Definition · Sampling rate, and captureUnder uniform sampling at rate s, each event is retained independently with probability s. A problem that produces k events is captured if at least one of them is retained. The capture probability is
1 − (1 − s)ᵏ,
which depends on k as strongly as it depends on s — a fact the phrase “one per cent sampling” hides completely, because it names only one of the two.
s = 1/100, k = 10
missed (1 − s)ᵏ = (99/100)¹⁰ = 0.904382075… 90.44%
caught 1 − that = 0.095617925… 9.56%
expected captures s·k = 0.1
the rule of thumb 1 − e^(−s·k) = 1 − e^(−0.1) = 9.516%
differs from the exact 9.562% by 0.045 percentage points
The last two lines are a small lesson of their own. The 1 − e^(−sk) form is an approximation, and the lab computes it by a series that rounds at about 10⁻¹³; the gap between the two columns is 4.5 × 10⁻⁴, nine orders of magnitude larger. An approximation and a rounded approximation are different kinds of wrong, and only one of them gets smaller if you compute harder.
The rate a stated confidence needs
Turn it round: given k and a target confidence c, find the smallest s with 1 − (1 − s)ᵏ ≥ c. The lab scans the thousandths and reports the first that clears the bar, which avoids a logarithm and gives an exact fraction.
want 1 − (1 − s)¹⁰ ≥ 95/100
(1 − s)¹⁰ ≤ 5/100
scan s = 1/1000, 2/1000, … :
s = 250/1000 (3/4)¹⁰ = 0.0563 → 94.37%, short
s = 259/1000 = 0.0499… → 95.01%, first to clear
so 25.9% sampling, against 1% — a factor of 26 for a factor of 10
in confidence
Ten per cent sampling, the obvious compromise, gives 1 − 0.9¹⁰ = 65.13% — better than a coin toss and not a guarantee of anything. If a problem must be visible whenever it occurs, uniform sampling is the wrong instrument at any rate you can afford, and the answer is to stop sampling uniformly.
Tail-biased sampling, and the average it breaks
Keep every request slower than a threshold and sample the rest. Now every slow request survives, which is what you wanted, and the retained set over-represents the tail by a factor of 1/s. Any statistic computed naively on the retained set is a statistic of a population that does not exist.
true traffic 5 ms × 900 8 ms × 60 12 ms × 30 400 ms × 10
n = 1 000
true mean (4 500 + 480 + 360 + 4 000)/1 000 = 9 340/1 000
= 9.34 ms
keep all ≥ 100 ms, sample the rest at s = 1/100:
retained 10 slow + 990/100 = 9.9 of the fast
naive mean (4 000 + 53.4)/19.9 = 4 053.4/19.9 = 203.69 ms
reweight: divide each retained request by its own keep probability
slow counted ×1 fast counted ×100
(4 000 + 5 340)/(10 + 990) = 9 340/1 000 = 9.34 ms exactly
The reweighted figure is not an approximation of the true mean: it is the true mean, recovered exactly, because the weights are the reciprocals of known inclusion probabilities. This is the Horvitz–Thompson estimator, and it is the whole content of “remember to divide by the sampling rate”.
It does not rescue everything. A weighted mean is easy; a weighted percentile needs the weights carried into the rank, and a naive percentile of a tail-biased sample is far worse than a naive mean because it is the tail that was over-kept. If your pipeline samples non-uniformly, every statistic downstream of it needs to know the rate, and the rate has to travel with the data.
Example · Two teams, one trace pipelineThe platform team samples traces at 1% uniformly, so the trace store holds one request in a hundred and its averages are honest. A customer reports ten slow requests; the probability any of them is in the store is 9.56%, and nobody finds anything.
They switch to keeping every request over 100 ms plus 1% of the rest. Now all ten are there. A week later a dashboard built on the same store reports a mean latency of 203.69 ms and an incident is declared about a service whose true mean is 9.34 ms. Both problems are the same decision seen from two ends, and the fix is to store the rate alongside the request rather than to choose between the two failures.