Skip to main content

cf_rustracing/
sampler.rs

1//! `Sampler` trait and its built-in implementations.
2use crate::span::CandidateSpan;
3use crate::{ErrorKind, Result};
4use std::fmt::Debug;
5
6/// `Sampler` decides whether a new trace should be sampled or not.
7pub trait Sampler<T>: Debug {
8    /// This method decides whether a trace with given `span` should be sampled.
9    fn is_sampled(&self, span: &CandidateSpan<T>) -> bool;
10
11    /// Returns the sampler that samples a trace if `self` or `other` decides to sample it.
12    fn or<U>(self, other: U) -> OrSampler<Self, U>
13    where
14        Self: Sized,
15        U: Sampler<T>,
16    {
17        OrSampler(self, other)
18    }
19
20    /// Returns the sampler that samples a trace if both of `self` and `other` decides to sample it.
21    fn and<U>(self, other: U) -> AndSampler<Self, U>
22    where
23        Self: Sized,
24        U: Sampler<T>,
25    {
26        AndSampler(self, other)
27    }
28
29    /// Converts into `BoxSampler`.
30    fn boxed(self) -> BoxSampler<T>
31    where
32        Self: Sized + Send + Sync + 'static,
33    {
34        Box::new(self)
35    }
36}
37impl<T> Sampler<T> for BoxSampler<T> {
38    fn is_sampled(&self, span: &CandidateSpan<T>) -> bool {
39        (**self).is_sampled(span)
40    }
41    fn boxed(self) -> BoxSampler<T>
42    where
43        Self: Sized + Send + 'static,
44    {
45        self
46    }
47}
48
49/// Boxed version of `Sampler`.
50pub type BoxSampler<T> = Box<dyn Sampler<T> + Send + Sync + 'static>;
51
52/// This samples a certain percentage of traces.
53#[derive(Debug, Clone)]
54pub struct ProbabilisticSampler {
55    sampling_rate: f64,
56}
57impl ProbabilisticSampler {
58    /// Makes a new `ProbabilisticSampler` instance.
59    ///
60    /// # Errors
61    ///
62    /// If `sampling_rate` is not in the range `0.0...1.0`,
63    /// it will return an error with the kind `ErrorKind::InvalidInput`.
64    pub fn new(sampling_rate: f64) -> Result<Self> {
65        track_assert!(0.0 <= sampling_rate, ErrorKind::InvalidInput);
66        track_assert!(sampling_rate <= 1.0, ErrorKind::InvalidInput);
67        Ok(ProbabilisticSampler { sampling_rate })
68    }
69}
70impl<T> Sampler<T> for ProbabilisticSampler {
71    fn is_sampled(&self, _span: &CandidateSpan<T>) -> bool {
72        rand::random_range(0.0..1.0) < self.sampling_rate
73    }
74}
75
76/// This samples traces which have one or more references.
77#[derive(Debug, Clone)]
78pub struct PassiveSampler;
79impl<T> Sampler<T> for PassiveSampler {
80    fn is_sampled(&self, span: &CandidateSpan<T>) -> bool {
81        !span.references().is_empty()
82    }
83}
84
85/// This samples no traces.
86#[derive(Debug, Clone)]
87pub struct NullSampler;
88impl<T> Sampler<T> for NullSampler {
89    fn is_sampled(&self, _span: &CandidateSpan<T>) -> bool {
90        false
91    }
92}
93
94/// This samples all traces.
95#[derive(Debug, Clone)]
96pub struct AllSampler;
97impl<T> Sampler<T> for AllSampler {
98    fn is_sampled(&self, _span: &CandidateSpan<T>) -> bool {
99        true
100    }
101}
102
103/// `or` combinator.
104#[derive(Debug, Clone)]
105pub struct OrSampler<A, B>(A, B);
106impl<A, B, T> Sampler<T> for OrSampler<A, B>
107where
108    A: Sampler<T>,
109    B: Sampler<T>,
110{
111    fn is_sampled(&self, span: &CandidateSpan<T>) -> bool {
112        self.0.is_sampled(span) || self.1.is_sampled(span)
113    }
114}
115
116/// `and` combinator.
117#[derive(Debug, Clone)]
118pub struct AndSampler<A, B>(A, B);
119impl<A, B, T> Sampler<T> for AndSampler<A, B>
120where
121    A: Sampler<T>,
122    B: Sampler<T>,
123{
124    fn is_sampled(&self, span: &CandidateSpan<T>) -> bool {
125        self.0.is_sampled(span) && self.1.is_sampled(span)
126    }
127}