Loki默认监听localhost:3100,Go服务在容器内调用localhost会指向自身而非Loki服务;需确认容器内可curl loki:3100/readyz,且v2.9+需显式启用enable_http_v1_api = true。

为什么直接用Loki官方client会连不上loki:3100?
因为Loki默认监听http://localhost:3100,但Golang服务通常跑在容器里,localhost指向自己而非Loki服务。常见错误是日志没报错但查不到数据,实际请求根本没发出去。
- 确认Loki服务地址是否可从Go服务容器内
curl -v http://loki:3100/readyz通(注意不是localhost) - 用
http.Client手动发POST /loki/api/v1/push测试,比直接上github.com/grafana/loki/pkg/logprotoclient更易定位网络问题 - Loki v2.9+默认关闭
/push端点,需在配置里显式启用:[server.http]下加enable_http_v1_api = true
用promtail还是直接logproto写入?
除非你有强实时性要求(比如审计日志必须秒级可见),否则别在Go服务里直连Loki。Promtail更稳、支持重试/背压/标签自动注入,而Go直写容易因Loki抖动丢日志。
- Go服务只打本地
stdout或文件,用promtail采集——这是生产推荐路径 - 若必须直写,用
github.com/grafana/loki/pkg/logproto+grpc协议(非HTTP),避免JSON序列化开销;但得自己实现批量、重试、流控 - 标签必须带
job和host,否则Loki查询时rate()等聚合函数失效
logfmt格式日志怎么塞进Loki的labels字段?
Loki不解析日志内容,logfmt里的键值对不会自动变成标签。想让level=error可过滤,得在推送前手动提取并塞进logproto.EntryAdapter.Labels。
- 用
github.com/go-logfmt/logfmt解析日志行,提取level、trace_id等关键字段 - 构造
logproto.EntryAdapter时,把提取的字段转成map[string]string赋给Labels,不要塞进Entry.Line - 避免标签爆炸:单个
entry的Labels键数建议≤10,高频变动字段(如request_id)应放Line里,用| json | __error__查
Grafana里查不到Go服务日志的三个硬坑
不是配置问题,而是Loki查询机制和Go日志行为的隐性冲突。
立即学习“go语言免费学习笔记(深入)”;
-
time.Now().UnixNano()精度太高,Loki默认按毫秒去重,同一毫秒多条日志只存一条——改用time.Now().UnixMilli()或加随机后缀 - Go的
log包默认不带时间戳,Loki用接收时间当ts,导致排序乱;要么用log.SetFlags(log.LstdFlags),要么推送时显式填Entry.Timestamp - Grafana查询框里写
{job="my-go-app"} |= "panic",但Loki实际存的是原始日志行(含ANSI色码),得先| regexp "(?P<msg>.*panic.*)"再过滤
标签命名别用camelCase,Loki内部转成snake_case,serviceName会变成service_name,查的时候得对应上。


















