一、日志基础使用
1.1 日志输出方法
go
import "github.com/zeromicro/go-zero/core/logx"
// 普通日志
logx.Info("普通信息日志")
logx.Infof("格式化信息: %s", "内容")
logx.Infow("结构化日志", logx.Field("key", "value"))
// 错误日志
logx.Error("错误日志")
logx.Errorf("错误: %v", err)
logx.Errorw("结构化错误", logx.Field("error", err))
// 调试日志(需要开启 Debug 模式)
logx.Debug("调试日志")
logx.Debugf("调试: %s", "内容")
// 慢日志
logx.Slow("慢操作日志")
logx.Slowf("慢操作: %dms", 1000)
logx.Sloww("结构化慢日志", logx.Field("duration", "1s"))
// 统计日志
logx.Stat("统计信息")
logx.Statf("统计: %s", "内容")
// 严重错误日志
logx.Severe("严重错误")
logx.Severef("严重错误: %v", err)
1.2 带 Context 的日志
go
// 推荐使用,可以追踪链路
logx.WithContext(ctx).Info("带上下文的日志")
logx.WithContext(ctx).Infow("结构化日志", logx.Field("user", "张三"))
logx.WithContext(ctx).Error("带上下文的错误日志")
二、日志配置
2.1 配置文件示例(yaml)
yaml
Name: user-api
Host: 0.0.0.0
Port: 8888
Log:
# 日志模式:console(控制台)、file(文件)、volume(容器卷)
Mode: file
# 日志级别:debug、info、error、severe
Level: info
# 编码格式:json 或 plain
Encoding: json
# 文件日志配置
Path: logs # 日志文件存放目录
MaxSize: 100 # 单个日志文件最大大小(MB)
MaxBackups: 5 # 保留的旧日志文件最大数量
MaxAge: 30 # 保留旧日志文件的最大天数
Compress: true # 是否压缩旧日志文件
# 日志打印调用位置
KeepDays: 7 # 日志保留天数
# 是否记录调用堆栈
StackCooldownMillis: 100 # 堆栈冷却时间(毫秒)
2.2 配置项详细说明
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| Mode | string | console | console-控制台输出,file-文件输出,volume-容器卷 |
| Level | string | info | debug、info、error、severe,级别越低输出越详细 |
| Encoding | string | json | json-JSON格式,plain-纯文本格式 |
| Path | string | logs | 日志文件存放路径(相对或绝对路径) |
| MaxSize | int | 100 | 单个日志文件最大大小(MB) |
| MaxBackups | int | 5 | 保留的旧日志文件最大数量 |
| MaxAge | int | 30 | 保留旧日志文件的最大天数 |
| Compress | bool | false | 是否压缩归档的日志文件 |
| KeepDays | int | 7 | 日志保留天数(优先级高于MaxAge) |
| StackCooldownMillis | int | 100 | 堆栈冷却时间,避免频繁打印堆栈 |
2.3 不同环境的日志配置建议
开发环境
yaml
Log:
Mode: console # 控制台输出,方便查看
Level: debug # 详细日志,便于调试
Encoding: plain # 纯文本,易读
测试环境
yaml
Log:
Mode: file # 文件输出,方便问题追溯
Level: info # 标准日志级别
Encoding: json # JSON格式,便于日志分析
Path: logs
KeepDays: 3
生产环境
yaml
Log:
Mode: file # 文件输出
Level: info # 只记录重要日志(或 error)
Encoding: json # JSON格式,便于日志收集系统解析
Path: /var/log/app # 绝对路径
MaxSize: 500 # 大容量
MaxBackups: 10
MaxAge: 30
Compress: true # 压缩节省空间
KeepDays: 30
三、配置与不配置 Log 的区别
3.1 不配置 Log(使用默认配置)
yaml
# 配置文件中不写 Log 配置项
Name: user-api
Host: 0.0.0.0
Port: 8888
默认行为:
- Mode:
console- 日志输出到控制台 - Level:
info- 只输出 info 及以上级别的日志 - Encoding:
json- JSON 格式输出 - 不会生成日志文件
- 日志只在控制台显示,重启后丢失
3.2 配置 Log
yaml
Name: user-api
Host: 0.0.0.0
Port: 8888
Log:
Mode: file
Level: info
Path: logs
行为:
- 日志输出到文件
- 日志持久化保存
- 可以配置日志轮转、压缩等
- 可以通过日志收集系统统一管理
3.3 最佳实践
go
// 在 main.go 中根据环境动态配置
var c config.Config
conf.MustLoad(*configFile, &c)
// 如果配置文件没有 Log 配置,可以代码中设置
if c.Log.Mode == "" {
logx.MustSetup(logx.LogConf{
Mode: "file",
Level: "info",
Encoding: "json",
Path: "logs",
})
}
四、日志收集场景与位置
4.1 自动日志收集场景
1. HTTP 中间件自动收集
go
// rest.Server 自动记录的日志
// 位置:rest/handler/loghandler.go
✅ 请求开始时间
✅ 请求方法和路径
✅ 请求耗时
✅ HTTP状态码
✅ 请求体大小
✅ 错误信息(如果有)
// 日志示例
{
"@timestamp": "2025-12-29T10:30:00.123Z",
"level": "info",
"content": "GET /api/users/1",
"duration": "15.2ms",
"code": 200
}
2. RPC 中间件自动收集
go
// zrpc.Server 自动记录的日志
// 位置:zrpc/internal/serverinterceptors/statinterceptor.go
✅ RPC方法名
✅ 调用耗时
✅ 错误信息
✅ 调用参数(可选)
3. 数据库操作日志
go
// sqlx 自动记录慢查询
// 慢查询阈值:默认 500ms
✅ SQL语句
✅ 执行耗时
✅ 受影响行数
4. 缓存操作日志
go
// redis/cache 自动记录慢操作
// 慢操作阈值:可配置
✅ Redis命令
✅ 执行耗时
✅ 缓存键
4.2 手动日志收集场景
go
// 业务逻辑层
func (l *UserLogic) GetUser(req *types.GetUserReq) (*types.User, error) {
// 关键业务操作记录
logx.WithContext(l.ctx).Infow("开始获取用户信息",
logx.Field("userId", req.UserId))
user, err := l.svcCtx.UserModel.FindOne(l.ctx, req.UserId)
if err != nil {
// 错误日志
logx.WithContext(l.ctx).Errorw("获取用户失败",
logx.Field("userId", req.UserId),
logx.Field("error", err.Error()))
return nil, err
}
// 成功日志
logx.WithContext(l.ctx).Infow("用户信息获取成功",
logx.Field("userId", req.UserId),
logx.Field("userName", user.Name))
return &types.User{
Id: user.Id,
Name: user.Name,
}, nil
}
4.3 日志收集最佳实践
go
// ✅ 推荐:关键业务节点记录
- 用户登录/登出
- 订单创建/支付
- 重要数据的增删改
- 外部API调用
- 异常错误
// ❌ 不推荐:过度日志
- 循环内的日志
- 高频调用的接口日志
- 敏感信息(密码、token等)
五、日志文件存储规则
5.1 日志文件命名规则
lua
logs/
├── access.log # 当前访问日志
├── error.log # 当前错误日志
├── severe.log # 当前严重错误日志
├── slow.log # 当前慢日志
├── stat.log # 当前统计日志
├── access.log.2025122901 # 归档的访问日志
├── access.log.2025122902
└── error.log.2025122901 # 归档的错误日志
5.2 日志分类存储
| 日志类型 | 文件名 | 触发条件 | 用途 |
|---|---|---|---|
| access.log | 访问日志 | Info、Infof、Infow | 记录正常业务流程 |
| error.log | 错误日志 | Error、Errorf、Errorw | 记录业务错误 |
| severe.log | 严重错误 | Severe、Severef、Severew | 记录系统级严重错误 |
| slow.log | 慢日志 | Slow、Slowf、Sloww | 记录耗时操作 |
| stat.log | 统计日志 | Stat、Statf、Statw | 记录统计信息 |
5.3 什么时候会存文件
存文件条件:
Log.Mode = "file"或"volume"- 配置了
Log.Path
不存文件条件:
Log.Mode = "console"- 只输出到控制台- 不配置 Log - 默认 console 模式
yaml
# ✅ 会存文件
Log:
Mode: file
Path: logs
# ✅ 会存文件(容器环境)
Log:
Mode: volume
Path: /var/log/app
# ❌ 不会存文件
Log:
Mode: console
# ❌ 不会存文件(默认配置)
# 不配置 Log
5.4 日志轮转机制
yaml
Log:
Path: logs
MaxSize: 100 # 单文件 100MB 后轮转
MaxBackups: 5 # 最多保留 5 个备份
MaxAge: 30 # 保留 30 天
KeepDays: 7 # 优先级更高,保留 7 天
Compress: true # 压缩旧文件为 .gz
轮转触发条件(满足任一):
- 文件大小超过 MaxSize
- 文件创建时间超过 KeepDays
- 达到每日午夜(自动轮转)
六、日志查看与问题排查
6.1 查看日志的方式
方式一:tail 实时查看
bash
# 实时查看所有日志
tail -f logs/access.log
# 实时查看错误日志
tail -f logs/error.log
# 同时查看多个日志
tail -f logs/access.log logs/error.log
方式二:grep 过滤查看
bash
# 查找特定用户的日志
grep "userId\":\"123" logs/access.log
# 查找错误日志
grep "error" logs/access.log
# 查找特定时间段的日志
grep "2025-12-29T10:" logs/access.log
# 查找并显示上下文
grep -C 5 "error" logs/access.log # 显示前后5行
方式三:less 分页查看
bash
# 分页查看日志
less logs/access.log
# 在 less 中搜索:按 / 然后输入关键词
# 下一个:n
# 上一个:N
方式四:cat 配合工具
bash
# 查看最近100行
tail -n 100 logs/access.log
# 查看前100行
head -n 100 logs/access.log
# JSON格式美化
cat logs/access.log | jq '.'
6.2 通过 trace_id 追踪请求链路
bash
# 提取 trace_id 追踪整个请求链路
grep "trace:abc123" logs/*.log
# 输出示例:
# logs/access.log:{"@timestamp":"...","trace":"abc123","content":"GET /api/users"}
# logs/access.log:{"@timestamp":"...","trace":"abc123","content":"query user from db"}
# logs/error.log:{"@timestamp":"...","trace":"abc123","content":"user not found"}
6.3 性能问题排查
慢查询排查
bash
# 查看慢日志
cat logs/slow.log
# 查找超过1秒的操作
grep "duration\":\"[0-9]\+s" logs/slow.log
# 统计最慢的10个操作
cat logs/slow.log | jq '.duration' | sort | tail -10
高频错误排查
bash
# 统计错误类型
cat logs/error.log | jq '.error' | sort | uniq -c | sort -rn
# 查找特定错误
grep "connection timeout" logs/error.log
6.4 典型问题排查流程
问题1:接口响应慢
bash
# 1. 查看 slow.log
tail -f logs/slow.log
# 2. 找到慢请求的 trace_id
grep "duration\":\"[0-9]\+s" logs/slow.log
# 3. 根据 trace_id 追踪完整链路
grep "trace:abc123" logs/*.log
# 4. 分析瓶颈:数据库?外部API?
问题2:接口返回 500 错误
bash
# 1. 查看 error.log
tail -f logs/error.log
# 2. 找到错误信息和堆栈
grep -A 10 "500" logs/error.log
# 3. 根据时间和路径定位代码
# 4. 查看相关业务日志
问题3:找不到某个请求的日志
bash
# 可能原因:
# 1. 日志级别太高(设置为 error,但请求是 info)
# 2. 日志已被轮转或删除
# 3. 时间不对(注意时区)
# 解决:
# 1. 检查 Log.Level 配置
# 2. 查看归档日志 access.log.2025122901
# 3. 检查服务器时区设置
七、日志使用建议
7.1 什么时候开启日志
| 场景 | 是否开启 | 建议配置 |
|---|---|---|
| 开发环境 | ✅ 必须 | Mode: console, Level: debug |
| 测试环境 | ✅ 必须 | Mode: file, Level: info |
| 预发环境 | ✅ 必须 | Mode: file, Level: info |
| 生产环境 | ✅ 必须 | Mode: file, Level: info/error |
| 性能测试 | ⚠️ 可选 | Mode: file, Level: error(减少IO) |
| 压力测试 | ⚠️ 可选 | Level: error(减少日志量) |
结论:建议一直开启日志,根据环境调整级别和输出方式。
7.2 日志级别选择
go
// debug - 开发调试(生产不建议)
logx.Debug("调试信息:变量值为 xxx")
// info - 正常业务流程(推荐)
logx.Info("用户登录成功")
// error - 业务错误(必须)
logx.Error("获取用户信息失败")
// severe - 严重系统错误(必须)
logx.Severe("数据库连接失败")
7.3 日志性能优化
go
// ❌ 不推荐:高频日志
for i := 0; i < 10000; i++ {
logx.Info("处理中:", i) // 会产生大量日志
}
// ✅ 推荐:批量记录
logx.Infof("批量处理完成,共处理 %d 条", 10000)
// ❌ 不推荐:复杂对象序列化
logx.Infow("用户信息", logx.Field("user", largeUserObject))
// ✅ 推荐:只记录关键字段
logx.Infow("用户信息",
logx.Field("userId", user.Id),
logx.Field("userName", user.Name))
7.4 敏感信息处理
go
// ❌ 危险:记录敏感信息
logx.Infow("用户登录",
logx.Field("password", password)) // 不要记录密码
logx.Infow("支付",
logx.Field("cardNo", cardNo)) // 不要记录完整卡号
// ✅ 安全:脱敏处理
logx.Infow("用户登录",
logx.Field("userId", userId))
logx.Infow("支付",
logx.Field("cardNo", maskCard(cardNo))) // 如:**** **** **** 1234
八、常用日志工具
8.1 日志分析工具
ELK Stack(推荐生产环境)
yaml
# Filebeat 配置示例
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
json.keys_under_root: true
json.add_error_key: true
output.elasticsearch:
hosts: ["localhost:9200"]
Loki(轻量级推荐)
yaml
# Promtail 配置示例
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: app
static_configs:
- targets:
- localhost
labels:
__path__: /var/log/app/*.log
8.2 日志查看命令速查
bash
# 实时查看
tail -f logs/access.log
# 查看最近100行
tail -n 100 logs/access.log
# 搜索关键词
grep "error" logs/*.log
# 搜索并高亮显示
grep --color "error" logs/access.log
# 统计日志行数
wc -l logs/access.log
# 按时间范围筛选
sed -n '/2025-12-29 10:00/,/2025-12-29 11:00/p' logs/access.log
# JSON 日志美化
cat logs/access.log | jq '.'
# 统计错误类型
cat logs/error.log | jq '.error' | sort | uniq -c
# 找出最慢的10个请求
cat logs/slow.log | jq '.duration' | sort -rn | head -10
九、完整配置示例
9.1 API 服务配置
yaml
# api/etc/user.yaml
Name: user-api
Host: 0.0.0.0
Port: 8888
# 生产环境日志配置
Log:
Mode: file
Level: info
Encoding: json
Path: logs
MaxSize: 500
MaxBackups: 10
MaxAge: 30
Compress: true
KeepDays: 30
StackCooldownMillis: 100
# Telemetry 配置(链路追踪)
Telemetry:
Name: user-api
Endpoint: http://jaeger:14268/api/traces
Sampler: 1.0
Batcher: jaeger
9.2 RPC 服务配置
yaml
# rpc/etc/user.yaml
Name: user-rpc
ListenOn: 0.0.0.0:8080
Log:
Mode: file
Level: info
Encoding: json
Path: logs
KeepDays: 30
# RPC 超时配置
Timeout: 30000 # 30秒
# RPC 日志配置
RpcLog:
Stat: true # 开启统计日志
Slow: true # 开启慢日志
9.3 Docker 环境配置
yaml
# docker-compose.yaml 中的日志配置
services:
user-api:
image: user-api:latest
volumes:
- ./logs:/app/logs # 挂载日志目录
environment:
- LOG_MODE=file
- LOG_LEVEL=info
十、总结与检查清单
✅ 日志配置检查清单
- 是否配置了 Log.Mode(开发用console,生产用file)
- 是否配置了合适的 Log.Level(开发用debug,生产用info)
- 是否配置了 Log.Path(生产环境)
- 是否配置了日志轮转(MaxSize、MaxBackups、KeepDays)
- 是否开启了日志压缩(Compress: true)
- 是否配置了链路追踪(Telemetry)
✅ 日志使用检查清单
- 关键业务操作是否有日志记录
- 错误处理是否记录了详细错误信息
- 日志是否使用了 WithContext 以便链路追踪
- 日志是否包含了足够的上下文信息
- 是否避免了记录敏感信息
- 高频操作是否控制了日志数量
- 是否使用了结构化日志(Infow、Errorw)
✅ 问题排查检查清单
- 是否能通过 trace_id 追踪完整请求链路
- 是否能快速定位错误日志
- 是否能分析慢查询和性能瓶颈
- 是否配置了日志收集系统(生产环境)
- 是否定期清理旧日志文件
- 是否有日志监控告警(严重错误)
附录:常见问题
Q1: 日志文件太大怎么办?
- 调整 MaxSize 和 KeepDays
- 提高日志级别(info -> error)
- 减少不必要的日志输出
- 开启 Compress 压缩
Q2: 找不到某个请求的日志?
- 检查日志级别配置
- 确认日志是否被轮转
- 检查时区是否正确
- 确认该请求是否真的到达了服务
Q3: 日志乱码怎么办?
- 确保使用 UTF-8 编码
- 检查 Encoding 配置
- 使用
cat -A查看特殊字符
Q4: 如何在代码中动态修改日志级别?
go
// 运行时修改日志级别(不推荐生产环境)
logx.SetLevel(logx.ErrorLevel)
Q5: 容器环境日志如何收集?
yaml
# 使用 volume 模式
Log:
Mode: volume
Path: /var/log/app
# Docker 挂载
volumes:
- ./logs:/var/log/app