app/vlogscli: allow toggling wrapping long lines with \wrap_long_lines command

This commit is contained in:
Aliaksandr Valialkin 2024-11-08 17:08:32 +01:00 committed by f41gh7
parent 0e9767cd77
commit 29c3a13836
No known key found for this signature in database
GPG key ID: 4558311CF775EC72
3 changed files with 25 additions and 6 deletions

View file

@ -17,7 +17,7 @@ func isTerminal() bool {
return isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stderr.Fd()) return isatty.IsTerminal(os.Stdout.Fd()) && isatty.IsTerminal(os.Stderr.Fd())
} }
func readWithLess(r io.Reader) error { func readWithLess(r io.Reader, wrapLongLines bool) error {
if !isTerminal() { if !isTerminal() {
// Just write everything to stdout if no terminal is available. // Just write everything to stdout if no terminal is available.
_, err := io.Copy(os.Stdout, r) _, err := io.Copy(os.Stdout, r)
@ -48,7 +48,11 @@ func readWithLess(r io.Reader) error {
if err != nil { if err != nil {
return fmt.Errorf("cannot find 'less' command: %w", err) return fmt.Errorf("cannot find 'less' command: %w", err)
} }
p, err := os.StartProcess(path, []string{"less", "-F", "-X"}, &os.ProcAttr{ opts := []string{"less", "-F", "-X"}
if !wrapLongLines {
opts = append(opts, "-S")
}
p, err := os.StartProcess(path, opts, &os.ProcAttr{
Env: append(os.Environ(), "LESSCHARSET=utf-8"), Env: append(os.Environ(), "LESSCHARSET=utf-8"),
Files: []*os.File{pr, os.Stdout, os.Stderr}, Files: []*os.File{pr, os.Stdout, os.Stderr},
}) })

View file

@ -91,6 +91,7 @@ func runReadlineLoop(rl *readline.Instance, incompleteLine *string) {
} }
outputMode := outputModeJSONMultiline outputMode := outputModeJSONMultiline
wrapLongLines := false
s := "" s := ""
for { for {
line, err := rl.ReadLine() line, err := rl.ReadLine()
@ -99,7 +100,7 @@ func runReadlineLoop(rl *readline.Instance, incompleteLine *string) {
case io.EOF: case io.EOF:
if s != "" { if s != "" {
// This is non-interactive query execution. // This is non-interactive query execution.
executeQuery(context.Background(), rl, s, outputMode) executeQuery(context.Background(), rl, s, outputMode, wrapLongLines)
} }
return return
case readline.ErrInterrupt: case readline.ErrInterrupt:
@ -163,6 +164,18 @@ func runReadlineLoop(rl *readline.Instance, incompleteLine *string) {
s = "" s = ""
continue continue
} }
if s == `\wrap_long_lines` {
if wrapLongLines {
wrapLongLines = false
fmt.Fprintf(rl, "wrapping of long lines is disabled\n")
} else {
wrapLongLines = true
fmt.Fprintf(rl, "wrapping of long lines is enabled\n")
}
historyLines = pushToHistory(rl, historyLines, s)
s = ""
continue
}
if line != "" && !strings.HasSuffix(line, ";") { if line != "" && !strings.HasSuffix(line, ";") {
// Assume the query is incomplete and allow the user finishing the query on the next line // Assume the query is incomplete and allow the user finishing the query on the next line
s += "\n" s += "\n"
@ -172,7 +185,7 @@ func runReadlineLoop(rl *readline.Instance, incompleteLine *string) {
// Execute the query // Execute the query
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
executeQuery(ctx, rl, s, outputMode) executeQuery(ctx, rl, s, outputMode, wrapLongLines)
cancel() cancel()
historyLines = pushToHistory(rl, historyLines, s) historyLines = pushToHistory(rl, historyLines, s)
@ -259,13 +272,14 @@ func printCommandsHelp(w io.Writer) {
\m - multiline json output mode \m - multiline json output mode
\c - compact output \c - compact output
\logfmt - logfmt output mode \logfmt - logfmt output mode
\wrap_long_lines - toggles wrapping long lines
\tail <query> - live tail <query> results \tail <query> - live tail <query> results
See https://docs.victoriametrics.com/victorialogs/querying/vlogscli/ for more details See https://docs.victoriametrics.com/victorialogs/querying/vlogscli/ for more details
`) `)
} }
func executeQuery(ctx context.Context, output io.Writer, qStr string, outputMode outputMode) { func executeQuery(ctx context.Context, output io.Writer, qStr string, outputMode outputMode, wrapLongLines bool) {
if strings.HasPrefix(qStr, `\tail `) { if strings.HasPrefix(qStr, `\tail `) {
tailQuery(ctx, output, qStr, outputMode) tailQuery(ctx, output, qStr, outputMode)
return return
@ -279,7 +293,7 @@ func executeQuery(ctx context.Context, output io.Writer, qStr string, outputMode
_ = respBody.Close() _ = respBody.Close()
}() }()
if err := readWithLess(respBody); err != nil { if err := readWithLess(respBody, wrapLongLines); err != nil {
fmt.Fprintf(output, "error when reading query response: %s\n", err) fmt.Fprintf(output, "error when reading query response: %s\n", err)
return return
} }

View file

@ -18,6 +18,7 @@ according to [these docs](https://docs.victoriametrics.com/victorialogs/quicksta
* FEATURE: [`join` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#join-pipe): add an ability to add prefix to all the log field names from the joined query, by using `| join by (<by_fields>) (<query>) prefix "some_prefix"` syntax. * FEATURE: [`join` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#join-pipe): add an ability to add prefix to all the log field names from the joined query, by using `| join by (<by_fields>) (<query>) prefix "some_prefix"` syntax.
* FEATURE: [`_time` filter](https://docs.victoriametrics.com/victorialogs/logsql/#time-filter): allow specifying offset without time range. For example, `_time:offset 1d` matches all the logs until `now-1d` in the [`_time` field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#time-field). This is useful when building graphs for time ranges with some offset in the past. * FEATURE: [`_time` filter](https://docs.victoriametrics.com/victorialogs/logsql/#time-filter): allow specifying offset without time range. For example, `_time:offset 1d` matches all the logs until `now-1d` in the [`_time` field](https://docs.victoriametrics.com/victorialogs/keyconcepts/#time-field). This is useful when building graphs for time ranges with some offset in the past.
* FEATURE: [`/select/logsql/tail` HTTP endpoint](): support for `offset` query arg, which can be used for delayed emission of matching logs during live tailing. Thanks to @Fusl for the initial idea and implementation in [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7428). * FEATURE: [`/select/logsql/tail` HTTP endpoint](): support for `offset` query arg, which can be used for delayed emission of matching logs during live tailing. Thanks to @Fusl for the initial idea and implementation in [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7428).
* FEATURE: [vlogscli](https://docs.victoriametrics.com/victorialogs/querying/vlogscli/): allow enabling and disabling wrapping of long lines, which do not fit screen width, with `\wrap_long_lines` command.
* BUGFIX: [HTTP querying APIs](https://docs.victoriametrics.com/victorialogs/querying/#http-api): properly take into account the `end` query arg when calculating time range for [`_time:duration` filter](https://docs.victoriametrics.com/victorialogs/logsql/#time-filter). Previously the `_time:duration` filter was treated as `_time:[now-duration, now)`, while it should be treated as `_time:[end-duration, end)`. * BUGFIX: [HTTP querying APIs](https://docs.victoriametrics.com/victorialogs/querying/#http-api): properly take into account the `end` query arg when calculating time range for [`_time:duration` filter](https://docs.victoriametrics.com/victorialogs/logsql/#time-filter). Previously the `_time:duration` filter was treated as `_time:[now-duration, now)`, while it should be treated as `_time:[end-duration, end)`.