日志系统
9 类结构化日志、文件落地与错误监控邮件
站点内置一套轻量结构化日志系统,把访问、认证、审计、外部调用、缓存、限流、定时任务、应用兜底与错误监控九类事件统一格式化后双写到终端和按天分文件。本节介绍日志落点、分类含义、站点配置、错误监控邮件与环境变量。
落点与目录结构
日志文件根目录默认取 site.config.ts 的 logs.dir(./logs/,按进程 cwd 解析),.env 中的 LOGS_DIR 设置后优先。Docker 部署的日志挂卷由 compose 内置,容器内的固定路径默认挂到项目根的 logs/ 目录,宿主路径同样由 .env 的 LOGS_DIR 指定。每条日志的落点形如 logs/{category}/{YYYY-MM-DD}.log,单文件超过大小上限后切分为 {YYYY-MM-DD}.1.log、{YYYY-MM-DD}.2.log(上限见下文「站点配置」);子目录名取英文 category(Windows / 工具链对中文路径兼容性差),行内标签用中文([访问]、[认证]、[审计]、[外部]、[缓存]、[限流]、[任务]、[应用]、[监控]),便于现场排障快速对位。
格式按 site.config.ts 的 logs.lineFormat 拼接:YYYY-MM-DD HH:mm:ss.SSS [TAG] [LEVEL] msg k=v k2="v with spaces",时间和日期键使用主机本地时区。容器默认时区是 UTC,因此容器内日志显示的日期与生产主机日期可能不一致。这是显式选择,不要再去引入 LOG_TIMEZONE 等额外环境变量。
分类含义
九类日志按用途划分,写入路径与典型调用方见下表:
| 中文标签 | 英文目录 | 典型来源 |
|---|---|---|
| 访问 | access/ | server/middleware/access-log.ts 拦所有请求,记录方法、路径、状态、耗时、IP |
| 认证 | auth/ | 登录、登出、二步验证、信任设备流程的成功与失败 |
| 审计 | audit/ | 后台所有写操作(文章增删改、设置变更、点赞清理等)的 actor / action / target |
| 外部 | external/ | SMTP 发送、第三方 API 调用、COS 上传等外部依赖的成功与失败 |
| 缓存 | cache/ | Redis 失效、缓存清理命令、按类别清理的执行结果 |
| 限流 | ratelimit/ | 通用限流中间件和登录限流的命中记录,含 IP、规则名、计数 |
| 任务 | cron/ | 定时发布 worker 每次扫描的结果与发布条数 |
| 应用 | app/ | 没有合适分类时的兜底,error 级输出(log.error)也落在这一类 |
| 监控 | monitor/ | 服务端 5xx 与客户端 error 报告事件,含来源、级别、消息摘要 |
所有日志除了写入文件还会同步打到 stdout;部署环境重定向 stdout 到采集器或直接扫 logs/* 离线分析都能看到同一份内容。
站点配置
日志的总开关、行格式、大小切分与保留集中在 site.config.ts 的 logs 区,分类逐一开关也在这一区:
TypeScriptdefineSiteConfig({
logs: {
file: true,
dir: "./logs",
lineFormat: "{ts} [{tag}] [{level}] {msg}{kv}",
maxFileSizeMb: 20,
retentionDays: 90,
categories: {
access: true,
audit: true,
auth: true,
external: true,
cache: true,
ratelimit: true,
cron: true,
monitor: true,
app: true,
},
},
})| 字段 | 默认 | 说明 |
|---|---|---|
file | true | 文件日志总开关,false 时所有日志只打终端不落盘 |
dir | "./logs" | 日志根目录,.env 的 LOGS_DIR 优先于此值 |
lineFormat | "{ts} [{tag}] [{level}] {msg}{kv}" | 落盘行格式,占位符见 lib/site-config.ts 的字段注释 |
maxFileSizeMb | 20 | 单个日志文件大小上限(MB),超出切分为 {日期}.1.log,≤ 0 不切分 |
retentionDays | 90 | 每类日志保留天数,新的一天首次写入时清理过期文件,0 永久保留 |
categories.* | 九类各 true | 分类落盘开关,false 的类别只打终端不落盘 |
access 是量最大的一类,磁盘紧张时可以第一个关掉它;app 是兜底分类,建议保持开启。该区属于构建期配置,改动后需要重新构建。
错误监控邮件
服务端 5xx 错误和客户端 error-handler.client.ts 捕获到的 error 级别异常都会触发 server/utils/error-report.ts,把事件写入 [监控] 日志后向站长收件邮箱发送中文模板邮件;发送前提是设置中的「通知站长」总开关与「错误日志通知」子开关均开启。同一错误(按 级别:消息前 100 字 取 SHA-256 前 32 位做指纹)5 分钟内只发一封,Redis 中按指纹计数计数,计数大于 1 标记为抑制并不再发邮件;Redis 不可用时一律不抑制(保守放行)。
邮件模板与日志字段对齐,按「级别 / 来源 / 堆栈 / 上下文」分区展示,便于从邮件回到日志快速定位。NOTIFY_DEDUPE_WINDOW_SEC 默认 300 秒,调整需要修改源码;修改前应当评估是否会显著放大故障期的收件量。
配置项
| 变量 | 默认 | 说明 |
|---|---|---|
LOGS_DIR | ./logs/ | 日志根目录。裸机部署指应用写日志的目录,相对路径按进程 cwd 解析;Docker 部署指挂载日志的宿主目录(默认项目根 logs/),容器内路径由 compose 固定,格式与分类含义见 日志系统 |
LOGS_DIR 之外的日志行为均不在 .env 里配置:开关、格式、切分与保留在 site.config.ts 的 logs 区(见上文「站点配置」),抑制窗口与邮件去重键集中在源码 server/utils/log.ts 与 server/utils/error-report.ts;改动前请通读文件内的注释,了解「最佳努力 / fail-open / 不阻断业务」的设计取舍。
文件写入失败一律
console.error、不抛,避免日志本身再抛造成无限循环。日志系统故障不会让业务请求失败,但也不会假装写过。终端仍能看到那条日志。