← 返回教程库

可观测与迭代:日志 / 监控 / 错误追踪 / 灰度,上线后怎么知道它在好好跑

最后更新 2026-06-22
你将学到
  • 搭起"错误追踪 + 关键日志 + 可用性报警 + 灰度"这套上线后可观测的最小配置
  • 学会写结构化日志,知道记什么、绝不记什么(敏感信息)
  • 用错误追踪工具自动收线上异常,不再靠用户截图来发现 bug
  • 出故障时按一条固定流程从报警查到根因,而不是干瞪线上

你的产品上线了,朋友圈也发了,第一批用户进来了。然后某天下午,有人在群里甩来一张截图:"你这个保存按钮点了没反应啊?"你打开自己电脑试了一下——好好的,能用。你心里一沉:它在用户那边到底出了什么事,你完全不知道。 你看不到线上发生了什么,没有日志、没有报错记录、没有任何报警,整个线上服务对你来说是一个黑盒子。

这一节就是来把这个黑盒子照亮的。读完你会搭起一套最小的「可观测」体系:线上一报错你立刻收到通知、关键操作留得下痕迹、服务挂了有报警把你叫醒、改动先放给一小撮人试。这篇讲的是运维层面的可观测——它在不在好好跑、报没报错、能不能访问。至于「用户激活了没、留存怎么样、哪个按钮点的人多」这类产品数据指标,是另一回事,在数据闭环 build-measure-learn 那一节讲,这里不重复。

这篇适合谁:你已经把产品部署上线了,但上线之后基本是「发完就不管」的状态,全靠用户反馈才知道出了问题。读完你会从「被动等用户报 bug」变成「线上一有事我先知道」。


先想清楚:可观测到底要回答哪三个问题

别一上来就装一堆工具。可观测的本质,是让你在不去翻用户电脑的情况下,回答三个问题:

  1. 它还活着吗?——服务能不能访问,首页打不打得开。这是「可用性」。
  2. 它报错了吗?——有没有代码抛异常、接口返回 500、用户操作失败。这是「错误」。
  3. 它当时在干什么?——某个时刻、某个用户、走到了哪一步、参数是什么。这是「日志」。

这三个问题对应三类工具:可用性监控回答第一个,错误追踪回答第二个,结构化日志回答第三个。一人产品不需要搞得多复杂,把这三样各搭一个最简版本,你的线上就从「全黑」变成「能看见」了。

记住一个判断口诀:可观测不是为了好看的仪表盘,是为了出事时你能在五分钟内说出「哪坏了、谁受影响、从什么时候开始」。 凡是帮不上这个的,都先别加。


第一件事:结构化日志——记什么,和绝不记什么

很多人写日志就是一句 console.log("到这了")console.log(data),出了事翻日志全是一堆没头没尾的字符串,根本对不上是谁、什么时候、哪个请求。

结构化日志的意思是:每条日志不是一句话,而是一条带固定字段的记录(通常是 JSON),机器能解析、能搜索、能过滤。

一条够用的结构化日志,至少带这几个字段:

{
  "time": "2026-06-22T14:03:11Z",
  "level": "error",
  "event": "order_save_failed",
  "requestId": "req_8f3a1c",
  "userId": "u_1024",
  "msg": "保存订单写库失败",
  "detail": "connection timeout"
}
  • time:什么时候。用 UTC 或带时区,别用模糊的「刚才」。
  • level:严重程度。常见分级 debug / info / warn / error。线上默认只输出 info 及以上,debug 平时关掉,免得淹没。
  • event:发生了什么,用固定的事件名(如 order_save_failed),方便日后按名字搜。
  • requestId:一次请求的唯一编号。同一个请求里所有日志都带上它,出事时你能把一次操作的全过程串起来看。这是最值钱的一个字段
  • userId:是谁触发的(注意见下方红线,用 ID 不用敏感信息)。

你应该看到什么:接好之后,去你的日志面板里按 requestId 一搜,某一次请求从进来到出错的每一步都连成一串,你能顺着读出「它当时在干什么」。

这条红线千万别踩:绝不记敏感信息

日志会被存下来、可能被多人看到、可能进第三方平台。以下这些绝不能进日志

  • 明文密码、密码哈希
  • 完整的银行卡号、身份证号、手机号(要记就脱敏,如 138****6612
  • API 密钥、token、session 内容
  • 用户的完整地址、聊天/订单的敏感正文

判断方法:假设这份日志哪天被截图发到了网上,里面有没有哪条会让你或用户出事? 有就脱敏或不记。记 userId 这种内部 ID 没问题,记用户手机号就是事故。


第二件事:错误追踪——让异常自己来找你

日志是「你想看才去查」,错误追踪是「一出错就主动推给你」。这是上线后回报最高的一件事,因为它把你从「等用户截图」里解放出来。

错误追踪工具(如 Sentry 这类,具体用法以官方为准)做的事是:你在代码里接一个 SDK,线上一旦有未捕获的异常、报错、接口失败,它自动把错误堆栈、发生时间、影响了多少用户、当时的环境信息收集起来,分组聚合,然后给你发通知(邮件、Slack、微信机器人都行)。

它帮你解决三个靠日志很难做到的事:

  • 自动发现:你不用守着,错误一发生就推送到你这。
  • 去重聚合:同一个 bug 发生一千次,它聚成一条,并告诉你「影响 326 个用户、首次出现在两小时前」,而不是刷屏。
  • 带现场:报错堆栈精确到哪个文件哪一行,前端还能带上用户的浏览器、操作路径,定位起来快得多。

接入的大致路子(前后端类似,配置字段以官方文档为准):

// 伪代码示意:在应用启动时初始化错误追踪 SDK
import * as ErrorTracker from "错误追踪SDK";

ErrorTracker.init({
  dsn: process.env.ERROR_TRACKER_DSN, // 你的项目接入地址,放环境变量别硬编码
  environment: process.env.NODE_ENV,  // 区分 production / staging
  tracesSampleRate: 0.1,              // 采样率,控制量和成本,按需调
});

你应该看到什么:接好后,故意在代码里抛一个错(比如访问一个 undefined 的属性),刷一下页面,几秒到几十秒内,你的错误追踪面板里就冒出一条新错误,带着堆栈和「production」标签。这就说明现场已经接通了——以后真出 bug,你比用户先知道。

一人产品的省力做法:错误追踪用免费额度起步就够。重点不是收集得多全,而是通知一定要响——配好推送,让它能在你不盯屏幕时把你叫住。


第三件事:可用性与响应时间监控——别闷声挂了

错误追踪能抓到「代码报错」,但抓不到一种更糟的情况:整个服务挂了,连报错的机会都没有——服务器宕机、域名解析坏了、构建挂了发了个白屏。这种时候没有任何异常被抛出,你的错误追踪面板一片安静,而用户那边已经全是打不开。

补这个洞的是可用性监控(也叫 uptime / 心跳监控)。原理很简单:一个外部服务每隔一小段时间(比如每分钟)去请求你的网址,看它

  • 通不通(HTTP 状态码是不是 200)
  • 多久才回(响应时间)
  • 内容对不对(可选:检查页面里有没有某个关键词,防「200 但白屏」)

一旦连续几次请求失败,它就触发报警,通过短信、邮件、电话、群机器人把你叫醒。这类工具不少都有免费档(具体能力以官方为准),对一人产品足够。

给两个值得加的「探针」:

  • 首页探针:测你的主域名,确认站还活着。
  • 健康检查接口:在后端开一个极简的 /health 接口,里面顺手检查一下「数据库连得上吗」,返回 200/500。让监控去打这个接口,它一红,往往意味着不只是页面挂了,是底层依赖出了问题。
// 一个最小健康检查接口的思路
app.get("/health", async (req, res) => {
  try {
    await db.ping();           // 真去戳一下数据库
    res.status(200).send("ok");
  } catch (e) {
    res.status(500).send("db down");
  }
});

你应该看到什么:配好监控后,主动把服务停掉一分钟(或临时让 /health 返回 500),过一两分钟,你应该收到一条报警通知。收到了,说明这套「闷声挂了也有人叫你」的机制真的通了。没收到,就去查报警渠道配置——报警发不出去,等于没装


第四件事:灰度发布——改动先放给一小撮人

前面三样是「出事后能看见」,灰度是「出事前先缩小爆炸半径」。

灰度发布的意思是:一个新版本或新功能,不一上来就放给全部用户,而是先放给一小撮(比如 5%),观察一段时间,错误率、响应时间都正常,再逐步放到 20%、50%、100%。一旦那一小撮里冒出问题,你只影响了 5% 的人,而且可以立刻回退。

对一人产品,灰度不必搞得很重,常见几种由轻到重的做法:

  1. 功能开关(feature flag):把新功能用一个开关包起来,先只对自己或内测名单开。最轻量,自己写个配置就能做。
  2. 按比例放量:用一个随机或按 userId 取模的判断,让一定比例的用户走新逻辑。
  3. 平台级灰度:有些托管平台支持把流量按比例切到新部署版本(具体能力以官方为准),不用自己写。
// 最朴素的功能开关思路
const ROLLOUT_PERCENT = 5; // 先放 5%
function inRollout(userId) {
  // 用 userId 做稳定哈希,保证同一个人每次结果一致
  return hashToPercent(userId) < ROLLOUT_PERCENT;
}

if (inRollout(currentUser.id)) {
  renderNewCheckout(); // 新版
} else {
  renderOldCheckout(); // 旧版
}

配合前面的错误追踪和监控一起用,灰度才有意义:放量后盯着错误率看,没异常再加比例,一冒头就把开关关回去。 灰度本身不解决 bug,它解决的是「让 bug 只伤到一小撮人,而且能秒退」。


增量一:上线后可观测最小配置 checklist

新产品上线那天,对着这张表过一遍,四样齐了你就从「黑盒」变「能看见」了:

  • 错误追踪:接好 SDK,故意抛一个错,确认面板能收到、通知能弹出
  • 关键日志:核心操作(注册/支付/保存这类)都打了结构化日志,带 requestIduserId,且确认没有任何敏感信息进日志
  • 可用性报警:配了首页 + /health 探针,停一下服务确认能收到报警,报警渠道(短信/群机器人)真的响
  • 灰度能力:至少有个功能开关,能把新功能只放给一小撮人,能一键关回去
  • 日志级别:线上默认 info 及以上,debug 关掉,别让噪音淹没真问题
  • 联系方式:所有报警都接到你会及时看到的地方(别只发邮件然后从不查邮箱)

这四样的优先级:错误追踪 > 可用性报警 > 结构化日志 > 灰度。预算和精力有限就按这个顺序来,先把「出错能知道、挂了有人叫」搭上。


增量二:出故障了,照这条流程定位

线上真出事时,最怕的是慌——东点一下西看一眼,越查越乱。固定走这条流程,能让你冷静、有序地从「报警」逼近「根因」:

  1. 确认范围:先看可用性监控和错误追踪面板。是整站挂了(监控全红)还是某个功能报错(错误追踪冒出某一类)?是所有人都中招还是只有一小撮?先框定爆炸半径,别一上来钻细节。
  2. 看时间线:这事从什么时候开始的?对照一下——那个时间点你是不是刚 git push 了、刚改了配置、刚到某个流量高峰?绝大多数线上故障,时间线一对就破了一半案。
  3. 顺着 requestId 钻:从错误追踪里挑一条具体报错,拿到它的 requestId,去日志里搜,把这一次请求从头到尾的轨迹拉出来,看它走到哪一步崩的、参数是什么。
  4. 能回退先回退:如果时间线指向「刚上的那次改动」,别急着现场修——先回退到上一个好版本(回滚部署或关掉灰度开关),让用户先恢复正常,你再慢慢查根因。止血优先于破案。
  5. 复盘留痕:修好后记一句:什么坏了、为什么、怎么发现的、下次怎么早点发现。一人产品也值得有个简单的故障记录,下次同类问题查得飞快。

把这五步记成肌肉记忆,你就从「线上一出事就手忙脚乱」升级成「按流程稳稳查到根因」。


故障排查:可观测本身没搭好的三个典型坑

可观测这套东西,最讽刺的是它自己也会出问题——你以为接好了,真出事时却不顶用。对号入座:

现象 最可能的原因 怎么办
用户报了 bug,错误追踪面板里却查不到 异常被你代码里的 try/catch 吞了、或前端错误没上报、或采样率把它丢了 检查有没有「catch 了但啥也没做」的地方,确认前端 SDK 接了、采样率别设太低;关键路径的错误不要采样
日志哗哗刷,真出事时根本找不到那条 debug 没关、什么都往日志里塞、没分级、没 requestId 线上调到 info 及以上,去掉无意义的 console.log,给日志加 event 名和 requestId 才能搜
服务挂了一晚上,第二天才从用户那知道 压根没配可用性报警,或报警发到了你不看的渠道 补上 uptime 监控 + /health 探针,报警接到会响的渠道,并真的测一次确认能收到
错误追踪天天弹一堆无关报警,最后你直接不看了 噪音错误(爬虫、浏览器插件、用户网络抖动)没过滤 把已知无害的错误加进忽略名单,只让真正需要你处理的弹出来——报警太吵和没报警一样糟
灰度放了量,但出问题时不知道是哪一拨人 灰度没和日志/错误追踪打通,分不清新旧版本 在日志和错误上打个「版本/灰度组」标签,出事能一眼看出是不是新版本的锅

这里最值钱的一条是最后一类的反面:报警的可信度比覆盖率更重要。 一个天天误报的报警系统,最终会被你忽略,等于没有。宁可少报、报得准。


动手挑战

挑一个真做了才算掌握:

  1. 给你已上线的项目接一个错误追踪工具,故意抛一个错,确认你的手机/群里收到了通知,并能从面板看到堆栈——亲手走通「报错主动找你」这条链路。
  2. 给后端加一个 /health 接口,接一个可用性监控去打它,然后故意让它返回 500 一分钟,看你多久收到报警、报警长什么样。
  3. 进阶:挑一个不影响主流程的小改动,用功能开关做一次灰度——先只对自己开,确认无误再放给一小撮,体会「先小范围、再放量」的安全感。

小结 · 你现在掌握了什么

  • 你知道可观测就是回答三个问题:它还活着吗、它报错了吗、它当时在干什么,分别对应可用性监控、错误追踪、结构化日志。
  • 你会写带 requestIduserId 的结构化日志,更重要的是知道密码/卡号/密钥这些绝不能进日志
  • 你能接错误追踪让异常自己找上门、配可用性报警防止闷声挂了、用功能开关做灰度把爆炸半径缩到一小撮。
  • 你手里有一张「上线最小可观测 checklist」和一条「从报警到根因」的固定排查流程,出事时不再干瞪线上。

可观测的价值,在你出事的那一天才会兑现——而那一天一定会来。提前搭好,你就是「线上一有事我先知道」,而不是「等用户来告诉我」。

下一步:能看见线上发生什么之后,下一个绕不开的问题是「它扛得住流量吗、会不会烧光预算」——去看本级性能与成本:让小产品扛得住又不烧钱 那一节。想区分清楚「运维可观测」和「产品数据指标」,去看数据闭环 build-measure-learn;想看自己在整条路上的位置,对照三支柱路线图

👉 看看我们的 AI 编程实战体系课,或逛 AI 编程教程大全 把基本功打扎实。

📄 来源 / 自校链接

本文为学习整理,关键步骤与代码请结合下列官方来源验证。

内容有错、看不懂、或想看下一期?告诉我们 →

本文为学习与落地整理,AI 工具与平台更新较快,关键步骤请结合官方最新资料验证。见免责声明