默认fiber.Logger不够用,因其仅输出固定字段(时间、状态码、方法、路径、耗时、字节数),缺失请求体、响应体、Header及自定义字段,无法满足调试需求;需自定义中间件复制body、提取头信息、脱敏截断并支持多输出。

为什么默认的 fiber.Logger() 不够用
因为它的输出固定为 time status method path latency bytes,不包含请求体、响应体、Header 或自定义字段。调试接口时经常需要看 Content-Type、Authorization 头,或者 POST 的原始 JSON,这时候默认日志器就抓瞎了。
实操建议:
- 不要直接用
fiber.Logger()做调试日志,它只适合生产环境做基础访问统计 - 自己写中间件时,优先读取
c.Request().Body前先调用c.Request().ForceRequestBodyReader(),否则后续路由 handler 会读不到 body - 记录请求体前务必检查
c.Method()是否为GET或HEAD,避免 panic:这些方法本就不带 body
如何安全地记录带 body 的请求日志
Go 的 fasthttp 底层复用 request buffer,body 只能读一次。直接 c.Body() 会清空缓冲区,导致下游 handler 解析失败。
实操建议:
- 用
c.Request().CopyTo(&buf)把原始请求完整拷贝到bytes.Buffer,再从中解析 method/path/body - 对
POST/PUT请求,仅在Content-Type包含application/json或application/x-www-form-urlencoded时才尝试解析 body,跳过multipart/form-data(否则会干扰文件上传) - 日志中 body 字段建议限制长度,比如截取前 512 字节,防止大文件或恶意 payload 打爆日志系统
示例关键逻辑:
buf := &bytes.Buffer{}
c.Request().CopyTo(buf)
bodyStr := buf.String()
if len(bodyStr) > 512 {
bodyStr = bodyStr[:512] + "...(truncated)"
}
如何让日志同时输出到文件和控制台
fiber.Logger() 默认只写 stdout,而生产环境必须落盘。Fiber 本身不提供多 writer 支持,得靠 io.MultiWriter 拼接。
实操建议:
- 创建日志文件时用
os.OpenFile(..., os.O_CREATE|os.O_APPEND|os.O_WRONLY),别用os.Create,否则每次启动都覆盖旧日志 - 把
os.Stdout和日志文件句柄一起传给io.MultiWriter,然后塞进fiber.Config{Logger: ...} - 注意文件句柄泄漏:全局 logger 实例应只 open 一次,在
main()开头初始化,不要在中间件里反复 open
示例配置片段:
logFile, _ := os.OpenFile("access.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
multiWriter := io.MultiWriter(os.Stdout, logFile)
app := fiber.New(fiber.Config{
Logger: multiWriter,
})
为什么不能在中间件里直接用 fmt.Println() 打日志
因为 Fiber 的并发模型下,多个请求共用 goroutine,fmt.Println() 输出无序、混杂,且无法关联请求 ID,查问题时根本分不清哪行日志属于哪个请求。
实操建议:
- 所有日志必须带唯一 trace ID,可用
c.Locals("fiber.ctx").(*fiber.Ctx).ID()获取(需开启fiber.Config{EnablePrintRoutes: true}吗?不,ID 是自动有的) - 用结构化日志库如
zerolog或zap替代fmt,至少确保每条日志是单行 JSON,方便 ELK 或 Loki 采集 - 避免在日志里拼接敏感字段,比如
Authorization: Bearer xxx必须脱敏为Authorization: Bearer ***
真正容易被忽略的是:日志中间件的注册顺序。它必须放在 app.Use() 链最前面,否则像 fiber.Recover() 这类 panic 捕获中间件会先执行,导致错误请求完全没被记录。


















