# Logging
Logging has two layers. The bare `log` verb is the always-on disk
logger: it appends formatted values to `<tmp-dir>/deft.log` and
bypasses every host-level redirect (TUI error console, echo capture).
On top of it, the leveled `log/debug`, `log/info`, `log/warn`, and
`log/error` functions tag each record and feed the workspace error
console, and the `[debug ...]` / `[info ...]` / `[warn ...]` /
`[error ...]` macros from `deft/stdext/logging` add level filtering at
compile time. Everything except the macros is available without an
import.
## Functions
| Function | Purpose |
|---|---|
| `log v ...` | Append values to `<tmp-dir>/deft.log`, bypassing capture and TUI redirects |
| `log/debug v ...` | `DEBUG` record — log file only, not the error console |
| `log/info v ...` | `INFO` record — log file and error console |
| `log/warn v ...` | `WARN` record — log file and error console |
| `log/error v ...` | `ERROR` record — log file and error console |
Notes:
- `<tmp-dir>` is the per-process temp directory (`[fs/tmp-dir]`, e.g.
`/tmp/deft-12345`). Bare `log` writes the values space-separated plus
a newline, with no level or timestamp; the `log/*` functions prefix
`[<epoch-ms>] LEVEL ` and write one line per call regardless of host.
- In the TUI hosts, `log/info`, `log/warn`, and `log/error` also surface
in the workspace error console; `log/debug` stays in the file. In the
scripting binary the console reporter is a no-op, so every level goes
to disk only.
- The `log/*` functions are not level-filtered: they always write.
Filtering lives in the macros from `deft/stdext/logging`, loaded with
`require` — it must be `require`, not `import`, so the macros are
available at compile time. Each macro appends the call site as
`(file:line:col)` and wraps its `log/*` call in `[macro/compile-when ...]`.
- `DEFT_LOG_LEVEL` is read when the logging module loads. A filtered
call site produces no runtime code at all. Accepted values are
`debug` (the default), `info`, `warn`, `error`, and `off` / `none`;
changing the variable requires a recompile for the filtering to
shift.
## Examples
require "deft/stdext/logging" [debug "loading" "/etc/app.conf"] # file only [info "server started on port" 8080] # file + error console [warn "disk usage at" 91 "%"] [error "failed to open" "/etc/missing"] # Built-ins ignore DEFT_LOG_LEVEL and always write, with their own tag: [log/info "this still lands in deft.log"] [log "and so does this"] # bare log: no level, no console
### Inspecting the log file
set state %{ :user "alice" :tries 2 } [log "state snapshot" $state] [log %{ :event :sync :ok true }] set path [fs/join [fs/tmp-dir] "deft.log"] echo $path echo [unwrap [fs/read $path]]
With `DEFT_LOG_LEVEL=warn`, the `[info ...]` and `[debug ...]` call
sites above compile to nothing, while `[warn ...]` and `[error ...]`
remain; the direct `log/*` calls are unaffected.
## See Also
- IO — channels, `echo`, and the bare `log` verb
- Filesystem — reading the log file back
- Debug Server — runtime error reporting