Files
heads/doc/logging.md
Jonathon Hall 42940e4d2f logging: Add NOTE level, clarify warn level, refer to doc in functions
Add NOTE level between INFO and warn.  NOTE is appropriate for context
that is required to understand confusing/surprising behavior in Heads,
but that does not indicate a problem.

Clarify warn level based on discussion.

Fix LOG output in tables, LOG actually does go to the debug log
currently in any configuration.

Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2025-04-15 10:26:06 -04:00

9.5 KiB

Heads Debug Logging

Heads produces debug logging to aid development and troubleshooting.

Logging is produced in scripts at a log level. Users can set an output level that controls how much output they see on the screen.

Log Levels

In order from "most verbose" to "least verbose":

LOG > TRACE > DEBUG > INFO > (console) > NOTE > warn

("console" level output is historical and should be replaced with INFO.)

LOG

LOG is for very detailed output or output with uncontrolled length. It never goes to the screen, this always goes to the log file. Usually, we dump outputs of commands like 'lsblk', 'lsusb', 'gpg --list-keys', etc. at LOG level (using DO_WITH_DEBUG or SINK_LOG), so we can tell the state of the system from a log submitted by a user. We rarely want these on the console as they usually hide more relevant output with information that we already know.

Use this in situations like:

  • Dumping information about the state of the system for debugging. The output doesn't indicate any specific action/decision in Heads or a problem, it's just state relevant for troubleshooting the rest of the log.
  • Tracing something that might be very long (including "we don't know how long this will be", even if it's sometimes short). Very long output isn't useful on the console, since you can't scroll back, and it hides more important information.
  • The output is intended for debugging a specific topic, and usually unintersting otherwise. We want to be able to turn up output to DEBUG/TRACE when working on any topic without excessively filling the console with every topic's detailed output.

TRACE

TRACE is for following execution flow through Heads. (TRACE_FUNC logs the current source location at TRACE level, you can use this when entering a function or script, this is much more common than using TRACE directly.)

You can also use TRACE to show parameter values to scripts or functions. Since TRACE is for execution flow, show the unprocessed parameters as provided by the caller, not an interpreted version. (This is uncommon though as it is very verbose, and we can also capture interesting call sites with DO_WITH_DEBUG.)

You can invoke TRACE to show specific execution flow when needed, but if you are tracing the result of a decision, consider using DEBUG instead.

Use this in situations like:

  • Following control flow - use TRACE_FUNC when entering a script or function
  • Showing the parameters used to invoke a script/function, when they are especially relevant and not excessively verbose

DEBUG

DEBUG is for most log information that is relevant if you are a Heads developer.

Use DEBUG to highlight the decisions made in script logic, and the information that affects those decisions. Generally, focus on decision points (if, else, case, while, for, etc.), because we can keep following straight-line execution without further tracing.

Decision points usually capture program behavior the best. Show the information that is about to influence a decision (DEBUG "Found ${#DEVS[@]} block devices: to check for LUKS:" "${DEVS[@]}") and/or the results of the decision (DEBUG "${DEVS[$i]} is not a LUKS device, ignore it).

Use DO_WITH_DEBUG to capture a particular command execution to the debug log. The command and its arguments are captured at DEBUG level (as they usually indicate the decisions the command will make), and the command's stdout/stderr are captured at LOG level. See DO_WITH_DEBUG for examples of usage.

Use this in situations like:

  • Showing information derived or obtained that will influence logical decisions and actions
  • Showing the result of decisions and the reasons for them

INFO

INFO is for contextual information that may be of interest to end users, but that is not required for use of Heads. Users can control whether this is displayed on the console.

Users might use this to troubleshoot Heads configuration or behavior, but this should not require knowledge of Heads implementation or developer experience.

For example:

  • "Why can't I enable USB keyboard support?" INFO "Not showing USB keyboard option, USB keyboard is always enabled for this board"
  • "Why isn't Heads booting automatically?" INFO "Not booting automatically, automatic boot is disabled in user settings"
  • "Why didn't Heads prompt me for a password?" INFO "Password has not been changed, using default")

These do not include highly technical details. They can include configuration values or context, but they should refer to configuration settings using the user-facing names in the configuration menus.

Use this in situations like:

  • Showing very high level decision-making information, which is reasonably understandable for users not familiar with Heads implementation
  • Explaining a behavior that could reasonably be unexpected for some users

console

This level is historical, use INFO for this. It is documented as there are still some occurrences in Heads, usually echo, echo >&2, or echo >/dev/console, each intended to produce output directly on the console. The intent is the same as INFO.

(This is different from echo used to produce output that might be captured by a caller, which is not logging at all.)

Avoid using this, and change existing console output to INFO or another level.

NOTE

NOTE is for contextual information explaining something that is likely to be unexpected or confusing to users new to Heads.

Unlike INFO, it cannot be hidden. Use this only if the behavior is likely to be unexpected or confusing to many users. If it is only possibly unexpected or uncommon that it is confusing, consider INFO instead.

Do not overuse this above INFO. Adding too much output at NOTE causes users to ignore it, as there is too much output.

For example:

  • "Rebooting in 3 seconds to enable booting default boot option". Users probably don't expect the firmware to reboot to accomplish this behavior, this is unique to Heads. Without a message justifying the reboot, it would likely appear that the firmware faulted and reset unexpectedly.
  • "Your GPG User PIN, followed by Enter key will be required [...]". GPG prompts are very confusing to users unfamiliar with GPG (which is most users).

warn

warn is for output that indicates a problem. We think the user should act on it, but we are able to continue, possibly with degraded functionality. (This level and the utility function are lowercase, as they predate the other levels.)

This is apppriate when all of the following are true:

  • there is a likely problem
  • we are able to continue, possibly with degraded functionality
  • the warning is actionable - there is a reasonable change that could silence the warning if this is intentional

Do not overuse this. Overuse of this level causes user to become accustomed to ignoring warnings. This level only has value as long as it does not occur frequently, so users will notice warnings.

Warnings must indicate a likely problem. (Not a rare or remote possibility of a problem.)

Warnings are only appropriate if we're able to continue operating. If we can't, consider prompting the user instead, since we cannot do what they asked.

Warnings must be actionable. Only warn if there is a reasonable change the user can make to avoid the warning.

For example:

  • Warning when using default passphrases that are completely insecure is reasonable - the user has no security, and if they want that, they should use Basic mode.
  • Warning when an unknown variable appears in config.user is not reasonable - there's no reasonable way for the user to address this.

Output Levels

Users can choose one of three output levels for extra console information.

  • None - Show no extra output. Only warnings appear on console. (Some 'console' level output appears that has not been addressed yet.)
  • Info - Show information about operations in Heads. (INFO and below.)
  • Debug - Show detailed information suitable for debugging Heads. (TRACE and below.) Log file captures all levels.

TODO: Document what happens for kernel messages too. This is more complex though since it is influenced by the board's config and user config differently (maybe we should improve that.)

TODO: Document the variables that control these levels

None - no extra output

Sink LOG TRACE DEBUG INFO console NOTE warn
Console (via /dev/kmsg) Yes* Yes Yes
/tmp/debug.log Yes
  • Most 'console' output should be changed to INFO, that content isn't intended to be displayed in quiet mode

No extra output is specified with:

CONFIG_DEBUG_OUTPUT=n
CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=n
CONFIG_QUIET_MODE=y

Info

Sink LOG TRACE DEBUG INFO console NOTE warn
Console (via /dev/kmsg) Yes Yes Yes Yes
/tmp/debug.log Yes

Info output is enabled with:

CONFIG_DEBUG_OUTPUT=n
CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=n
CONFIG_QUIET_MODE=n

Debug

Sink LOG TRACE DEBUG INFO console NOTE warn
Console (via /dev/kmsg) Yes Yes Yes Yes Yes Yes
/tmp/debug.log Yes Yes Yes Yes Yes Yes Yes

Debug output is enabled with:

CONFIG_DEBUG_OUTPUT=y
CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=y
CONFIG_QUIET_MODE=n