mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-08 01:05:47 +00:00
Implement custom OpenTelemetry sampler to filter uninstrumented traces (#8647)
Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com>
This commit is contained in:
8
common/tracing_samplers/Cargo.toml
Normal file
8
common/tracing_samplers/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "tracing_samplers"
|
||||
version = "0.1.0"
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
opentelemetry = { workspace = true }
|
||||
opentelemetry_sdk = { workspace = true }
|
||||
78
common/tracing_samplers/src/lib.rs
Normal file
78
common/tracing_samplers/src/lib.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
//! OpenTelemetry samplers for filtering traces.
|
||||
|
||||
use opentelemetry::Context;
|
||||
use opentelemetry::trace::{Link, SamplingDecision, SamplingResult, SpanKind, TraceState};
|
||||
use opentelemetry_sdk::trace::ShouldSample;
|
||||
|
||||
/// A sampler that only samples spans whose names start with a given prefix.
|
||||
///
|
||||
/// This sampler is designed to be used with `Sampler::ParentBased`, which will:
|
||||
/// - Use this sampler's decision for root spans (no parent)
|
||||
/// - Automatically inherit the parent's sampling decision for child spans
|
||||
///
|
||||
/// This ensures that only traces starting from known instrumented code paths are exported,
|
||||
/// reducing noise from partially instrumented code paths.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PrefixBasedSampler {
|
||||
prefix: &'static str,
|
||||
}
|
||||
|
||||
impl PrefixBasedSampler {
|
||||
pub fn new(prefix: &'static str) -> Self {
|
||||
Self { prefix }
|
||||
}
|
||||
}
|
||||
|
||||
impl ShouldSample for PrefixBasedSampler {
|
||||
fn should_sample(
|
||||
&self,
|
||||
_parent_context: Option<&Context>,
|
||||
_trace_id: opentelemetry::trace::TraceId,
|
||||
name: &str,
|
||||
_span_kind: &SpanKind,
|
||||
_attributes: &[opentelemetry::KeyValue],
|
||||
_links: &[Link],
|
||||
) -> SamplingResult {
|
||||
if name.starts_with(self.prefix) {
|
||||
SamplingResult {
|
||||
decision: SamplingDecision::RecordAndSample,
|
||||
attributes: Vec::new(),
|
||||
trace_state: TraceState::default(),
|
||||
}
|
||||
} else {
|
||||
SamplingResult {
|
||||
decision: SamplingDecision::Drop,
|
||||
attributes: Vec::new(),
|
||||
trace_state: TraceState::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use opentelemetry::trace::TraceId;
|
||||
|
||||
#[test]
|
||||
fn prefix_based_sampler_filters_by_prefix() {
|
||||
let sampler = PrefixBasedSampler::new("test_");
|
||||
let trace_id = TraceId::from_hex("0123456789abcdef0123456789abcdef").unwrap();
|
||||
|
||||
// Spans with prefix should be sampled
|
||||
let result = sampler.should_sample(
|
||||
None,
|
||||
trace_id,
|
||||
"test_my_span",
|
||||
&SpanKind::Internal,
|
||||
&[],
|
||||
&[],
|
||||
);
|
||||
assert!(matches!(result.decision, SamplingDecision::RecordAndSample));
|
||||
|
||||
// Spans without prefix should be dropped
|
||||
let result =
|
||||
sampler.should_sample(None, trace_id, "other_span", &SpanKind::Internal, &[], &[]);
|
||||
assert!(matches!(result.decision, SamplingDecision::Drop));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user