From d2d5f87e918d7e7d99b31abdf63571e743c1bb67 Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Wed, 28 Oct 2026 15:15:54 +0700 Subject: [PATCH] feat(client): filter output by selected event types --- crates/irtt-app/src/cmd/client/args.rs | 35 +++++++++++++++++++++++- crates/irtt-app/src/cmd/client/output.rs | 32 +++++++++++++--------- crates/irtt-app/src/cmd/client/run.rs | 1 + docs/irtt-client.md | 21 +++++++++++--- 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/crates/irtt-app/src/cmd/client/args.rs b/crates/irtt-app/src/cmd/client/args.rs index 87ff4fa..da04178 100644 --- a/crates/irtt-app/src/cmd/client/args.rs +++ b/crates/irtt-app/src/cmd/client/args.rs @@ -101,12 +101,22 @@ pub struct ClientArgs { )] pub format: OutputFormat, + /// Filter output by event type. + #[arg( + long, + value_name = "EVENTS", + value_delimiter = ',', + value_enum, + long_help = "Filter output by event type. Accepts comma-separated names or repeated options. If omitted, the normal output behavior is unchanged." + )] + pub events: Vec, + /// Comma-separated event row columns, or default/all. #[arg( short = 'c', long, value_name = "COLUMNS", - long_help = "Comma-separated event row columns, or default/all.\n\nThe default table columns are compact and hide echo_sent rows. Custom table columns include all event rows. Run --list-columns to see valid names." + long_help = "Comma-separated event row columns, or default/all.\n\nThe default table columns are compact and hide echo_sent rows unless explicitly selected with --events. Custom table columns include all event rows. Run --list-columns to see valid names." )] pub columns: Option, @@ -189,6 +199,29 @@ impl std::ops::Deref for ClientArgs { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "snake_case")] +pub enum EventKind { + SessionStarted, + NoTestCompleted, + SessionClosed, + EchoSent, + EchoReply, + Loss, + Duplicate, + Late, + Warning, +} + +impl EventKind { + pub(super) fn name(self) -> String { + self.to_possible_value() + .expect("all event kinds have a CLI value") + .get_name() + .to_owned() + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] pub enum OutputFormat { /// Readable terminal table output. diff --git a/crates/irtt-app/src/cmd/client/output.rs b/crates/irtt-app/src/cmd/client/output.rs index a6af2a2..ae8d43d 100644 --- a/crates/irtt-app/src/cmd/client/output.rs +++ b/crates/irtt-app/src/cmd/client/output.rs @@ -12,12 +12,13 @@ use irtt_client::{ #[cfg(feature = "stats")] use irtt_stats::{EventStatsUpdate, IpdvPairUpdate}; -use super::args::{HeaderMode, OutputFormat}; +use super::args::{EventKind, HeaderMode, OutputFormat}; use crate::cmd::format::{format_duration, format_signed_duration, ABSENT}; #[derive(Debug, Clone)] pub(super) struct OutputConfig { format: OutputFormat, + events: Vec, columns: Vec, header: HeaderMode, default_table_rows: bool, @@ -30,6 +31,7 @@ impl OutputConfig { columns: Option<&str>, header: HeaderMode, verbose: bool, + events: Vec, ) -> Result { let uses_default_columns = columns .map(|columns| columns.trim() == "default") @@ -42,6 +44,7 @@ impl OutputConfig { Ok(Self { format, + events, columns, header, default_table_rows, @@ -102,7 +105,10 @@ impl OutputConfig { #[cfg(feature = "stats")] stats: Option<&EventStatsUpdate>, ) -> Option { let row = OutputRow::from_event(event); - if self.default_table_rows && row.is_default_table_hidden() { + if !self.events.is_empty() && !self.events.contains(&row.event_kind()) { + return None; + } + if self.events.is_empty() && self.default_table_rows && row.is_default_table_hidden() { return None; } @@ -322,17 +328,17 @@ impl OutputRow { } } - fn event_name(&self) -> &'static str { + fn event_kind(&self) -> EventKind { match self { - Self::SessionStarted(_) => "session_started", - Self::NoTestCompleted(_) => "no_test_completed", - Self::SessionClosed { .. } => "session_closed", - Self::EchoSent { .. } => "echo_sent", - Self::EchoReply(_) => "echo_reply", - Self::Loss { .. } => "loss", - Self::Duplicate { .. } => "duplicate", - Self::Late { .. } => "late", - Self::Warning { .. } => "warning", + Self::SessionStarted(_) => EventKind::SessionStarted, + Self::NoTestCompleted(_) => EventKind::NoTestCompleted, + Self::SessionClosed { .. } => EventKind::SessionClosed, + Self::EchoSent { .. } => EventKind::EchoSent, + Self::EchoReply(_) => EventKind::EchoReply, + Self::Loss { .. } => EventKind::Loss, + Self::Duplicate { .. } => EventKind::Duplicate, + Self::Late { .. } => EventKind::Late, + Self::Warning { .. } => EventKind::Warning, } } @@ -784,7 +790,7 @@ fn render_jsonl_row(row: &OutputRow, columns: &[Column], context: RenderContext< fn cell_for(row: &OutputRow, column: Column, context: RenderContext<'_>) -> Option { match column { Column::Target => context.target.map(CellValue::text), - Column::Event => Some(CellValue::text(row.event_name())), + Column::Event => Some(CellValue::text(row.event_kind().name())), Column::Seq => row.seq().map(|seq| CellValue::Unsigned(u128::from(seq))), Column::Remote => row .remote() diff --git a/crates/irtt-app/src/cmd/client/run.rs b/crates/irtt-app/src/cmd/client/run.rs index 27c6df0..2ab06e9 100644 --- a/crates/irtt-app/src/cmd/client/run.rs +++ b/crates/irtt-app/src/cmd/client/run.rs @@ -171,6 +171,7 @@ async fn run_stream_output( args.columns.as_deref(), args.header, args.verbose, + args.events.clone(), ) .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?; #[cfg(feature = "stats")] diff --git a/docs/irtt-client.md b/docs/irtt-client.md index f5ac881..9615607 100644 --- a/docs/irtt-client.md +++ b/docs/irtt-client.md @@ -313,10 +313,23 @@ Choose one of four event-row formats. The default is `table`: - `jsonl`: one JSON object per event. CSV, TSV, and JSON Lines include all columns by default for structured export; -`table` defaults to a compact column set and hides `echo_sent` rows. An -explicit `--columns` selection other than `default` shows all event rows, -including `echo_sent`; `--columns default` is equivalent to omitting the -option and keeps `echo_sent` hidden for table output. +`table` defaults to a compact column set and hides `echo_sent` events. +You can show those events by explicitly selecting them with `--events` +or by using custom columns. + +### `--events EVENTS` + +Choose which events to print with a comma-separated list, or repeat the +option to select more events. The available names are `session_started`, +`no_test_completed`, `session_closed`, `echo_sent`, `echo_reply`, `loss`, +`duplicate`, `late`, and `warning`. Without this option, the client prints +all events normally shown by the selected format. + +For CSV output containing only echo replies: + +```sh +irtt-client --events echo_reply --format csv --header never --no-stats +``` ### `--columns COLUMNS` / `-c COLUMNS`