Skip to content

Commit 7f40013

Browse files
authored
feat(tracing-otlp): make trace id ratio sample customizable with --tracing-otlp.sample-ratio arg (#19438)
1 parent 6e36594 commit 7f40013

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+584
-35
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/node/core/src/args/trace.rs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use clap::Parser;
44
use eyre::WrapErr;
55
use reth_tracing::{tracing_subscriber::EnvFilter, Layers};
6-
use reth_tracing_otlp::OtlpProtocol;
6+
use reth_tracing_otlp::{OtlpConfig, OtlpProtocol};
77
use url::Url;
88

99
/// CLI arguments for configuring `Opentelemetry` trace and span export.
@@ -78,6 +78,23 @@ pub struct TraceArgs {
7878
help_heading = "Tracing"
7979
)]
8080
pub service_name: String,
81+
82+
/// Trace sampling ratio to control the percentage of traces to export.
83+
///
84+
/// Valid range: 0.0 to 1.0
85+
/// - 1.0, default: Sample all traces
86+
/// - 0.01: Sample 1% of traces
87+
/// - 0.0: Disable sampling
88+
///
89+
/// Example: --tracing-otlp.sample-ratio=0.0.
90+
#[arg(
91+
long = "tracing-otlp.sample-ratio",
92+
env = "OTEL_TRACES_SAMPLER_ARG",
93+
global = true,
94+
value_name = "RATIO",
95+
help_heading = "Tracing"
96+
)]
97+
pub sample_ratio: Option<f64>,
8198
}
8299

83100
impl Default for TraceArgs {
@@ -86,6 +103,7 @@ impl Default for TraceArgs {
86103
otlp: None,
87104
protocol: OtlpProtocol::Http,
88105
otlp_filter: EnvFilter::from_default_env(),
106+
sample_ratio: None,
89107
service_name: "reth".to_string(),
90108
}
91109
}
@@ -102,22 +120,24 @@ impl TraceArgs {
102120
/// Note: even though this function is async, it does not actually perform any async operations.
103121
/// It's needed only to be able to initialize the gRPC transport of OTLP tracing that needs to
104122
/// be called inside a tokio runtime context.
105-
pub async fn init_otlp_tracing(
106-
&mut self,
107-
_layers: &mut Layers,
108-
) -> eyre::Result<OtlpInitStatus> {
123+
pub async fn init_otlp_tracing(&mut self, layers: &mut Layers) -> eyre::Result<OtlpInitStatus> {
109124
if let Some(endpoint) = self.otlp.as_mut() {
110125
self.protocol.validate_endpoint(endpoint)?;
111126

112127
#[cfg(feature = "otlp")]
113128
{
114-
_layers.with_span_layer(
115-
self.service_name.clone(),
116-
endpoint.clone(),
117-
self.otlp_filter.clone(),
118-
self.protocol,
119-
)?;
120-
Ok(OtlpInitStatus::Started(endpoint.clone()))
129+
{
130+
let config = OtlpConfig::new(
131+
self.service_name.clone(),
132+
endpoint.clone(),
133+
self.protocol,
134+
self.sample_ratio,
135+
)?;
136+
137+
layers.with_span_layer(config.clone(), self.otlp_filter.clone())?;
138+
139+
Ok(OtlpInitStatus::Started(config.endpoint().clone()))
140+
}
121141
}
122142
#[cfg(not(feature = "otlp"))]
123143
{

crates/tracing-otlp/src/lib.rs

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use opentelemetry::{global, trace::TracerProvider, KeyValue, Value};
1212
use opentelemetry_otlp::{SpanExporter, WithExportConfig};
1313
use opentelemetry_sdk::{
1414
propagation::TraceContextPropagator,
15-
trace::{SdkTracer, SdkTracerProvider},
15+
trace::{Sampler, SdkTracer, SdkTracerProvider},
1616
Resource,
1717
};
1818
use opentelemetry_semantic_conventions::{attribute::SERVICE_VERSION, SCHEMA_URL};
@@ -29,36 +29,92 @@ const HTTP_TRACE_ENDPOINT: &str = "/v1/traces";
2929
///
3030
/// This layer can be added to a [`tracing_subscriber::Registry`] to enable `OpenTelemetry` tracing
3131
/// with OTLP export to an url.
32-
pub fn span_layer<S>(
33-
service_name: impl Into<Value>,
34-
endpoint: &Url,
35-
protocol: OtlpProtocol,
36-
) -> eyre::Result<OpenTelemetryLayer<S, SdkTracer>>
32+
pub fn span_layer<S>(otlp_config: OtlpConfig) -> eyre::Result<OpenTelemetryLayer<S, SdkTracer>>
3733
where
3834
for<'span> S: Subscriber + LookupSpan<'span>,
3935
{
4036
global::set_text_map_propagator(TraceContextPropagator::new());
4137

42-
let resource = build_resource(service_name);
38+
let resource = build_resource(otlp_config.service_name.clone());
4339

4440
let span_builder = SpanExporter::builder();
4541

46-
let span_exporter = match protocol {
47-
OtlpProtocol::Http => span_builder.with_http().with_endpoint(endpoint.as_str()).build()?,
48-
OtlpProtocol::Grpc => span_builder.with_tonic().with_endpoint(endpoint.as_str()).build()?,
42+
let span_exporter = match otlp_config.protocol {
43+
OtlpProtocol::Http => {
44+
span_builder.with_http().with_endpoint(otlp_config.endpoint.as_str()).build()?
45+
}
46+
OtlpProtocol::Grpc => {
47+
span_builder.with_tonic().with_endpoint(otlp_config.endpoint.as_str()).build()?
48+
}
4949
};
5050

51+
let sampler = build_sampler(otlp_config.sample_ratio)?;
52+
5153
let tracer_provider = SdkTracerProvider::builder()
5254
.with_resource(resource)
55+
.with_sampler(sampler)
5356
.with_batch_exporter(span_exporter)
5457
.build();
5558

5659
global::set_tracer_provider(tracer_provider.clone());
5760

58-
let tracer = tracer_provider.tracer("reth");
61+
let tracer = tracer_provider.tracer(otlp_config.service_name);
5962
Ok(tracing_opentelemetry::layer().with_tracer(tracer))
6063
}
6164

65+
/// Configuration for OTLP trace export.
66+
#[derive(Debug, Clone)]
67+
pub struct OtlpConfig {
68+
/// Service name for trace identification
69+
service_name: String,
70+
/// Otlp endpoint URL
71+
endpoint: Url,
72+
/// Transport protocol, HTTP or gRPC
73+
protocol: OtlpProtocol,
74+
/// Optional sampling ratio, from 0.0 to 1.0
75+
sample_ratio: Option<f64>,
76+
}
77+
78+
impl OtlpConfig {
79+
/// Creates a new OTLP configuration.
80+
pub fn new(
81+
service_name: impl Into<String>,
82+
endpoint: Url,
83+
protocol: OtlpProtocol,
84+
sample_ratio: Option<f64>,
85+
) -> eyre::Result<Self> {
86+
if let Some(ratio) = sample_ratio {
87+
ensure!(
88+
(0.0..=1.0).contains(&ratio),
89+
"Sample ratio must be between 0.0 and 1.0, got: {}",
90+
ratio
91+
);
92+
}
93+
94+
Ok(Self { service_name: service_name.into(), endpoint, protocol, sample_ratio })
95+
}
96+
97+
/// Returns the service name.
98+
pub fn service_name(&self) -> &str {
99+
&self.service_name
100+
}
101+
102+
/// Returns the OTLP endpoint URL.
103+
pub const fn endpoint(&self) -> &Url {
104+
&self.endpoint
105+
}
106+
107+
/// Returns the transport protocol.
108+
pub const fn protocol(&self) -> OtlpProtocol {
109+
self.protocol
110+
}
111+
112+
/// Returns the sampling ratio.
113+
pub const fn sample_ratio(&self) -> Option<f64> {
114+
self.sample_ratio
115+
}
116+
}
117+
62118
// Builds OTLP resource with service information.
63119
fn build_resource(service_name: impl Into<Value>) -> Resource {
64120
Resource::builder()
@@ -67,6 +123,18 @@ fn build_resource(service_name: impl Into<Value>) -> Resource {
67123
.build()
68124
}
69125

126+
/// Builds the appropriate sampler based on the sample ratio.
127+
fn build_sampler(sample_ratio: Option<f64>) -> eyre::Result<Sampler> {
128+
match sample_ratio {
129+
// Default behavior: sample all traces
130+
None | Some(1.0) => Ok(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))),
131+
// Don't sample anything
132+
Some(0.0) => Ok(Sampler::ParentBased(Box::new(Sampler::AlwaysOff))),
133+
// Sample based on trace ID ratio
134+
Some(ratio) => Ok(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(ratio)))),
135+
}
136+
}
137+
70138
/// OTLP transport protocol type
71139
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
72140
pub enum OtlpProtocol {

crates/tracing/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ tracing-logfmt.workspace = true
2626
clap = { workspace = true, features = ["derive"] }
2727
eyre.workspace = true
2828
rolling-file.workspace = true
29-
url = { workspace = true, optional = true }
3029

3130
[features]
3231
default = ["otlp"]
33-
otlp = ["reth-tracing-otlp", "dep:url"]
32+
otlp = ["reth-tracing-otlp"]

crates/tracing/src/layers.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
use crate::formatter::LogFormat;
2+
#[cfg(feature = "otlp")]
3+
use reth_tracing_otlp::{span_layer, OtlpConfig};
24
use rolling_file::{RollingConditionBasic, RollingFileAppender};
35
use std::{
46
fmt,
57
path::{Path, PathBuf},
68
};
79
use tracing_appender::non_blocking::WorkerGuard;
810
use tracing_subscriber::{filter::Directive, EnvFilter, Layer, Registry};
9-
#[cfg(feature = "otlp")]
10-
use {
11-
reth_tracing_otlp::{span_layer, OtlpProtocol},
12-
url::Url,
13-
};
1411

1512
/// A worker guard returned by the file layer.
1613
///
@@ -137,14 +134,12 @@ impl Layers {
137134
#[cfg(feature = "otlp")]
138135
pub fn with_span_layer(
139136
&mut self,
140-
service_name: String,
141-
endpoint_exporter: Url,
137+
otlp_config: OtlpConfig,
142138
filter: EnvFilter,
143-
otlp_protocol: OtlpProtocol,
144139
) -> eyre::Result<()> {
145140
// Create the span provider
146141

147-
let span_layer = span_layer(service_name, &endpoint_exporter, otlp_protocol)
142+
let span_layer = span_layer(otlp_config)
148143
.map_err(|e| eyre::eyre!("Failed to build OTLP span exporter {}", e))?
149144
.with_filter(filter);
150145

docs/vocs/docs/pages/cli/reth.mdx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,13 @@ Tracing:
146146
Defaults to TRACE if not specified.
147147
148148
[default: debug]
149+
150+
--tracing-otlp.sample-ratio <RATIO>
151+
Trace sampling ratio to control the percentage of traces to export.
152+
153+
Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling
154+
155+
Example: --tracing-otlp.sample-ratio=0.0.
156+
157+
[env: OTEL_TRACES_SAMPLER_ARG=]
149158
```

docs/vocs/docs/pages/cli/reth/config.mdx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,13 @@ Tracing:
132132
Defaults to TRACE if not specified.
133133
134134
[default: debug]
135+
136+
--tracing-otlp.sample-ratio <RATIO>
137+
Trace sampling ratio to control the percentage of traces to export.
138+
139+
Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling
140+
141+
Example: --tracing-otlp.sample-ratio=0.0.
142+
143+
[env: OTEL_TRACES_SAMPLER_ARG=]
135144
```

docs/vocs/docs/pages/cli/reth/db.mdx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,13 @@ Tracing:
242242
Defaults to TRACE if not specified.
243243
244244
[default: debug]
245+
246+
--tracing-otlp.sample-ratio <RATIO>
247+
Trace sampling ratio to control the percentage of traces to export.
248+
249+
Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling
250+
251+
Example: --tracing-otlp.sample-ratio=0.0.
252+
253+
[env: OTEL_TRACES_SAMPLER_ARG=]
245254
```

docs/vocs/docs/pages/cli/reth/db/checksum.mdx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,13 @@ Tracing:
149149
Defaults to TRACE if not specified.
150150
151151
[default: debug]
152+
153+
--tracing-otlp.sample-ratio <RATIO>
154+
Trace sampling ratio to control the percentage of traces to export.
155+
156+
Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling
157+
158+
Example: --tracing-otlp.sample-ratio=0.0.
159+
160+
[env: OTEL_TRACES_SAMPLER_ARG=]
152161
```

docs/vocs/docs/pages/cli/reth/db/clear.mdx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,13 @@ Tracing:
141141
Defaults to TRACE if not specified.
142142
143143
[default: debug]
144+
145+
--tracing-otlp.sample-ratio <RATIO>
146+
Trace sampling ratio to control the percentage of traces to export.
147+
148+
Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling
149+
150+
Example: --tracing-otlp.sample-ratio=0.0.
151+
152+
[env: OTEL_TRACES_SAMPLER_ARG=]
144153
```

0 commit comments

Comments
 (0)