From 5bd44dcb1e588fd5df8c02aec58353f7aa8f7d13 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 19 May 2026 09:47:09 +0300 Subject: t6 stabilize family recording integration --- internal/flags/flags.go | 2 +- internal/ior_mode_registry.go | 2 +- internal/ior_mode_test.go | 17 ++++++++++++----- internal/ior_parquet_sink.go | 7 +++---- 4 files changed, 17 insertions(+), 11 deletions(-) (limited to 'internal') diff --git a/internal/flags/flags.go b/internal/flags/flags.go index e7171ce..285569c 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -170,7 +170,7 @@ func registerFlags(fs *flag.FlagSet, cfg *Config) (tpsAttach, tpsExclude, fields fs.BoolVar(&cfg.PlainMode, "plain", false, "Enable plain CSV output mode (disable TUI)") fs.BoolVar(&cfg.FlamegraphOutput, "flamegraph", false, "Write aggregated .ior.zst output for trace/integration workflows") - fs.StringVar(&cfg.ParquetPath, "parquet", cfg.ParquetPath, "Write all traced syscall rows directly to a parquet file in headless mode (skip the TUI; incompatible with -plain, -flamegraph, --testflames, --testliveflames, and content filters)") + fs.StringVar(&cfg.ParquetPath, "parquet", cfg.ParquetPath, "Write traced syscall rows directly to a parquet file in headless mode (skip the TUI; compatible with -pid; incompatible with -plain, -flamegraph, --testflames, --testliveflames, and other content filters)") fs.StringVar(&cfg.OutputName, "name", cfg.OutputName, "Base name for .ior.zst trace output files") fs.BoolVar(&cfg.TestFlames, "testflames", false, "Run TUI with static synthetic flamegraph data for keyboard-navigation testing") fs.BoolVar(&cfg.TestLiveFlames, "testliveflames", false, "Run TUI with continuously-updating synthetic flamegraph data for live keyboard-navigation testing") diff --git a/internal/ior_mode_registry.go b/internal/ior_mode_registry.go index e262784..b0ef59f 100644 --- a/internal/ior_mode_registry.go +++ b/internal/ior_mode_registry.go @@ -214,7 +214,7 @@ func (h *headlessParquetModeHandler) validate(cfg flags.Config) error { return errors.New("-parquet and -flamegraph are mutually exclusive") } if hasHeadlessParquetContentFilters(cfg) { - return errors.New("-parquet cannot be combined with content filters (-comm, -path, -pid, -tid)") + return errors.New("-parquet cannot be combined with content filters (-comm, -path, -tid)") } return nil } diff --git a/internal/ior_mode_test.go b/internal/ior_mode_test.go index 526b9af..8a152cc 100644 --- a/internal/ior_mode_test.go +++ b/internal/ior_mode_test.go @@ -446,11 +446,18 @@ func TestValidateRunConfigRejectsParquetWithContentFilters(t *testing.T) { if err == nil { t.Fatalf("expected error for -parquet with content filters") } - if err.Error() != "-parquet cannot be combined with content filters (-comm, -path, -pid, -tid)" { + if err.Error() != "-parquet cannot be combined with content filters (-comm, -path, -tid)" { t.Fatalf("unexpected error: %v", err) } } +func TestValidateRunConfigAllowsParquetWithPIDFilter(t *testing.T) { + cfg := flags.Config{ParquetPath: "trace.parquet", PidFilter: 42} + if err := validateRunConfig(cfg); err != nil { + t.Fatalf("expected -parquet with -pid to be accepted, got %v", err) + } +} + func TestValidateRunConfigRejectsParquetWithGlobalFilter(t *testing.T) { cfg := flags.Config{ ParquetPath: "trace.parquet", @@ -462,7 +469,7 @@ func TestValidateRunConfigRejectsParquetWithGlobalFilter(t *testing.T) { if err == nil { t.Fatalf("expected error for -parquet with global filter") } - if err.Error() != "-parquet cannot be combined with content filters (-comm, -path, -pid, -tid)" { + if err.Error() != "-parquet cannot be combined with content filters (-comm, -path, -tid)" { t.Fatalf("unexpected error: %v", err) } } @@ -664,7 +671,7 @@ func TestTuiTraceStarterFromRunTraceRespectsCancel(t *testing.T) { } } -func TestHeadlessParquetTraceConfigClearsContentFilters(t *testing.T) { +func TestHeadlessParquetTraceConfigPreservesPIDAndClearsContentFilters(t *testing.T) { cfg := flags.Config{ ParquetPath: "trace.parquet", PidFilter: 1234, @@ -677,8 +684,8 @@ func TestHeadlessParquetTraceConfigClearsContentFilters(t *testing.T) { } got := headlessParquetTraceConfig(cfg) - if got.PidFilter != -1 || got.TidFilter != -1 { - t.Fatalf("pid/tid filters = %d/%d, want -1/-1", got.PidFilter, got.TidFilter) + if got.PidFilter != 1234 || got.TidFilter != -1 { + t.Fatalf("pid/tid filters = %d/%d, want 1234/-1", got.PidFilter, got.TidFilter) } if got.CommFilter != "" || got.PathFilter != "" { t.Fatalf("comm/path filters = %q/%q, want empty", got.CommFilter, got.PathFilter) diff --git a/internal/ior_parquet_sink.go b/internal/ior_parquet_sink.go index 6869e1e..f52dffa 100644 --- a/internal/ior_parquet_sink.go +++ b/internal/ior_parquet_sink.go @@ -67,24 +67,23 @@ func isHeadlessParquetMode(cfg flags.Config) bool { } // hasHeadlessParquetContentFilters reports whether cfg carries filters that are -// incompatible with headless Parquet mode (all events must be recorded unfiltered). +// incompatible with headless Parquet mode. PID filtering is still allowed so +// focused headless recordings can avoid tracing unrelated system activity. func hasHeadlessParquetContentFilters(cfg flags.Config) bool { return cfg.CommFilter != "" || cfg.PathFilter != "" || - cfg.PidFilter > 0 || cfg.TidFilter > 0 || cfg.GlobalFilter.IsActive() } // headlessParquetTraceConfig strips TUI-only flags from cfg so that the -// headless Parquet run records a clean, unfiltered event stream. +// headless Parquet run records a clean event stream, optionally scoped by PID. func headlessParquetTraceConfig(cfg flags.Config) flags.Config { out := cfg out.PlainMode = false out.FlamegraphOutput = false out.CommFilter = "" out.PathFilter = "" - out.PidFilter = -1 out.TidFilter = -1 out.GlobalFilter = globalfilter.Filter{} return out -- cgit v1.2.3