mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
app/vlogscli: allow toggling wrapping long lines with \wrap_long_lines command
This commit is contained in:
parent
2febd00bb3
commit
f55791f20b
3 changed files with 25 additions and 6 deletions
|
@ -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},
|
||||||
})
|
})
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)`.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue