Skip to content

Commit 37891f1

Browse files
authored
fix(sampling): format _dd.p.ksr to 6 decimal places, not 6 significant digits (#2086)
# What does this PR do? The cross-tracer spec for _dd.p.ksr is "up to 6 decimal digits of precision, with trailing zeros stripped" — i.e. Go's `strconv.FormatFloat(rate, 'f', 6, 64)`. The previous implementation rounded to 6 *significant* digits ('g', 6, 64), which gave the right answer for every value in the original unit test but diverged for very small rates: 0.0000001 produced "0.0000001" instead of "0", and 0.00000051 produced "0.00000051" instead of "0.000001". System-tests PR DataDog/system-tests#6466 added explicit cases for those two inputs (below_precision_rounds_to_zero, rounds_up_to_one_millionth), which started failing for dd-trace-rs once it bumped to a libdatadog containing this code (PR DataDog/dd-trace-rs#180, now living here after the sampling move-out refactor). Replace the bespoke significant-digit rounding with a plain `{rate:.6}` format followed by trailing-zero strip; this gives the right rounding for free (including the "0" case, since "0.000000" trims down to "0"). Co-authored-by: igor.unanua <igor.unanua@datadoghq.com>
1 parent d85861b commit 37891f1

1 file changed

Lines changed: 17 additions & 26 deletions

File tree

libdd-sampling/src/datadog_sampler.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -187,45 +187,27 @@ impl DatadogSampler {
187187
}
188188
}
189189

190-
/// Formats a sampling rate with up to 6 significant digits, stripping trailing zeros.
190+
/// Formats a sampling rate with up to 6 decimal places, stripping trailing zeros.
191191
///
192-
/// This matches the Go behavior of `strconv.FormatFloat(rate, 'g', 6, 64)`.
192+
/// Matches `strconv.FormatFloat(rate, 'f', 6, 64)` in Go, after trailing-zero
193+
/// stripping. Rates below 5e-7 round to `"0"`.
193194
///
194195
/// # Examples
195196
/// - `1.0` → `Some("1")`
196197
/// - `0.5` → `Some("0.5")`
197198
/// - `0.7654321` → `Some("0.765432")`
198199
/// - `0.100000` → `Some("0.1")`
200+
/// - `0.0000001` → `Some("0")` (rounds below the 6th decimal place)
201+
/// - `0.00000051` → `Some("0.000001")` (rounds up to one millionth)
199202
/// - `-0.1` → `None`
200203
/// - `1.1` → `None`
201204
fn format_sampling_rate(rate: f64) -> Option<String> {
202205
if rate.is_nan() || !(0.0..=1.0).contains(&rate) {
203206
return None;
204207
}
205208

206-
if rate == 0.0 {
207-
return Some("0".to_string());
208-
}
209-
210-
let digits = 6_i32;
211-
let magnitude = rate.abs().log10().floor() as i32;
212-
let scale = 10f64.powi(digits - 1 - magnitude);
213-
let rounded = (rate * scale).round() / scale;
214-
215-
// Determine decimal places needed for 6 significant digits
216-
let decimal_places = if magnitude >= digits - 1 {
217-
0
218-
} else {
219-
(digits - 1 - magnitude) as usize
220-
};
221-
222-
let s = format!("{:.prec$}", rounded, prec = decimal_places);
223-
// Strip trailing zeros after decimal point
224-
Some(if s.contains('.') {
225-
s.trim_end_matches('0').trim_end_matches('.').to_string()
226-
} else {
227-
s
228-
})
209+
let s = format!("{rate:.6}");
210+
Some(s.trim_end_matches('0').trim_end_matches('.').to_string())
229211
}
230212

231213
pub struct TraceRootSamplingInfo {
@@ -1178,7 +1160,7 @@ mod tests {
11781160
assert_eq!(format_sampling_rate(0.100000), Some("0.1".to_string()));
11791161
assert_eq!(format_sampling_rate(0.500000), Some("0.5".to_string()));
11801162

1181-
// Truncation to 6 significant digits
1163+
// Truncation to 6 decimal places
11821164
assert_eq!(
11831165
format_sampling_rate(0.7654321),
11841166
Some("0.765432".to_string())
@@ -1190,6 +1172,15 @@ mod tests {
11901172

11911173
// Small values
11921174
assert_eq!(format_sampling_rate(0.001), Some("0.001".to_string()));
1175+
assert_eq!(format_sampling_rate(0.000001), Some("0.000001".to_string()));
1176+
1177+
// Below the 6th decimal place rounds to "0"
1178+
assert_eq!(format_sampling_rate(0.0000001), Some("0".to_string()));
1179+
// Just above the round-up threshold lands on one millionth
1180+
assert_eq!(
1181+
format_sampling_rate(0.00000051),
1182+
Some("0.000001".to_string())
1183+
);
11931184

11941185
// Boundary values
11951186
assert_eq!(format_sampling_rate(0.75), Some("0.75".to_string()));

0 commit comments

Comments
 (0)