必须配置 jsonformatter(logrus)或 encoding: "json"(zap),统一字段命名、禁用框架默认日志中间件、显式注册 /metrics 路由、指标须独立定义而非依赖日志解析、journald 需调大 linemax 和 limitnofile。

logrus/zap 输出结构化日志时,必须设 JSONFormatter 或 ZapCore,否则监控系统无法解析字段
很多团队在用 logrus 或 zap 时只改了日志级别,却漏掉格式器配置,结果日志仍是纯文本——Logstash、Fluent Bit、Loki 都没法提取 level、endpoint、status_code 这类字段,告警和聚合全失效。
-
logrus.SetFormatter(&logrus.JSONFormatter{})是最低要求,别只调SetLevel -
zap.NewProduction()默认就是 JSON,但若手动构造zap.Config,必须确认Encoding: "json" - 字段命名要统一:比如错误码统一用
http_status而不是status,避免和logrus内置的level冲突 - 不要在日志里拼接字符串(如
"user " + id + " failed"),而要用字段传参:log.WithField("user_id", id).Error("login failed")
Prometheus 指标暴露路径 /metrics 和日志采集路径不能共用同一 HTTP server 的 Handler 注册顺序
常见错误是把 promhttp.Handler() 放在 http.HandleFunc("/", ...) 后面,导致 /metrics 被主路由拦截返回 404。更隐蔽的问题是:用 Gin/Echo 时没禁用默认日志中间件,它会提前写响应头,让 promhttp.Handler() panic 报 http: multiple response.WriteHeader calls。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 注册顺序必须是:先
http.Handle("/metrics", promhttp.Handler()),再挂其他路由 - Gin 中要显式关闭默认 Logger:
r.Use(gin.Recovery())可以保留,但去掉r.Use(gin.Logger()) - Echo 中用
e.HideBanner = true不影响指标,但e.Use(middleware.Logger())必须移除或替换为不写响应体的轻量版 - 如果用
net/http自建 server,建议用http.ServeMux显式管理路由,避免隐式覆盖
日志字段转 Prometheus 指标时,别直接用 log.WithField 做计数器
有人想“复用日志字段”自动产生指标,比如在 log.WithField("error_type", "timeout").Error(...) 后,靠 Logstash 解析出 error_type 并发到 Prometheus——这条路走不通。Prometheus 不接受日志流推送,它只拉取 Counter/Histogram 等内存中维护的指标值。
- 错误日志计数必须靠独立指标:定义
errors_total = prometheus.NewCounterVec(...),在业务逻辑里显式errors_total.WithLabelValues("timeout").Inc() - 日志里的
error_type字段只用于 ELK/Loki 查询,不能替代指标逻辑 - 如果真想联动,得在日志采集层(如 Fluent Bit)做解析+HTTP POST 到 Pushgateway,但 Pushgateway 有单点和生命周期问题,生产环境慎用
- 耗时类指标必须用
Histogram或Summary,别用Counter加时间戳——Prometheus 自带_sum/_count计算 P99
systemd 服务 stdout 日志被 journald 截断时,StandardOutput=journal 不够,还得配 LimitNOFILE 和 LineMax
Debian/Ubuntu 上跑 Golang 服务,日志量大时 journalctl 会显示 MESSAGE_TRUNCATED 或直接丢行。这不是 Go 日志库问题,是 journald 默认限制每条日志最多 64KB,且文件描述符不够时会静默丢日志。
- 在
/etc/systemd/system/myapp.service里加:LineMax=10M(单位是字节,不是 MB) - 同时加
LimitNOFILE=65536,避免 journald 因 fd 不足丢日志 - 重启生效:
sudo systemctl daemon-reload && sudo systemctl restart myapp.service - 验证:
journalctl -u myapp.service --all | grep MESSAGE_TRUNCATED应无输出
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










