# 日志
日志记录有两个层次。裸 `log` 动词是常开的磁盘日志器:它将格式化后的值追加到 `<tmp-dir>/deft.log`,并绕过所有宿主级重定向(TUI 错误控制台、echo 捕获)。在其之上,分级的 `log/debug`、`log/info`、`log/warn` 和 `log/error` 函数为每条记录打标签并送入工作区错误控制台,而 `deft/stdext/logging` 中的 `[debug ...]` / `[info ...]` / `[warn ...]` / `[error ...]` 宏在编译期增加级别过滤。除宏之外的所有内容都无需导入即可使用。
## 函数
| 函数 | 用途 |
|---|---|
| `log v ...` | 将值追加到 `<tmp-dir>/deft.log`,绕过捕获和 TUI 重定向 |
| `log/debug v ...` | `DEBUG` 记录——仅日志文件,不进入错误控制台 |
| `log/info v ...` | `INFO` 记录——日志文件和错误控制台 |
| `log/warn v ...` | `WARN` 记录——日志文件和错误控制台 |
| `log/error v ...` | `ERROR` 记录——日志文件和错误控制台 |
说明:
- `<tmp-dir>` 是每进程临时目录(`[fs/tmp-dir]`,例如 `/tmp/deft-12345`)。裸 `log` 以空格分隔写入值并加换行,没有级别或时间戳;`log/*` 函数会加上前缀 `[<epoch-ms>] LEVEL `,且无论宿主如何,每次调用写一行。
- 在 TUI 宿主中,`log/info`、`log/warn` 和 `log/error` 也会出现在工作区错误控制台;`log/debug` 只留在文件中。在脚本二进制中,控制台报告器是空操作,因此所有级别只写入磁盘。
- `log/*` 函数不做级别过滤:它们总是写入。过滤位于 `deft/stdext/logging` 的宏中,通过 `require` 加载——必须是 `require`,而不是 `import`,这样宏在编译期可用。每个宏将调用位置以 `(file:line:col)` 追加,并将其 `log/*` 调用包裹在 `[macro/compile-when ...]` 中。
- `DEFT_LOG_LEVEL` 在日志模块加载时读取。被过滤的调用位置完全不产生运行时代码。可接受的值有 `debug`(默认)、`info`、`warn`、`error` 以及 `off` / `none`;更改变量需要重新编译,过滤才会改变。
## 示例
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
### 检查日志文件
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]]