From f54481ee8cc60c6feba2cba9c7dc5d7ae4c877b8 Mon Sep 17 00:00:00 2001 From: Caroline Chen <324939130+caroline-db@users.noreply.github.com> Date: Wed, 9 Sep 2026 16:22:52 +0000 Subject: [PATCH] experimental: rename air logs flag to tail --- acceptance/experimental/air/help/output.txt | 2 +- .../experimental/air/logs-download/output.txt | 6 ++--- .../experimental/air/logs-download/script | 4 ++-- acceptance/experimental/air/logs/output.txt | 20 ++++++++-------- acceptance/experimental/air/logs/script | 16 ++++++------- experimental/air/cmd/logmlflow.go | 2 +- experimental/air/cmd/logs.go | 24 +++++++++---------- experimental/air/cmd/logs_test.go | 14 ++++++----- experimental/air/cmd/logstream.go | 8 +++---- 9 files changed, 49 insertions(+), 47 deletions(-) diff --git a/acceptance/experimental/air/help/output.txt b/acceptance/experimental/air/help/output.txt index f2ab58d0a38..59d29c91322 100644 --- a/acceptance/experimental/air/help/output.txt +++ b/acceptance/experimental/air/help/output.txt @@ -59,10 +59,10 @@ Usage: Flags: --download-to string Download all logs to this directory instead of printing -h, --help help for logs - --lines int For completed runs, print the last N lines (default 10000) --minutes int Fetch only logs from the last N minutes --node int Fetch logs from this node --retry int View logs from a specific retry attempt; -1 means latest (default -1) + --tail int For completed runs, print the last N log lines (default 10000) Global Flags: --debug enable debug logging diff --git a/acceptance/experimental/air/logs-download/output.txt b/acceptance/experimental/air/logs-download/output.txt index d3458758c42..202f1094fd5 100644 --- a/acceptance/experimental/air/logs-download/output.txt +++ b/acceptance/experimental/air/logs-download/output.txt @@ -9,8 +9,8 @@ Error: invalid --node 5: run has 2 node(s), indexed 0 to 1 Exit code: 1 -=== download-to cannot be combined with --lines ->>> [CLI] experimental air logs 123 --download-to dl-logs --lines 50 -Error: --download-to writes complete logs, so it cannot be combined with --lines or --minutes +=== download-to cannot be combined with --tail +>>> [CLI] experimental air logs 123 --download-to dl-logs --tail 50 +Error: --download-to writes complete logs, so it cannot be combined with --tail or --minutes Exit code: 1 diff --git a/acceptance/experimental/air/logs-download/script b/acceptance/experimental/air/logs-download/script index 027b5c89528..b90fbbdb850 100644 --- a/acceptance/experimental/air/logs-download/script +++ b/acceptance/experimental/air/logs-download/script @@ -8,5 +8,5 @@ errcode trace $CLI experimental air logs 123 --download-to dl-logs title "download-to with an out-of-range node is rejected" errcode trace $CLI experimental air logs 123 --download-to dl-logs --node 5 -title "download-to cannot be combined with --lines" -errcode trace $CLI experimental air logs 123 --download-to dl-logs --lines 50 +title "download-to cannot be combined with --tail" +errcode trace $CLI experimental air logs 123 --download-to dl-logs --tail 50 diff --git a/acceptance/experimental/air/logs/output.txt b/acceptance/experimental/air/logs/output.txt index 9ea8deedc5e..1a1027c8be4 100644 --- a/acceptance/experimental/air/logs/output.txt +++ b/acceptance/experimental/air/logs/output.txt @@ -18,12 +18,12 @@ step 1 step 2 CUDA out of memory -=== logs with --lines ->>> [CLI] experimental air logs 123 --lines 1 +=== logs with --tail +>>> [CLI] experimental air logs 123 --tail 1 CUDA out of memory -=== logs with --lines 0 prints nothing ->>> [CLI] experimental air logs 123 --lines 0 +=== logs with --tail 0 prints nothing +>>> [CLI] experimental air logs 123 --tail 0 No logs available for run 123. Run terminated in state SUCCESS === logs from a specific retry @@ -32,21 +32,21 @@ step 1 step 2 CUDA out of memory -=== logs --lines and --minutes are mutually exclusive ->>> [CLI] experimental air logs 123 --lines 100 --minutes 30 -Error: cannot combine --lines with --minutes: --lines tails by line count, --minutes by time window +=== logs --tail and --minutes are mutually exclusive +>>> [CLI] experimental air logs 123 --tail 100 --minutes 30 +Error: cannot combine --tail with --minutes: --tail selects by line count, --minutes by time window Exit code: 1 -=== logs --lines and --minutes are mutually exclusive (json) ->>> [CLI] experimental air logs 123 --lines 100 --minutes 30 -o json +=== logs --tail and --minutes are mutually exclusive (json) +>>> [CLI] experimental air logs 123 --tail 100 --minutes 30 -o json { "v": 1, "ts": "[TIMESTAMP]", "error": { "code": "INVALID_ARGS", "kind": "PERMANENT", - "message": "cannot combine --lines with --minutes: --lines tails by line count, --minutes by time window", + "message": "cannot combine --tail with --minutes: --tail selects by line count, --minutes by time window", "retryable": false } } diff --git a/acceptance/experimental/air/logs/script b/acceptance/experimental/air/logs/script index 167ee331f01..1462e493566 100644 --- a/acceptance/experimental/air/logs/script +++ b/acceptance/experimental/air/logs/script @@ -7,20 +7,20 @@ trace $CLI experimental air logs 123 -o json title "logs with --minutes" trace $CLI experimental air logs 123 --minutes 30 -title "logs with --lines" -trace $CLI experimental air logs 123 --lines 1 +title "logs with --tail" +trace $CLI experimental air logs 123 --tail 1 -title "logs with --lines 0 prints nothing" -trace $CLI experimental air logs 123 --lines 0 +title "logs with --tail 0 prints nothing" +trace $CLI experimental air logs 123 --tail 0 title "logs from a specific retry" trace $CLI experimental air logs 123 --retry 0 -title "logs --lines and --minutes are mutually exclusive" -errcode trace $CLI experimental air logs 123 --lines 100 --minutes 30 +title "logs --tail and --minutes are mutually exclusive" +errcode trace $CLI experimental air logs 123 --tail 100 --minutes 30 -title "logs --lines and --minutes are mutually exclusive (json)" -errcode trace $CLI experimental air logs 123 --lines 100 --minutes 30 -o json +title "logs --tail and --minutes are mutually exclusive (json)" +errcode trace $CLI experimental air logs 123 --tail 100 --minutes 30 -o json title "invalid run id" errcode trace $CLI experimental air logs notanumber diff --git a/experimental/air/cmd/logmlflow.go b/experimental/air/cmd/logmlflow.go index 239197fab89..c305fc10b0b 100644 --- a/experimental/air/cmd/logmlflow.go +++ b/experimental/air/cmd/logmlflow.go @@ -79,7 +79,7 @@ var artifactDownloadClient = &http.Client{ // per-node log directory, lists the chunk files, and walks them newest-first // until it has the requested tail, then prints oldest-first. // -// The tail length is --lines, else the default cap. MLflow chunks are not +// The tail length is --tail, else the default cap. MLflow chunks are not // time-indexed, so --minutes cannot restrict the window here. func mlflowLogFallback(ctx context.Context, w *databricks.WorkspaceClient, out io.Writer, req logRequest, status logRunStatus) (bool, error) { if req.windowMinutes > 0 { diff --git a/experimental/air/cmd/logs.go b/experimental/air/cmd/logs.go index 6a6189a8999..2ffa2347c83 100644 --- a/experimental/air/cmd/logs.go +++ b/experimental/air/cmd/logs.go @@ -21,7 +21,7 @@ import ( func newLogsCommand() *cobra.Command { var ( node int - lines int + tail int minutes int retry int downloadTo string @@ -36,7 +36,7 @@ func newLogsCommand() *cobra.Command { } cmd.Flags().IntVar(&node, "node", 0, "Fetch logs from this node") - cmd.Flags().IntVar(&lines, "lines", 0, "For completed runs, print the last N lines (default 10000)") + cmd.Flags().IntVar(&tail, "tail", 0, "For completed runs, print the last N log lines (default 10000)") cmd.Flags().IntVar(&minutes, "minutes", 0, "Fetch only logs from the last N minutes") cmd.Flags().IntVar(&retry, "retry", -1, "View logs from a specific retry attempt; -1 means latest") cmd.Flags().StringVar(&downloadTo, "download-to", "", "Download all logs to this directory instead of printing") @@ -64,20 +64,20 @@ func newLogsCommand() *cobra.Command { // A download always writes the full log, so a tail or time window would be // silently dropped. - if downloadTo != "" && (cmd.Flags().Changed("lines") || minutes > 0) { + if downloadTo != "" && (cmd.Flags().Changed("tail") || minutes > 0) { return renderError(ctx, cmd, "INVALID_ARGS", "PERMANENT", false, - errors.New("--download-to writes complete logs, so it cannot be combined with --lines or --minutes")) + errors.New("--download-to writes complete logs, so it cannot be combined with --tail or --minutes")) } - // --lines (line tail) and --minutes (time window) answer the same question + // --tail (line tail) and --minutes (time window) answer the same question // two ways, so reject both together rather than silently honoring one. - if lines > 0 && minutes > 0 { + if tail > 0 && minutes > 0 { return renderError(ctx, cmd, "INVALID_ARGS", "PERMANENT", false, - errors.New("cannot combine --lines with --minutes: --lines tails by line count, --minutes by time window")) + errors.New("cannot combine --tail with --minutes: --tail selects by line count, --minutes by time window")) } - if lines < 0 { + if tail < 0 { return renderError(ctx, cmd, "INVALID_ARGS", "PERMANENT", false, - fmt.Errorf("invalid --lines %d: must be positive", lines)) + fmt.Errorf("invalid --tail %d: must be positive", tail)) } if minutes < 0 { return renderError(ctx, cmd, "INVALID_ARGS", "PERMANENT", false, @@ -98,11 +98,11 @@ func newLogsCommand() *cobra.Command { fmt.Errorf("invalid JOB_RUN_ID %q: must be a positive integer", args[0])) } - // -1 signals "unset" (use the default cap); an explicit --lines 0 stays 0 + // -1 signals "unset" (use the default cap); an explicit --tail 0 stays 0 // and prints nothing. tailLines := -1 - if cmd.Flags().Changed("lines") { - tailLines = lines + if cmd.Flags().Changed("tail") { + tailLines = tail } // Only the streaming path prints resume guidance, so only it catches the diff --git a/experimental/air/cmd/logs_test.go b/experimental/air/cmd/logs_test.go index e459779bb7a..c641bfe5e4e 100644 --- a/experimental/air/cmd/logs_test.go +++ b/experimental/air/cmd/logs_test.go @@ -30,6 +30,8 @@ func TestLogsCommandShape(t *testing.T) { review := cmd.Flags().Lookup("review") require.NotNil(t, review) assert.True(t, review.Hidden) + assert.NotNil(t, cmd.Flags().Lookup("tail")) + assert.Nil(t, cmd.Flags().Lookup("lines")) } // runLogsCmd invokes the logs command's RunE with the given flags against a mock @@ -55,16 +57,16 @@ func TestLogsFlagValidation(t *testing.T) { wantMsg string }{ { - name: "lines and minutes are mutually exclusive", + name: "tail and minutes are mutually exclusive", args: []string{"5"}, - flags: map[string]string{"lines": "100", "minutes": "10"}, - wantMsg: "cannot combine --lines with --minutes", + flags: map[string]string{"tail": "100", "minutes": "10"}, + wantMsg: "cannot combine --tail with --minutes", }, { - name: "negative lines rejected", + name: "negative tail rejected", args: []string{"5"}, - flags: map[string]string{"lines": "-1"}, - wantMsg: "invalid --lines", + flags: map[string]string{"tail": "-1"}, + wantMsg: "invalid --tail", }, { name: "negative minutes rejected", diff --git a/experimental/air/cmd/logstream.go b/experimental/air/cmd/logstream.go index ef5197c24ed..fd2beae59ee 100644 --- a/experimental/air/cmd/logstream.go +++ b/experimental/air/cmd/logstream.go @@ -23,7 +23,7 @@ const ( // before falling back to MLflow. maxTransientFailures = 5 // defaultCompletedRunTailLines caps a completed run's output when neither - // --lines nor --minutes is set. + // --tail nor --minutes is set. defaultCompletedRunTailLines = 10000 // seenRecordsCap bounds the dedup set, evicting oldest-inserted entries first. seenRecordsCap = 100000 @@ -89,7 +89,7 @@ type logRequest struct { // windowMinutes, when > 0, restricts the fetch to the last N minutes. windowMinutes int // tailLines caps a completed run's output to the last N lines. Negative means - // --lines was unset (use the default cap); 0 prints nothing. + // --tail was unset (use the default cap); 0 prints nothing. tailLines int // downloadTo, when set, writes logs to that directory instead of stdout. downloadTo string @@ -462,8 +462,8 @@ func (st *bricklensStreamer) drainStatic(toSec int64) (bool, error) { } // tailTarget is the number of lines a tail keeps. A negative tailLines means -// --lines was unset, so use the default cap; 0 or more is taken literally (an -// explicit --lines 0 prints nothing). +// --tail was unset, so use the default cap; 0 or more is taken literally (an +// explicit --tail 0 prints nothing). func (req logRequest) tailTarget() int { if req.tailLines < 0 { return defaultCompletedRunTailLines