Logging & output#
Emitting messages at the right level and framing a long-running command’s output.
Log at the right level#
Narrate a command with knit_trace/debug/info/warning/error/critical and control verbosity with KNIT_LOG_LEVEL or knit_log_set_level.
APIs: knit_trace, knit_debug, knit_info, knit_warning, knit_error, knit_critical, knit_fatal, knit_log_set_level, KNIT_LOG_LEVEL
Knit gives you one logging function per severity — knit_trace,
knit_debug, knit_info, knit_warning, knit_error, and
knit_critical — so you can narrate a command and let the reader choose how
much to see. Each takes printf-style arguments, prefixes the line with
[knit:<level>], and writes to stderr, leaving stdout for the command’s
real output:
@command "work" "Do some work, narrating at several log levels."
_do_work() {
knit_trace "entering _do_work" # shown only at --log-level trace
knit_debug "computing the result" # trace or debug
knit_info "starting the computation" # info and below (the default)
knit_warning "input looks unusually large" # warning and below
knit_error "a recoverable step failed" # error and below
# knit_fatal prints at ANY level and then exits non-zero:
# knit_fatal "unrecoverable: %s" "${reason}"
echo "done"
}
@done
knit_register "work" _do_work "Do some work, narrating at several log levels."
_do_work() {
knit_trace "entering _do_work" # shown only at --log-level trace
knit_debug "computing the result" # trace or debug
knit_info "starting the computation" # info and below (the default)
knit_warning "input looks unusually large" # warning and below
knit_error "a recoverable step failed" # error and below
# knit_fatal prints at ANY level and then exits non-zero:
# knit_fatal "unrecoverable: %s" "${reason}"
echo "done"
}
knit_done
A message prints only when its level is at or above the current threshold. The
levels, from most to least verbose, are trace < debug < info <
warning < error < critical. The default threshold is info, so
knit_trace and knit_debug stay silent until you ask for them.
Set the threshold two ways. Before launch, export the KNIT_LOG_LEVEL
environment variable; from inside a script, call knit_log_set_level:
# Raise the threshold from inside a body so only warnings and above surface.
# The same effect is available before launch with KNIT_LOG_LEVEL=warning.
@command "quiet" "Run the work quietly (warnings and errors only)."
_go_quiet() {
knit_log_set_level warning
_do_work
}
@done
# Raise the threshold from inside a body so only warnings and above surface.
# The same effect is available before launch with KNIT_LOG_LEVEL=warning.
knit_register "quiet" _go_quiet "Run the work quietly (warnings and errors only)."
_go_quiet() {
knit_log_set_level warning
_do_work
}
knit_done
KNIT_LOG_LEVEL=trace ./exp.sh work turns everything on for one run without
touching the script. An invalid level is rejected: knit_log_set_level
returns non-zero and leaves the level unchanged, and an invalid
KNIT_LOG_LEVEL is reset to info with a warning when knit loads.
knit_fatal is the odd one out: it prints at any level and then exits the
process with status 1, so reach for it only when the command cannot continue. If
knit has captured a subprocess’s output in its trace file, the fatal message
also points you at that file.
Frame a long-running command#
Pipe a noisy command’s output into knit_framed to keep it inside a fixed scrolling box, with safe non-TTY passthrough.
APIs: knit_framed
A build or install can spew hundreds of lines. Pipe its output into
knit_framed to confine that noise to a fixed, scrolling box with a title,
instead of letting it flood the terminal:
# Pipe a long-running command's output into knit_framed to keep it inside a
# fixed, scrolling box with a title. On a non-TTY (a log file, CI) the input is
# forwarded unchanged, so framing never corrupts captured output.
@command "build" "Build something, framing the output."
_do_build() {
_build_steps | knit_framed 10 60 --title "Building" --cleanup
}
_build_steps() {
echo "step 1/3"
echo "step 2/3"
echo "step 3/3"
}
@done
# Pipe a long-running command's output into knit_framed to keep it inside a
# fixed, scrolling box with a title. On a non-TTY (a log file, CI) the input is
# forwarded unchanged, so framing never corrupts captured output.
knit_register "build" _do_build "Build something, framing the output."
_do_build() {
_build_steps | knit_framed 10 60 --title "Building" --cleanup
}
_build_steps() {
echo "step 1/3"
echo "step 2/3"
echo "step 3/3"
}
knit_done
The two leading positional arguments are the frame’s height and width
(both default to the terminal size; pass -1 for either to keep the default).
Useful named options follow:
--title <text>centers a label on the top border.--cleanuperases the frame once the command finishes, leaving no trace on screen.--log-level <level>only draws the frame whenKNIT_LOG_LEVELis at or below that level; otherwise the input is drained silently. Use it to hide verbose output unless someone is debugging.--frame-color/--text-color(and their--*-bg-colorvariants) tint the border and text.
knit_framed only draws when stdout is a terminal. When it is not — a
redirect to a log file, a pipe, a CI run — stdin is forwarded to stdout
unchanged, so framing decorates an interactive session but never corrupts
captured or piped output.