Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: remove log processing for klio/v1 api version #75

Merged
merged 1 commit into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 3 additions & 115 deletions docs/output-handling.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,10 @@
# Output handling

For CLI tools printing output to a terminal is the basic way to communicate with a user. Klio
aims to make it easier for you to implement this mode of communication without using any
language-specific framework.

Each command run by Klio may write output either to stdout or stderr. By default, Klio captures those
streams and processes them line by line. Each line is prefixed with a log-level. You can control how command
output is handled within Klio by prepending it with special control sequences.

This default mode of processing outputs is called 'line mode'. There is also an alternative - 'raw mode'.
It disables most of the output processing and simply passes things through.

## Controlling output using escape sequences

A command can control how its output is handled using [ANSI escape codes][]. Klio uses APC
sequences that are stripped from the output by most of the terminal emulators. Each such escape
sequence has the following format:

```text
\033_<command-name> <json-encoded-parameters>\033\\
```

Keep in mind that each stream (stdout and stderr) is handled separately. Sending control sequence to
stdout is not going to affect stderr.

A more detailed description of this format is available
[at the end of this document](#escape-sequences-grammar). If you don't want to dive into the
nitty-gritty details of grammar, simply follow the examples or use one of the libraries.

## Line mode

By default, Klio is working in the line mode, in which each line is prefixed with log level and
tags:

```text
[INFO][TAG][ANOTHER TAG] original output printed by command
```

Lines that have a log-level lower than a minimum specified by a user ('info' by default) are stripped
from the output.
For CLI tools printing output to a terminal is the basic way to communicate with a user. Klio injects `KLIO_LOG_LEVEL` environment varianble into each run subcommand. Its value is equal to the currently set log level for Klio command. You can use the variable to dynamically set the log level in your subcommand. If your subcommand is written in Go, you can use the logger exported in `github.com/g2a-com/klio/pkg/log`.

### Log levels

Klio assigns each line a log level. If you don't set it explicitly, by default, all lines printed to
the stdout are marked with the 'info' level and lines printed to the stderr are marked with the 'error' level.
You may change log level by sending `klio_log_level` command. You have one of the following log levels
to pick from:
Log levels used by Klio and their meaning is as follows:

| Log level | Description |
| --------- | ---------------------------------------------------------------------------------------- |
Expand All @@ -55,75 +14,4 @@ to pick from:
| info | Generally useful information (_things happen_) |
| verbose | More granular but still useful information |
| debug | Information helpful for command developers |
| spam | \*Give me **everything\*** |

**Examples**

- `\033_klio_log_level "spam"\033\\` – sets log level to spam
- `\033_klio_log_level "warn"\033\\` – sets log level to warn

### Tags

Using `klio_tags` command you may specify multiple tags which will be added to each log line. You may
use these tags to distinguish various steps of command execution.

**Examples**

- `\033_klio_tags ["foo", "bar"]\033\\` – sets tags to `[FOO][BAR]`
- `\033_klio_tags []\033\\` – disables tags

## Raw mode

Raw mode neither buffers nor modifies output. It simply passes it further unchanged. Use it if you
want to implement a spinner, a progress bar or even [a text-based user interface][]. In order to
enable the raw mode, use `klio_mode` command.

**Examples**

- `\033_klio_mode "raw"\033\\` – enables raw mode
- `\033_klio_mode "line"\033\\` – goes back to line mode

## Resetting

You can reset mode, log level, and tags to default using `klio_reset` command.

**Examples**

- `\033_klio_reset\033\\` - resets to default settings

## Escape sequences grammar

```abnf
control-sequence = escape underscore command escape backslash

; Commands
command = log-level-command / tags-command / mode-command / reset-command
log-level-command = "klio_log_level" space quotation-mark log-level quotation-mark
tags-command = "klio_tags" space strings-array
mode-command = "klio_mode" space quotation-mark mode quotation-mark
reset-command = "klio_reset"

; Enums
log-level = "spam" / "debug" / "verbose" / "info" / "warn" / "error" / "fatal"
mode = "line" / "raw"

; Supported subset of JSON
strings-array = begin-array [ string *( value-separator string ) ] end-array
string = quotation-mark *char quotation-mark
char = %x20-21 / %x23-5B / %x5D-10FFFF / backslash (%x22 / %x5C / %x2F / %x62 / %x66 / %x6E / %x72 / %x74 / %x75 4hex-digit)
begin-array = *space "[" *space
end-array = *space "]" *space
value-separator = *space "," *space

; Other
escape = %x1B
backslash = "\"
underscore = "_"
space = " "
quotation-mark = %x22
hex-digit = %x30–39 / %x41-46 / %x61-66
```

[text-based user interface]: https://en.wikipedia.org/wiki/Text-based_user_interface
[ANSI escape codes]: https://en.wikipedia.org/wiki/ANSI_escape_code

| spam | \*Give me **everything\*** |
29 changes: 1 addition & 28 deletions internal/cmd/root/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,9 @@ func loadExternalCommand(ctx context.CLIContext, rootCmd *cobra.Command, dep dep
var wg sync.WaitGroup

switch cmdConfig.APIVersion {
case "g2a-cli/v1beta1", "g2a-cli/v1beta2", "g2a-cli/v1beta3", "g2a-cli/v1beta4":
case "g2a-cli/v1beta1", "g2a-cli/v1beta2", "g2a-cli/v1beta3", "g2a-cli/v1beta4", "klio/v1":
externalCmd.Stdout = os.Stdout
externalCmd.Stderr = os.Stderr
case "klio/v1":
setupLogProcessor(externalCmd, &wg)
default:
log.Warnf(
"Cannot load command %s since it requires an unsupported API Version to run (%s). Try to update the %s and try again.",
Expand Down Expand Up @@ -213,28 +211,3 @@ func getUpdateMessage(ctx context.CLIContext, dep dependency.DependenciesIndexEn
msg <- fmt.Sprintf("New version of this command is available, but it may introduce some BREAKING CHANGES. Please consider updating it using:\n %s", getInstallCmd(update.Breaking))
}
}

func setupLogProcessor(cmd *exec.Cmd, wg *sync.WaitGroup) {
stdoutPipe, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
stderrPipe, err := cmd.StderrPipe()
if err != nil {
log.Fatal(err)
}

wg.Add(1)
stdoutLogProcessor := log.NewProcessor(log.InfoLevel, log.DefaultLogger, stdoutPipe)
go func() {
stdoutLogProcessor.Process()
wg.Done()
}()

wg.Add(1)
stderrLogProcessor := log.NewProcessor(log.ErrorLevel, log.ErrorLogger, stderrPipe)
go func() {
stderrLogProcessor.Process()
wg.Done()
}()
}
Loading
Loading