Files
go-omni/logx/README.md

4.8 KiB
Raw Permalink Blame History

logx

业务通过 logx 记录结构化日志,独立于 HTTP、队列和具体业务字段。普通 context.Context 继续由业务管理;框架不会约定或自动注入 userId、tenantId。

logx.InfoContext(ctx, "order.created", "orderId", orderID)
logx.ErrorContext(ctx, "order.failed", "error", err)
// 可选:附上本次记录位置的当前 goroutine 堆栈。
logx.ErrorStackContext(ctx, "unexpected.failure", "error", err)
// 固定字段可使用子日志对象,无需重复传入。
logger := logx.With("component", "invoice")
logger.InfoContext(ctx, "invoice.saved", "invoiceId", invoiceID)

Debug/Info/Warn/Error 有包级和实例方法,也有带 Context 的方法。requestId 自动跟随 HTTP Context;接入 telemetry 后可带 traceId。不要在 Service 中改用 context.Background(),否则会丢失取消信号和关联字段。

文件轮转

closeLog, err := logx.Setup(logx.Config{
    Service: "billing-api", Environment: "production",
    Level: "info", Format: "json", File: "./var/log/billing-api.log",
    Rotation: logx.RotationConfig{
        Enabled: true, MaxSizeMB: 100, MaxBackups: 10,
        MaxAgeDays: 7, Compress: true,
    },
    RedactKeys: []string{"bankAccount", "identityNumber"},
})
if err != nil { return err }
defer closeLog()

omni.WithLogConfig(...) 只保存日志配置,omni.New() 不会因此创建或关闭 Logger。手写入口需要像上例一样调用 logx.Setup 并负责关闭,或使用 logx.New、logx.SetDefault 和 app.OnShutdown(logger.Close) 显式装配。生成的 API 项目已在入口完成这些步骤。子日志共用输出、级别和关闭状态;独立 logx.New 返回的实例由创建者负责关闭。

轮转显式开启;三个数值为 0 时分别取 100 MiB、10 份、7 天。超过大小后轮转,旧文件按份数/年龄清理,可 gzip 压缩;保留天数不表示每天定时切割。压缩和历史清理由底层异步执行,不承诺 Close 等待压缩完成。轮转使用 lumberjack v2,一个日志文件只能由一个进程拥有。容器通常直接用 stdout/stderr,让运行平台管理日志文件。

rotation.enabled 与自定义 Writer 不能同时使用;只设轮转但未提供 File 会报错。开启轮转时会创建父目录,并在初始化阶段检查文件可打开。自定义 Writer 的并发和生命周期由接入方负责。普通文件输出仍然是追加写入;未开启轮转不自动清理。

结构化脱敏

默认匹配 password、passwd、secret、clientSecret、token、accessToken、refreshToken、authorization、cookie、setCookie、apiKey、privateKey、signedUrl。匹配忽略大小写、下划线和连字符;RedactKeys 追加业务自行定义的键,不替换默认列表。

覆盖普通属性、With 属性、slog Group/LogValuer、嵌套字符串键 map、切片和导出 struct 字段。敏感值变为 [REDACTED],不修改调用者的数据;循环/过深结构截断。嵌套字节数组隐藏为 [BINARY],非字符串键 map 隐藏为 [UNSUPPORTED MAP],不调用对象自定义 JSON 序列化方法。

脱敏按字段名处理,不解析自由文本。 把密码拼进 msg/error/URL 字符串,或使用不在列表中的字段名,仍可能泄露。签名链接、完整请求体和认证头不应写入日志。业务隐私字段自行放进 RedactKeys;日志中不会自动添加身份/租户约定。

HTTP 异常与慢请求

application := omni.New(
    omni.WithLogger(true),
    omni.WithSlowRequestThreshold(500*time.Millisecond),
)

WithSlowRequestThreshold 同时开启访问日志,0 禁用慢请求识别。也可以在 JSON/YAML 中配 enableLogger: true、slowRequestThreshold: "500ms",或使用 GO_OMNI_SLOW_REQUEST_THRESHOLD 配合 GO_OMNI_ENABLE_LOGGER=true。

每个请求记录一条 http.request:方法、路径、匹配路由、实际状态码、耗时、客户端 IP 和关联字段。正常请求 INFO,超过阈值 WARN(slow: true),5xx ERROR;返回的 error 会记录到结构化字段。计时覆盖 Handler 调用,不包含框架之外的代理排队,也不自动计入 Handler 返回后继续写入的自管流。

Recovery 自动记录单独的 ERROR http.panic 和当前堆栈,再走原有统一错误响应;如果响应已提交,不改写已发送状态。客户端不会收到日志堆栈。普通业务 error 默认不抓堆栈,需要时显式使用 ErrorStackContext,它记录调用位置,不回溯 error 最初创建位置。

运行时可通过 logger.SetLevel("debug") 调整级别;文件轮转和脱敏配置属于静态设置,变更后重建实例/重启。当前不包含日志采样、异步缓冲、日志平台导出或慢 SQL 记录。