Render nested process execution as a live, colored tree in the console, with tree connectors, status glyphs, and elapsed time per step. Nesting depth is tracked via frame exit handlers so it never desynchronizes, even when a step errors. Builds on the 'cli' package for console rendering.

logtree renders nested process execution as a live, colored tree in the console – tree connectors, status glyphs, and elapsed time per step – while keeping nesting depth correct even when a step errors partway through.
install.packages("logtree")
# or the development version
# install.packages("pak")
pak::pak("IvanSortino/logtree")
library(logtree)
load_config <- function() {
log_step("Load config")
log_info("reading config.yml")
log_success("validated 12 parameters")
}
fetch_rows <- function() {
log_step("Fetch rows")
log_info("requesting from API")
log_warn("rate limit at 80%")
log_success("fetched 1,204 rows")
}
pipeline <- function() {
log_step("Nightly pipeline")
load_config()
fetch_rows()
}
with_logging(pipeline())
#> ▶ Nightly pipeline
#> ├─ ▶ Load config
#> │ ├─ ℹ reading config.yml
#> │ ├─ ✔ validated 12 parameters
#> │ └─ ✔ Done 0.00s
#> ├─ ▶ Fetch rows
#> │ ├─ ℹ requesting from API
#> │ ├─ ⚠ rate limit at 80%
#> │ ├─ ✔ fetched 1,204 rows
#> │ └─ ⚠ Done 0.00s
#> └─ ✔ Done 0.01s
#> ✔ Run complete in 0.01s
logtree_summary()
#>
#> ── Summary: 1 warning ──────────────────────────────────────────────────────────
#> ⚠ Nightly pipeline › Fetch rows › rate limit at 80%
log_step() is meant to be called from inside a function: the step
auto-closes when the function that opened it returns – normally, early,
or via an uncaught error – so nesting depth never gets stuck out of
sync. (At top level, with no function frame to close on, reach for
log_open() / log_close() instead.)
The log_warn() line turned its own step’s close glyph yellow without
throwing anything, and logtree_summary() replayed it with the path it
happened on.
with_logging() marks every open step failed,
logs the condition, and rethrows; it never swallows an error.warning() and message() become
leaves in the tree instead of stderr noise.logger bridge – route an existing
logger codebase through logtree
in one call.