返回文章列表

日志、指标、Tracing 的边界,不是按工具划的,是按决策成本划的

指标负责发现异常,Tracing 负责收窄路径,日志负责还原现场;三者混用,只会把排障成本一起抬高

很多团队补可观测性,第一反应是“把日志、指标、Tracing 都接上”。

这句话听起来没错,真正出问题的是下一步:三件东西都接上了,但边界没定,于是每一种手段都在替另外两种擦屁股。

结果通常很眼熟:指标标签爆炸,Tracing 采样一路上调,日志量每月翻倍,告警还是不准,排障还是靠人肉 grep。工具一个没少,系统却没有真正变得更可观察。

我的判断是:日志、指标、Tracing 的边界,不该按“数据长什么样”来划,而该按“你下一步要做什么决策”来划。

  • 指标回答的是:要不要立刻处理,影响范围大不大;
  • Tracing 回答的是:问题大概卡在链路哪一段;
  • 日志回答的是:那一段代码在那个请求里到底发生了什么。

三者不是信息量递增的关系,而是决策成本递增的关系。指标最便宜,适合持续盯盘;Tracing 更贵,适合收窄范围;日志最重,适合最后还原现场。

如果你让日志承担报警,让 Tracing 承担审计,让指标承载每个用户、每个订单、每个 SQL 维度,系统当然也能跑,但代价会非常诚实地出现在存储、查询、采样、基数控制和人力排障上。

真正先做决定的,应该是指标

线上出了毛刺,第一步通常不是“看细节”,而是“判断值不值得立刻处理”。

这一步最适合指标,不是因为指标更高级,而是因为它最便宜。

一个好的指标系统,应该让你在几十秒内回答下面几件事:

  • 错误率是在抬头,还是只是偶发噪声;
  • 延迟变差是全局性的,还是只集中在某个接口;
  • 影响是一台机器、一个机房,还是整条调用链;
  • 问题是刚发生,还是已经持续半小时。

这些问题本质上都在做同一件事:用低成本聚合信息,换取高价值的行动判断。

所以指标最重要的设计原则不是“字段越多越好”,而是“聚合后还能支持决策”。

很多团队把指标做坏,往往不是监控埋少了,而是把本不该放进指标的高基数字段硬塞进去,比如 user_idorder_idtrace_id、完整 URL、动态错误消息。这样做短期很爽,感觉什么都能切;中期就会开始看到存储膨胀、查询变慢、告警维度失控;长期的结果通常是团队自己把指标平台用怕了。

指标适合表达的是稳定维度下的趋势和分布,比如接口名、状态码、机房、依赖服务、缓存命中与否。这些维度的价值不在于“还原具体一次请求”,而在于帮助你快速判断问题是否成片发生。

一旦你想问的是“到底哪一个订单失败了”,那就已经不是指标该独自回答的问题了。

Tracing 的价值,不是记录一切,而是缩短定位路径

Tracing 经常被误解成“比日志更高级的日志”。这会直接把它用废。

Tracing 真正擅长的,是描述一次请求跨服务、跨组件的路径和耗时关系。它天然适合回答这种问题:

  • 慢,是慢在网关、应用、数据库还是外部依赖;
  • 一次重试,是在哪一跳被放大的;
  • 某个接口的 P99 飙高,是否和某个下游服务相关;
  • 一个异常请求在经过哪些服务后开始偏离正常路径。

也就是说,Tracing 提供的是链路结构,不是完整现场。

所以它最该承载的是路径信息、关键阶段耗时、少量能帮助筛选的标签,而不是把业务对象完整塞进去,更不是把每个局部变量都变成 span attribute。

我见过不少团队一上 tracing,就想把它做成统一真相源:SQL 原文要挂、用户输入要挂、完整响应体要挂、所有重试参数要挂。最后的结果不是“排障更快”,而是:

  • span 体积迅速变大,采样率被迫下调;
  • 查询链路时噪声远大于信号;
  • 真到事故现场,关键请求反而因为采样没留下来;
  • 敏感数据治理开始变成新的维护成本。

Tracing 最有价值的时候,不是信息最多的时候,而是你能用一条链路迅速判断下一跳应该看哪个服务、哪个 span、哪一段日志的时候。

如果它已经重到不能全局稳定保留,或者重到查询一次都很痛苦,那说明边界已经越过了。

日志不是第二套指标系统,它是最后的取证材料

日志最容易让人误判,因为它看起来什么都能装。

确实,日志最接近现场。分支怎么走的、参数长什么样、重试第几次、命中了哪个降级路径、为什么这次返回了一个看似成功却语义错误的结果,很多时候都只能从日志里看出来。

但也正因为它信息熵最高,所以它最不适合承担“全局持续观察”这件事。

把日志当主监控源,常见后果有三个。

第一,查询成本高。 你每次都在从原始事实里临时拼结论,速度慢,稳定性也差。

第二,噪声极大。 日志量一大,团队就会自然减少打印;一旦减少打印,关键分支又经常缺证据;最后大家会在“太多看不完”和“太少看不出”之间来回摆。

第三,它会诱导错误的工程习惯。 很多开发者一遇到问题就多打一层日志,结果系统不是更清晰,而是更吵。真正该补的是边界清楚的事件日志、带上下文的错误日志和可关联的 request id,而不是更多“进入方法”“离开方法”“开始处理”“处理完成”。

日志最合适的位置,是在你已经靠指标判断出“这里真的有问题”,靠 tracing 知道“问题大概出在这里之后”,再用它还原具体一次请求。

换句话说,日志应该服务于取证,而不是承担巡逻。

一个简单分工,比“三件都打满”更有效

我更推荐的做法很朴素:先定义排障顺序,再定义采集边界。

可以把一次线上排障拆成三步。

  1. 先用指标判断有没有系统性问题;
  2. 再用 tracing 把问题收敛到服务和链路阶段;
  3. 最后用日志解释那次请求为什么走成这样。

如果你的埋点设计不能支持这个顺序,通常不是工具不够,而是职责分错了。

下面是一种相对克制的写法:

func CreateOrder(ctx context.Context, req CreateOrderReq) error {
    start := time.Now()
    defer metrics.OrderCreateLatency.Observe(time.Since(start).Seconds())

    ctx, span := tracer.Start(ctx, "order.create")
    defer span.End()
    span.SetAttributes(
        attribute.String("payment_provider", req.Provider),
        attribute.Bool("has_coupon", req.CouponID != ""),
    )

    err := service.Create(ctx, req)
    if err != nil {
        metrics.OrderCreateErrors.WithLabelValues(classify(err)).Inc()
        logger.Error("create order failed",
            "request_id", requestid.FromContext(ctx),
            "provider", req.Provider,
            "err", err,
        )
        return err
    }
    return nil
}

这里面有三个边界是故意保持克制的。

  • 指标只保留聚合后仍然有决策价值的维度,比如错误分类;
  • tracing 只挂少量能帮助筛选路径的属性,而不是整个请求体;
  • 日志只在失败路径记录关键上下文,并且保证能通过 request_id 关联到链路。

这套设计不花哨,但它解决的是一个很现实的问题:出了事之后,团队能不能按成本从低到高地逼近答案,而不是一上来就扎进最贵的数据里。

一个常见误区:把“可观测性统一”理解成“数据全部汇总”

现在很多平台都在讲统一观测。这件事本身没问题,问题出在实现方式上。

有些团队把统一理解成“所有数据进一个平台,所有字段彼此打通,最好一次查询解决所有问题”。这种想法很诱人,因为它像是在消灭工具边界;但工程上,它经常是在消灭成本边界。

统一的正确方向,不是让三种数据长得越来越像,而是让它们能低摩擦地关联起来。

比如:

  • 指标告警能直接跳到相关服务和时间窗;
  • tracing 能按 request_id 或错误码找到对应日志;
  • 日志能带上 trace 上下文,而不是各自为政。

这叫联通,不叫混用。

真正危险的不是平台多,而是所有问题都只能靠最重的那层数据来回答。

反例和边界:不是所有系统都需要三件套拉满

也要承认,有些场景里不必把边界讲得这么完整。

低 QPS 的内部工具、单机批处理脚本、非常稳定的离线任务,日志就可能已经够用;请求链路很短、依赖关系很简单的服务,tracing 的收益未必有想象中高;某些受合规约束的审计场景,也不该指望 tracing 或普通应用日志来充当正式审计记录。

所以这篇文章不是在说“每个系统都必须把日志、指标、Tracing 配齐”,而是在说:只要你决定做三件事,就不要让它们互相替班。

系统越复杂,职责越需要收束。否则今天省掉的是设计边界,明天补上的就是平台账单、排障时间和团队认知负担。

结尾

可观测性最怕的,不是工具少,而是每一层都想回答所有问题。

指标应该让你尽快决定是否行动,Tracing 应该让你尽快决定先看哪里,日志应该让你尽快知道到底发生了什么。

这三个动作顺序一乱,采得再全,也只是把排障成本埋得更深。