feat: switch samply feature for CLI flags (#20586)

This commit is contained in:
DaniPopes
2025-12-27 12:16:49 -03:00
committed by GitHub
parent a852084b43
commit e595b58c28
12 changed files with 78 additions and 45 deletions

View File

@@ -329,7 +329,6 @@ pub(crate) async fn run_comparison(args: Args, _ctx: CliContext) -> Result<()> {
output_dir.clone(), output_dir.clone(),
git_manager.clone(), git_manager.clone(),
args.features.clone(), args.features.clone(),
args.profile,
)?; )?;
// Initialize node manager // Initialize node manager
let mut node_manager = NodeManager::new(&args); let mut node_manager = NodeManager::new(&args);

View File

@@ -14,7 +14,6 @@ pub(crate) struct CompilationManager {
output_dir: PathBuf, output_dir: PathBuf,
git_manager: GitManager, git_manager: GitManager,
features: String, features: String,
enable_profiling: bool,
} }
impl CompilationManager { impl CompilationManager {
@@ -24,9 +23,8 @@ impl CompilationManager {
output_dir: PathBuf, output_dir: PathBuf,
git_manager: GitManager, git_manager: GitManager,
features: String, features: String,
enable_profiling: bool,
) -> Result<Self> { ) -> Result<Self> {
Ok(Self { repo_root, output_dir, git_manager, features, enable_profiling }) Ok(Self { repo_root, output_dir, git_manager, features })
} }
/// Detect if the RPC endpoint is an Optimism chain /// Detect if the RPC endpoint is an Optimism chain
@@ -102,18 +100,9 @@ impl CompilationManager {
let mut cmd = Command::new("cargo"); let mut cmd = Command::new("cargo");
cmd.arg("build").arg("--profile").arg("profiling"); cmd.arg("build").arg("--profile").arg("profiling");
// Append samply feature when profiling to enable tracing span markers. let features = &self.features;
// NOTE: The `samply` feature must exist in the branch being compiled. If comparing cmd.arg("--features").arg(features);
// against an older branch that predates the samply integration, compilation will fail info!("Using features: {features}");
// or markers won't appear. In that case, omit --profile or ensure both branches
// include the samply feature support.
let features = if self.enable_profiling && !self.features.contains("samply") {
format!("{},samply", self.features)
} else {
self.features.clone()
};
cmd.arg("--features").arg(&features);
info!("Using features: {}", features);
// Add bin-specific arguments for optimism // Add bin-specific arguments for optimism
if is_optimism { if is_optimism {

View File

@@ -211,6 +211,11 @@ impl NodeManager {
cmd.arg("--"); cmd.arg("--");
cmd.args(reth_args); cmd.args(reth_args);
// Enable tracing-samply
if supports_samply_flags(&reth_args[0]) {
cmd.arg("--log.samply");
}
// Set environment variable to disable log styling // Set environment variable to disable log styling
cmd.env("RUST_LOG_STYLE", "never"); cmd.env("RUST_LOG_STYLE", "never");
@@ -552,3 +557,16 @@ impl NodeManager {
Ok(()) Ok(())
} }
} }
fn supports_samply_flags(bin: &str) -> bool {
let mut cmd = std::process::Command::new(bin);
// NOTE: The flag to check must come before --help.
// We pass --help as a shortcut to not execute any command.
cmd.args(["--log.samply", "--help"]);
debug!(?cmd, "Checking samply flags support");
let Ok(output) = cmd.output() else {
return false;
};
debug!(?output, "Samply flags support check");
output.status.success()
}

View File

@@ -87,10 +87,6 @@ otlp = [
"reth-ethereum-cli/otlp", "reth-ethereum-cli/otlp",
"reth-node-core/otlp", "reth-node-core/otlp",
] ]
samply = [
"reth-ethereum-cli/samply",
"reth-node-core/samply",
]
js-tracer = [ js-tracer = [
"reth-node-builder/js-tracer", "reth-node-builder/js-tracer",
"reth-node-ethereum/js-tracer", "reth-node-ethereum/js-tracer",

View File

@@ -38,7 +38,6 @@ tempfile.workspace = true
default = [] default = []
otlp = ["reth-tracing/otlp", "reth-node-core/otlp"] otlp = ["reth-tracing/otlp", "reth-node-core/otlp"]
samply = ["reth-tracing/samply", "reth-node-core/samply"]
dev = ["reth-cli-commands/arbitrary"] dev = ["reth-cli-commands/arbitrary"]

View File

@@ -82,7 +82,6 @@ jemalloc = ["reth-cli-util/jemalloc"]
asm-keccak = ["alloy-primitives/asm-keccak"] asm-keccak = ["alloy-primitives/asm-keccak"]
keccak-cache-global = ["alloy-primitives/keccak-cache-global"] keccak-cache-global = ["alloy-primitives/keccak-cache-global"]
otlp = ["reth-tracing/otlp"] otlp = ["reth-tracing/otlp"]
samply = ["reth-tracing/samply"]
min-error-logs = ["tracing/release_max_level_error"] min-error-logs = ["tracing/release_max_level_error"]
min-warn-logs = ["tracing/release_max_level_warn"] min-warn-logs = ["tracing/release_max_level_warn"]

View File

@@ -61,6 +61,20 @@ pub struct LogArgs {
)] )]
pub journald_filter: String, pub journald_filter: String,
/// Emit traces to samply. Only useful when profiling.
#[arg(long = "log.samply", global = true, hide = true)]
pub samply: bool,
/// The filter to use for traces emitted to samply.
#[arg(
long = "log.samply.filter",
value_name = "FILTER",
global = true,
default_value = "debug",
hide = true
)]
pub samply_filter: String,
/// Sets whether or not the formatter emits ANSI terminal escape codes for colors and other /// Sets whether or not the formatter emits ANSI terminal escape codes for colors and other
/// text formatting. /// text formatting.
#[arg( #[arg(
@@ -129,6 +143,11 @@ impl LogArgs {
tracer = tracer.with_file(file, info); tracer = tracer.with_file(file, info);
} }
if self.samply {
let config = self.layer_info(LogFormat::Terminal, self.samply_filter.clone(), false);
tracer = tracer.with_samply(config);
}
let guard = tracer.init_with_layers(layers)?; let guard = tracer.init_with_layers(layers)?;
Ok(guard) Ok(guard)
} }

View File

@@ -30,7 +30,6 @@ workspace = true
default = ["jemalloc", "otlp", "reth-optimism-evm/portable", "js-tracer", "keccak-cache-global", "asm-keccak"] default = ["jemalloc", "otlp", "reth-optimism-evm/portable", "js-tracer", "keccak-cache-global", "asm-keccak"]
otlp = ["reth-optimism-cli/otlp"] otlp = ["reth-optimism-cli/otlp"]
samply = ["reth-optimism-cli/samply"]
js-tracer = [ js-tracer = [
"reth-optimism-node/js-tracer", "reth-optimism-node/js-tracer",

View File

@@ -78,7 +78,6 @@ default = []
# Opentelemtry feature to activate metrics export # Opentelemtry feature to activate metrics export
otlp = ["reth-tracing/otlp", "reth-node-core/otlp"] otlp = ["reth-tracing/otlp", "reth-node-core/otlp"]
samply = ["reth-tracing/samply", "reth-node-core/samply"]
asm-keccak = [ asm-keccak = [
"alloy-primitives/asm-keccak", "alloy-primitives/asm-keccak",

View File

@@ -21,14 +21,13 @@ tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "ansi"
tracing-appender.workspace = true tracing-appender.workspace = true
tracing-journald.workspace = true tracing-journald.workspace = true
tracing-logfmt.workspace = true tracing-logfmt.workspace = true
tracing-samply.workspace = true
# misc # misc
clap = { workspace = true, features = ["derive"] } clap = { workspace = true, features = ["derive"] }
eyre.workspace = true eyre.workspace = true
rolling-file.workspace = true rolling-file.workspace = true
tracing-samply = { workspace = true, optional = true }
[features] [features]
default = ["otlp"] default = ["otlp"]
otlp = ["reth-tracing-otlp"] otlp = ["reth-tracing-otlp"]
samply = ["tracing-samply"]

View File

@@ -1,4 +1,4 @@
use crate::formatter::LogFormat; use crate::{formatter::LogFormat, LayerInfo};
#[cfg(feature = "otlp")] #[cfg(feature = "otlp")]
use reth_tracing_otlp::{span_layer, OtlpConfig}; use reth_tracing_otlp::{span_layer, OtlpConfig};
use rolling_file::{RollingConditionBasic, RollingFileAppender}; use rolling_file::{RollingConditionBasic, RollingFileAppender};
@@ -130,6 +130,18 @@ impl Layers {
Ok(guard) Ok(guard)
} }
pub(crate) fn samply(&mut self, config: LayerInfo) -> eyre::Result<()> {
self.add_layer(
tracing_samply::SamplyLayer::new()
.map_err(|e| eyre::eyre!("Failed to create samply layer: {e}"))?
.with_filter(build_env_filter(
Some(config.default_directive.parse()?),
&config.filters,
)?),
);
Ok(())
}
/// Add OTLP spans layer to the layer collection /// Add OTLP spans layer to the layer collection
#[cfg(feature = "otlp")] #[cfg(feature = "otlp")]
pub fn with_span_layer( pub fn with_span_layer(

View File

@@ -70,44 +70,51 @@ pub struct RethTracer {
stdout: LayerInfo, stdout: LayerInfo,
journald: Option<String>, journald: Option<String>,
file: Option<(LayerInfo, FileInfo)>, file: Option<(LayerInfo, FileInfo)>,
samply: Option<LayerInfo>,
} }
impl RethTracer { impl RethTracer {
/// Constructs a new `Tracer` with default settings. /// Constructs a new `Tracer` with default settings.
/// ///
/// Initializes with default stdout layer configuration. /// Initializes with default stdout layer configuration.
/// Journald and file layers are not set by default. /// Journald and file layers are not set by default.
pub fn new() -> Self { pub fn new() -> Self {
Self { stdout: LayerInfo::default(), journald: None, file: None } Self { stdout: LayerInfo::default(), journald: None, file: None, samply: None }
} }
/// Sets a custom configuration for the stdout layer. /// Sets a custom configuration for the stdout layer.
/// ///
/// # Arguments /// # Arguments
/// * `config` - The `LayerInfo` to use for the stdout layer. /// * `config` - The `LayerInfo` to use for the stdout layer.
pub fn with_stdout(mut self, config: LayerInfo) -> Self { pub fn with_stdout(mut self, config: LayerInfo) -> Self {
self.stdout = config; self.stdout = config;
self self
} }
/// Sets the journald layer filter. /// Sets the journald layer filter.
/// ///
/// # Arguments /// # Arguments
/// * `filter` - The `filter` to use for the journald layer. /// * `filter` - The `filter` to use for the journald layer.
pub fn with_journald(mut self, filter: String) -> Self { pub fn with_journald(mut self, filter: String) -> Self {
self.journald = Some(filter); self.journald = Some(filter);
self self
} }
/// Sets the file layer configuration and associated file info. /// Sets the file layer configuration and associated file info.
/// ///
/// # Arguments /// # Arguments
/// * `config` - The `LayerInfo` to use for the file layer. /// * `config` - The `LayerInfo` to use for the file layer.
/// * `file_info` - The `FileInfo` containing details about the log file. /// * `file_info` - The `FileInfo` containing details about the log file.
pub fn with_file(mut self, config: LayerInfo, file_info: FileInfo) -> Self { pub fn with_file(mut self, config: LayerInfo, file_info: FileInfo) -> Self {
self.file = Some((config, file_info)); self.file = Some((config, file_info));
self self
} }
/// Sets the samply layer configuration.
pub fn with_samply(mut self, config: LayerInfo) -> Self {
self.samply = Some(config);
self
}
} }
impl Default for RethTracer { impl Default for RethTracer {
@@ -224,11 +231,9 @@ impl Tracer for RethTracer {
None None
}; };
#[cfg(feature = "samply")] if let Some(config) = self.samply {
layers.add_layer( layers.samply(config)?;
tracing_samply::SamplyLayer::new() }
.map_err(|e| eyre::eyre!("Failed to create samply layer: {}", e))?,
);
// The error is returned if the global default subscriber is already set, // The error is returned if the global default subscriber is already set,
// so it's safe to ignore it // so it's safe to ignore it