Sentry 揭示的问题:可观测性、稳定性与监控自有代码成本的变化
生产环境错误暴露了架构不匹配、事务恢复失败和无效日志。本文介绍一个小团队如何借助 Sentry 修复后端故障、准备浏览器监控并控制告警噪声。
过去,可观测性往往走向两个极端:要么整个 SRE 团队投入大量精力搭建没人看的仪表盘,要么完全跳过监控,直到客户发邮件才知道服务已宕机。到了 2026 年,这两种做法都不可接受。你需要知道哪里出了问题,但也不该为一款独立产品支付企业级价格。
本文介绍我们如何通过 Sentry 集成发现生产环境错误、据此做出哪些改动,以及如何配置监控以控制噪声和用量。我们也会看看可观测性工具正在如何适应小型工程团队。
为什么浏览器故障没有触发告警
从 3 月起,我们的后端就已接入 Sentry。DSN 存放在 Google Secret Manager 中,密钥挂载到 Cloud Run,每次启动都会运行 sentry_sdk.init。邮件告警也能收到。从外部看,一切正常。
但实际情况并非如此。前端没有接入 Sentry,浏览器异常、hydration 错误和分块加载失败都不可见。后端还把 Python 错误发送到了名为 javascript-nextjs 的项目,因为组织中只有这一个项目。堆栈跟踪堆在错误的位置,分组毫无帮助,仪表盘里混杂着不同语言的事件。
在处理单个错误之前,我们必须补上这个缺口,将浏览器故障和后端错误分开。
数据说明了什么
我们提取了过去 90 天的错误事件,发现了几个明显模式:
一次自行恢复的历史故障
这段时间内最常见的错误是社交注册接口触发的 Postgres StringDataRightTruncation,22 秒内出现 16 次。原因是典型的架构漂移:模型定义允许 800 个字符的个人简介,但生产数据库列仍是早期迁移留下的 VARCHAR(500)。用户提交了略长于 500 个字符的简介,Pydantic 层接受了请求,INSERT 却失败了。
将列扩展到 800 个字符的迁移早已编写,并在第二天早上完成部署。但更根本的问题仍然存在:模型和数据库架构可能彼此漂移,直到客户触发故障才有人发现。
我们采取了两项措施。首先,收紧社交注册请求架构,为邮箱、显示名称和令牌明确设置 max_length,让异常输入能够干净地返回 422,而不是抵达数据库。其次,扩展数据库完整性脚本,将 information_schema.columns.character_maximum_length 与应用程序预期长度进行比较。这样,如果未来迁移把列缩短到模型可能生成的长度以下,下次部署时完整性检查就会失败。
无法回滚的会话
错误列表中还有一串相关事件:POST /v1/upload 发生一次 OperationalError: server closed the connection unexpectedly,随后同一代码路径不断出现 PendingRollbackError。Postgres 在查询中途断开连接,SQLAlchemy 会话进入无效状态,而上传服务仍尝试在其上保存部分结果。该会话后续的每项操作都连锁失败。
修复很小,但很容易做错。现在上传流程捕获异常时,第一件事就是调用 db.rollback(),并用独立的 try/except 包裹,避免回滚失败掩盖原始错误。然后,部分保存逻辑会在干净的会话中运行。
把信息抹掉的日志
WebSocket 完成处理程序用 err=%s 记录捕获的异常。对多数异常来说,这能输出有用信息。但有少数异常类型的 __str__ 会返回空字符串,于是日志只剩下 err=,后面什么都没有。Sentry 事件能告诉我们保存失败,却没说明原因。
改用 logger.exception(...) 和 err=%r,成本为零,却能让之后的每条事件都包含足以辨认问题的信息。
不值得付费的噪声
队列里的其他项目并非程序缺陷。客户端在 SSL 期间中途断开时,uvloop 偶尔会抛出 RuntimeError: unable to perform operation on <TCPTransport closed=True>。这是正常行为,并非我们能修复的问题。每月 5,000 个错误的免费额度不该浪费在这上面。我们添加了 before_send 过滤器,丢弃匹配这些特定异常和值模式的事件。前端也采用相同思路过滤 ResizeObserver loop limit exceeded 等浏览器噪声。
按免费方案调整用量
截至2026年10月13日核查的Sentry当前Developer方案,每月免费提供5,000个错误、500万条追踪跨度和50次回放。追踪按跨度计量,而不是按旧版性能单位计量。选择采样率前,请查看当前方案限额:错误额度并不等于SDK所有信号都可随意发送。
我们的配置如下:
- 后端和前端都设为
tracesSampleRate: 0。分布式追踪确实有用,但每月 10K 个性能单位可能在一个糟糕的下午就耗尽。需要排查特定问题时,可以用较低采样率临时启用。 - 后端设为
profilesSampleRate: 0,理由相同。 - 前端禁用 Session Replay。集成代码仍保留,但两个采样率都设为零。如果排查严重错误确实需要回放上下文,可以将
replaysOnErrorSampleRate临时调为0.05,持续一天后再关闭。 - 两种运行环境都使用
before_send过滤器,丢弃已知无需处理的事件。
后端改动减少了可处理错误的噪声,而浏览器 SDK 配置只是为启用做好准备。这是两个不同的里程碑:只有代码和采样设置,并不能证明浏览器事件已抵达预期项目。
可观测性市场正在发生什么变化
我们按免费方案进行调整,是因为对于托管产品而言,Sentry 的免费额度相当慷慨。但相关经济条件正在变化,了解更广泛的趋势也很有必要。
在过去 12 到 18 个月里,有几方面发生了变化:
- 开放标准能减少迁移工作,但不能消除所有迁移工作。 兼容 OTLP 的埋点可以减少对某个监控后端的绑定。迁移时,厂商专属查询、仪表盘、告警规则和 SDK 功能仍需要规划和测试。
- 自托管会改变成本计算。 GlitchTip 和 原生支持 OTLP 的技术栈提供了其他监控途径。比较时要考虑存储、备份、升级和工程时间,而不是只拿虚拟机账单与订阅价格对比。
- AI 辅助调试拓展了工作流程。 Sentry 的 Seer 会提出根因和补丁建议;经授权的 MCP 集成则可把错误上下文带入编程助手。建议的修复在发布前仍需复现并通过回归测试。
- 方案限制也值得和功能一样仔细核对。 错误量、保留期限、采样和团队访问权限都可能影响账单。先确定所需信号和可衡量的事件预算,再按实际工作负载比较方案。
在本文对应的发布快照中,Sentry 满足了我们眼下的错误监控需求。尽可能使用开放接口能为团队保留更多选择,但迁移供应商时仍须检查项目路由、告警、保留数据和供应商专属功能。
部署检查补全监控配置
截至本文的 2026 年 5 月 17 日快照,还有两项部署工作尚未完成:
- 创建专用的 Python Sentry 项目,避免后端错误继续归入
javascript-nextjs。DSN 会在后端当前读取的同一个 Secret Manager 条目中替换。 - 在 Vercel 项目设置中配置前端 DSN,让客户端错误开始发送。代码已经存在,并会按条件初始化;目前缺少的只有环境变量。
无论部署什么监控,都应从每种运行环境发送受控的测试事件,并确认项目、环境、分组和上下文后,再宣布集成完成。拆分项目和设置环境变量属于配置步骤,并非事件已成功到达的证据。
这为何重要
看不到问题时,你要么在防御性编码上投入过多,要么投入不足并把缺陷发布出去。这两种做法都很昂贵。成本低且可靠的可观测性,让小团队也能像更大的团队一样工作:在客户发现之前捕捉回归,不靠猜测修复,并把工程时间用于构建新功能。
真正有用的经验是两头都要验证:既验证应用的修复,也验证负责揭示下一次回归的监控链路。