RFD: configuring output

Hi all! This is meant to be a general spot for describing how users tell Syft, Grype, and friends what output goes where. This is meant to start as a discussion and morph into something more authoritative we can link to in PR comments or whatever after the discussion concludes.

First up, some terms! There are 3 kinds of output that tools make:

  1. program output - this is the SBOM for Syft, the list of matches for grype, etc. By default, it goes to stdout in table format.
  2. Terminal UI output - this is fancy stuff like spinners, progress bars, realtime updating counts of packages, etc. By default, it goes to stderr if stderr is a TTY and is discarded otherwise.
  3. Logging output - this is logging. It has a level (error/warn/info/debug/trace) and a destination. By default the level is warn (meaning less severe messages are dropped) and the destination is stderr.

Then, there four configuration knobs:

  1. quiet e.g. a user has passed --quiet. This should have the effect that nothing is going to the terminal besides program output.
  2. Verbosity/log level determine what the log level is. For example SYFT_LOG_LEVEL=debug in the environment or -vv on the command line should set the logger to keep messages at debug and above.
  3. Presence/absence of a TTY - tools should only attempt to do fancy terminal things if they are in a fancy terminal. No point in filling GitHub actions log output with control characters meant to redraw progress bars, for example.
  4. A log file config, e.g. SYFT_LOG_FILE=/tmp/log.txt. This is a path on the local file system that will log to that path in addition to sderr.

None of these 4 affect program output, but rather logging and TUI output.

Here’s a table showing how these settings interact (first row is default behavior):

TTY Present Quiet Log File Set Logging Destination TUI Destination
Yes No No stderr stderr
Yes No Yes stderr and log file stderr
Yes Yes No discard discard
Yes Yes Yes log file only discard
No No No stderr discard
No No Yes stderr and log file discard
No Yes No discard discard
No Yes Yes log file only discard

Note that verbosity / log level is not in this table. That’s because verbosity / log level directly sets the level the logger will print, but this table describes where. In other words, if you’re in a row on this table where logs go to a file, and you pass -vvv, you get trace logs in that file.

Program output is much simpler. By default, program output goes to stdout in table format. Other formats can be specified like -o json to print JSON to stdout, or -o json=/some/path.json to save the JSON file to a path without printing it.

One question I have right off the bat is: Should setting log file prevent messages from the logger from going to stderr?

Let’s discuss a bit and then decide if this is the direction we want to commit to.

Here’s a PR where this came up: Fix: still warn on zero verbosity by willmurphyscode · Pull Request #68 · anchore/clio · GitHub

Note that the PR doesn’t fully implement this, it just fixes a specific bug.

If merged as it stands now, it will also make setting NO_TTY=1 cause our tools to behave as if no TTY is available, even if one is. If nothing else, that will make it a lot easier to test how things like this are working.