diff --git a/Cargo.lock b/Cargo.lock index 46290ab97..9fc6acbc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1552,9 +1552,9 @@ checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "snapbox" -version = "0.2.10" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767a1d5da232b6959cd1bd5c9e8db8a7cce09c3038e89deedb49a549a2aefd93" +checksum = "44d199ccf8f606592df2d145db26f2aa45344e23c64b074cc5a4047f1d99b0f7" dependencies = [ "concolor", "content_inspector", @@ -1572,9 +1572,9 @@ dependencies = [ [[package]] name = "snapbox-macros" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01dea7e04cbb27ef4c86e9922184608185f7cd95c1763bc30d727cda4a5e930" +checksum = "8a253e6f894cfa440cba00600a249fa90869d8e0ec45ab274a456e043a0ce8f2" [[package]] name = "socket2" @@ -1981,9 +1981,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "trycmd" -version = "0.13.4" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4185126cc904642173a54c185083f410c86d1202ada6761aacf7c40829f13" +checksum = "9ac9fa73959e252e7c5a4e6260544b952f5bf3989e0b7ad229f4fd6f14671b02" dependencies = [ "glob", "humantime", diff --git a/README.md b/README.md index 809038005..b5a4db4d8 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,25 @@ Options: [env: RUST_LOG=] + -W, --warn ... + Enable lint warnings. + + This is a comma-separated list of warnings to enable. + + Each warning is specified by its name, which is one of: + + * `self-wakes` -- Warns when a task wakes itself more than a + certain percentage of its total wakeups. Default percentage is + 50%. + + * `lost-waker` -- Warns when a task is dropped without being + woken. + + * `never-yielded` -- Warns when a task has never yielded. + + [default: self-wakes lost-waker never-yielded] + [possible values: self-wakes, lost-waker, never-yielded] + --log-dir Path to a directory to write the console's internal logs to. diff --git a/tokio-console/Cargo.toml b/tokio-console/Cargo.toml index 564aa46fc..68740071a 100644 --- a/tokio-console/Cargo.toml +++ b/tokio-console/Cargo.toml @@ -53,5 +53,5 @@ toml = "0.5" dirs = "5" [dev-dependencies] -# Use 1.64.0 compatible version of `trycmd@0.13.4`. -trycmd = "=0.13.4" +# Use 1.64.0 compatible version of `trycmd@0.13.6`. +trycmd = "=0.13.6" diff --git a/tokio-console/console.example.toml b/tokio-console/console.example.toml index f899e878e..4b0db2b4e 100644 --- a/tokio-console/console.example.toml +++ b/tokio-console/console.example.toml @@ -1,5 +1,10 @@ default_target_addr = 'http://127.0.0.1:6669/' log = 'off' +warnings = [ + 'self-wakes', + 'lost-waker', + 'never-yielded', +] log_directory = '/tmp/tokio-console/logs' retention = '6s' diff --git a/tokio-console/src/config.rs b/tokio-console/src/config.rs index 7e2fd2f6e..c470a22e9 100644 --- a/tokio-console/src/config.rs +++ b/tokio-console/src/config.rs @@ -1,4 +1,6 @@ +use crate::state::tasks::Task; use crate::view::Palette; +use crate::warnings; use clap::builder::{PossibleValuesParser, TypedValueParser}; use clap::{ArgAction, ArgGroup, CommandFactory, Parser as Clap, Subcommand, ValueHint}; use clap_complete::Shell; @@ -48,6 +50,23 @@ pub struct Config { #[clap(long = "log", env = "RUST_LOG")] log_filter: Option, + /// Enable lint warnings. + /// + /// This is a comma-separated list of warnings to enable. + /// + /// Each warning is specified by its name, which is one of: + /// + /// * `self-wakes` -- Warns when a task wakes itself more than a certain percentage of its total wakeups. + /// Default percentage is 50%. + /// + /// * `lost-waker` -- Warns when a task is dropped without being woken. + /// + /// * `never-yielded` -- Warns when a task has never yielded. + /// + #[clap(long = "warn", short = 'W', value_delimiter = ',', num_args = 1..)] + #[clap(default_values_t = KnownWarnings::default_enabled_warnings())] + pub(crate) warnings: Vec, + /// Path to a directory to write the console's internal logs to. /// /// [default: /tmp/tokio-console/logs] @@ -98,6 +117,45 @@ pub struct Config { pub subcmd: Option, } +/// Known warnings that can be enabled or disabled. +#[derive(clap::ValueEnum, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)] +#[serde(rename_all = "kebab-case")] +pub(crate) enum KnownWarnings { + SelfWakes, + LostWaker, + NeverYielded, +} + +impl From<&KnownWarnings> for warnings::Linter { + fn from(warning: &KnownWarnings) -> Self { + match warning { + KnownWarnings::SelfWakes => warnings::Linter::new(warnings::SelfWakePercent::default()), + KnownWarnings::LostWaker => warnings::Linter::new(warnings::LostWaker), + KnownWarnings::NeverYielded => warnings::Linter::new(warnings::NeverYielded::default()), + } + } +} + +impl fmt::Display for KnownWarnings { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + KnownWarnings::SelfWakes => write!(f, "self-wakes"), + KnownWarnings::LostWaker => write!(f, "lost-waker"), + KnownWarnings::NeverYielded => write!(f, "never-yielded"), + } + } +} + +impl KnownWarnings { + fn default_enabled_warnings() -> Vec { + vec![ + KnownWarnings::SelfWakes, + KnownWarnings::LostWaker, + KnownWarnings::NeverYielded, + ] + } +} + #[derive(Debug, Subcommand, PartialEq, Eq)] pub enum OptionalCmd { /// Generate a `console.toml` config file with the default configuration @@ -240,6 +298,7 @@ impl FromStr for LogFilter { struct ConfigFile { default_target_addr: Option, log: Option, + warnings: Vec, log_directory: Option, retention: Option, charset: Option, @@ -428,6 +487,13 @@ impl Config { log_directory: other.log_directory.or(self.log_directory), target_addr: other.target_addr.or(self.target_addr), log_filter: other.log_filter.or(self.log_filter), + warnings: { + let mut warns: Vec = other.warnings; + warns.extend(self.warnings); + warns.sort_unstable(); + warns.dedup(); + warns + }, retain_for: other.retain_for.or(self.retain_for), view_options: self.view_options.merge_with(other.view_options), subcmd: other.subcmd.or(self.subcmd), @@ -442,6 +508,7 @@ impl Default for Config { log_filter: Some(LogFilter( filter::Targets::new().with_default(filter::LevelFilter::OFF), )), + warnings: KnownWarnings::default_enabled_warnings(), log_directory: Some(default_log_directory()), retain_for: Some(RetainFor::default()), view_options: ViewOptions::default(), @@ -677,6 +744,7 @@ impl From for ConfigFile { default_target_addr: config.target_addr.map(|addr| addr.to_string()), log: config.log_filter.map(|filter| filter.to_string()), log_directory: config.log_directory, + warnings: config.warnings, retention: config.retain_for, charset: Some(CharsetConfig { lang: config.view_options.lang, @@ -699,6 +767,7 @@ impl TryFrom for Config { Ok(Config { target_addr: value.target_addr()?, log_filter: value.log_filter()?, + warnings: value.warnings.clone(), log_directory: value.log_directory.take(), retain_for: value.retain_for(), view_options: ViewOptions { diff --git a/tokio-console/src/main.rs b/tokio-console/src/main.rs index 9f2fc6aa3..4f99ee71a 100644 --- a/tokio-console/src/main.rs +++ b/tokio-console/src/main.rs @@ -66,13 +66,7 @@ async fn main() -> color_eyre::Result<()> { let (details_tx, mut details_rx) = mpsc::channel::(2); let mut state = State::default() - // TODO(eliza): allow configuring the list of linters via the - // CLI/possibly a config file? - .with_task_linters(vec![ - warnings::Linter::new(warnings::SelfWakePercent::default()), - warnings::Linter::new(warnings::LostWaker), - warnings::Linter::new(warnings::NeverYielded::default()), - ]) + .with_task_linters(args.warnings.iter().map(|lint| lint.into())) .with_retain_for(retain_for); let mut input = Box::pin(input::EventStream::new().try_filter(|event| { future::ready(!matches!( diff --git a/tokio-console/tests/cli-ui.stdout b/tokio-console/tests/cli-ui.stdout index 237a12641..519a82dbd 100644 --- a/tokio-console/tests/cli-ui.stdout +++ b/tokio-console/tests/cli-ui.stdout @@ -39,6 +39,25 @@ Options: [env: RUST_LOG=] + -W, --warn ... + Enable lint warnings. + + This is a comma-separated list of warnings to enable. + + Each warning is specified by its name, which is one of: + + * `self-wakes` -- Warns when a task wakes itself more than a + certain percentage of its total wakeups. Default percentage is + 50%. + + * `lost-waker` -- Warns when a task is dropped without being + woken. + + * `never-yielded` -- Warns when a task has never yielded. + + [default: self-wakes lost-waker never-yielded] + [possible values: self-wakes, lost-waker, never-yielded] + --log-dir Path to a directory to write the console's internal logs to.