mirror of
https://github.com/rustfs/rustfs.git
synced 2026-03-17 14:24:08 +00:00
fix(obs): avoid panic in telemetry init and clamp sampler boundaries (#2118)
Signed-off-by: houseme <housemecn@gmail.com> Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
@@ -206,7 +206,7 @@ fn init_file_logging_internal(
|
||||
|
||||
builder
|
||||
.build(log_directory)
|
||||
.expect("failed to initialize rolling file appender")
|
||||
.map_err(|e| TelemetryError::Io(format!("failed to initialize rolling file appender: {e}")))?
|
||||
};
|
||||
|
||||
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
|
||||
@@ -417,3 +417,24 @@ fn spawn_cleanup_task(
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::OtelConfig;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
fn test_init_file_logging_invalid_filename_does_not_panic() {
|
||||
let temp_dir = tempdir().expect("create temp dir");
|
||||
let temp_path = temp_dir.path().to_str().expect("temp dir path is utf-8");
|
||||
let config = OtelConfig {
|
||||
log_filename: Some("invalid\0name.log".to_string()),
|
||||
..OtelConfig::default()
|
||||
};
|
||||
|
||||
let result = init_file_logging_internal(&config, temp_path, "info", true);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,11 +96,7 @@ pub(super) fn init_observability_http(
|
||||
let service_name = config.service_name.as_deref().unwrap_or(APP_NAME).to_owned();
|
||||
let use_stdout = config.use_stdout.unwrap_or(!is_production);
|
||||
let sample_ratio = config.sample_ratio.unwrap_or(SAMPLE_RATIO);
|
||||
let sampler = if (0.0..1.0).contains(&sample_ratio) {
|
||||
Sampler::TraceIdRatioBased(sample_ratio)
|
||||
} else {
|
||||
Sampler::AlwaysOn
|
||||
};
|
||||
let sampler = build_tracer_sampler(sample_ratio);
|
||||
|
||||
// ── Endpoint resolution ───────────────────────────────────────────────────
|
||||
// Each signal may have a dedicated endpoint; if absent, fall back to the
|
||||
@@ -239,6 +235,14 @@ fn build_tracer_provider(
|
||||
Ok(Some(provider))
|
||||
}
|
||||
|
||||
fn build_tracer_sampler(sample_ratio: f64) -> Sampler {
|
||||
if sample_ratio.is_finite() && (0.0..=1.0).contains(&sample_ratio) {
|
||||
Sampler::TraceIdRatioBased(sample_ratio)
|
||||
} else {
|
||||
Sampler::AlwaysOn
|
||||
}
|
||||
}
|
||||
|
||||
/// Build an optional [`SdkMeterProvider`] for the given metrics endpoint.
|
||||
///
|
||||
/// Returns `None` when the endpoint is empty or metric export is disabled.
|
||||
@@ -360,3 +364,29 @@ fn create_periodic_reader(interval: u64) -> PeriodicReader<opentelemetry_stdout:
|
||||
.with_interval(Duration::from_secs(interval))
|
||||
.build()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_build_tracer_sampler_uses_trace_ratio_for_valid_values() {
|
||||
let sampler = build_tracer_sampler(0.0);
|
||||
assert!(format!("{sampler:?}").contains("TraceIdRatioBased"));
|
||||
|
||||
let sampler = build_tracer_sampler(1.0);
|
||||
assert!(format!("{sampler:?}").contains("TraceIdRatioBased"));
|
||||
|
||||
let sampler = build_tracer_sampler(0.5);
|
||||
assert!(format!("{sampler:?}").contains("TraceIdRatioBased"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_tracer_sampler_rejects_invalid_ratio_with_always_on() {
|
||||
let sampler = build_tracer_sampler(-0.1);
|
||||
assert!(format!("{sampler:?}").contains("AlwaysOn"));
|
||||
|
||||
let sampler = build_tracer_sampler(1.2);
|
||||
assert!(format!("{sampler:?}").contains("AlwaysOn"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user