目录
- 为什么 Sentry 自己打不了电话
- 你需要什么
- 第 1 步 —— 建一个会响铃的频道
- 第 2 步 —— 创建 Sentry internal integration
- 第 3 步 —— 把集成挂到告警规则上
- 第 4 步 —— 搞清楚到底收到了什么
- 第 5 步 —— 过滤到「值得一通电话」的程度
- 第 6 步 —— 给警告级别留一扇安静的门
- 只在下班时间响
- 两个坑
- 载荷大小、错误风暴与截断
- 和团队共享
- 这套方案给不了你什么
- 排障
- 常见问题
- Sentry 能原生打电话吗?
- Sentry 告警能穿透勿扰模式吗?
- 用 Webhook 需要付费的 Sentry 套餐吗?
- 为什么我的 Sentry 模板变量是空的?
- 怎么只对某一个环境告警?
- 同一个错误能同时打给两个人吗?
- 过滤应该放在 Sentry 还是 Echobell?
- 小结
- 相关内容
Sentry 不能给你打电话。它能发邮件、发 Slack、把告警交给 PagerDuty——但没有内置的语音动作。想在不买一整套事件管理平台的前提下拿到这个能力,办法是把 Sentry 的 issue 告警发给一个会响铃的 Webhook:建一个 internal integration,指向 Echobell 的来电频道,再在前面加一层过滤,只让真正压垮生产的错误通过。
这篇文章讲完整链路:集成、告警规则、Sentry 真正发出的载荷、读取它的模板,以及让大多数人半途放弃的两个坑。
为什么 Sentry 自己打不了电话
Sentry 的 issue 告警动作分三类:通知(邮件、Slack、Discord、Microsoft Teams)、建工单(Jira、GitHub、Azure DevOps)、交给寻呼产品(PagerDuty、Opsgenie)。每一类的终点要么是一块你得正好在看的屏幕,要么是另一个平台上按人头收费的席位。
下午两点这没问题。凌晨三点,一条 Slack 消息和静音没有区别,推送通知也打不过勿扰模式。对于那一小撮「晚两小时就要真金白银亏钱」的错误——结账接口全返 500、登录全被拒、后台任务在悄悄丢单——你需要的是一台会响的设备。
Webhook 就是这个接口。Sentry 可以把任意 HTTPS 端点作为告警规则的动作;Echobell 则把这个 HTTP 请求变成能穿透 iOS 专注模式的来电式提醒。
你需要什么
- 一个你能进到 Settings → Developer Settings 的 Sentry 组织(owner 或 manager 权限)
- 装好 Echobell(App Store / Google Play)
- 五分钟
你这边不需要任何公网可达的东西。请求是 Sentry 主动发出的,你只负责接收。
第 1 步 —— 建一个会响铃的频道
在 Echobell 里新建频道,通知类型选 来电(Calling)。这正是整件事的意义所在:来电频道的行为像一通打进来的电话而不是推送,所以它能穿过专注模式和勿扰模式。
模板要写成凌晨三点也能看懂的样子。Sentry 的载荷嵌套很深,所以变量路径比平时长:
标题:{{data.event.level}}: {{data.event.metadata.type}}
正文:{{data.event.title}} — {{data.event.culprit}}
在高级设置里配好链接模板,这样点通知就能直接打开这个 issue:
{{data.event.web_url}}
从频道详情页复制 Webhook URL,形如:
https://hook.echobell.one/t/<channel-token>
第 2 步 —— 创建 Sentry internal integration
Sentry 只有通过 integration 才把 Webhook 暴露成告警规则动作,所以你必须建一个。它只是一个表单,不是一个服务——你不用写任何代码。
- 进入 Settings → Developer Settings → Custom Integrations
- Create New Integration → Internal Integration
- Name:
Echobell(这就是你稍后在告警规则里选的名字) - Webhook URL:第 1 步拿到的频道 URL
- 打开 Alert Rule Action 开关
- Permissions:
Issue & Event→ Read 就够了 - Webhooks 下面的复选框全部不要勾——原因见下面的坑
- 保存
internal integration 只在你自己的组织内可用,并且会自动安装。这套配置用不到它生成的 token。
第 3 步 —— 把集成挂到告警规则上
进入 Alerts → Create Alert → Issue Alert,或者编辑已有规则。
在 Then perform these actions 里添加 Send a notification via an integration,选 Echobell。
把 Action interval(「同一条告警重复触发时」的节流)至少设成 30 minutes。默认是每次触发都发,一个每分钟报 400 次的错误会一直打你电话,直到你把它关掉为止。
保存,然后用规则的测试/预览功能跑一次,先看到真实载荷到达,再去信任它。
第 4 步 —— 搞清楚到底收到了什么
大多数配置死在这一步,因为载荷的形状和你猜的不一样。Sentry 把所有东西都包了一层:
{
"action": "triggered",
"actor": { "id": "sentry", "name": "Sentry", "type": "application" },
"data": {
"event": {
"event_id": "e4874d664c3540c1a32eab185f12c5ab",
"level": "error",
"title": "ReferenceError: heck is not defined",
"culprit": "?(<anonymous>)",
"platform": "javascript",
"project": 1,
"release": null,
"metadata": { "type": "ReferenceError", "value": "heck is not defined" },
"tags": [["level", "error"], ["browser", "Chrome 75.0.3770"]],
"issue_id": "1117540176",
"issue_url": "https://sentry.io/api/0/issues/1117540176/",
"web_url": "https://sentry.io/organizations/test-org/issues/1117540176/events/e4874.../"
},
"triggered_rule": "Very Important Alert!"
},
"installation": { "uuid": "a8e5d2..." }
}
动手写模板之前,有四件事值得先知道:
- 有用的东西全在
data.event底下。{{title}}什么都渲染不出来;{{data.event.title}}才是那条错误。 data.event.project是数字 ID,不是 slug。 想让通知里出现可读的项目名,就把它当字面量写进频道标题模板,并且一个项目配一个频道。- 没有
environment字段。 环境是以["environment", "production"]这样的键值对出现在data.event.tags里的,而且它在数组里的位置不固定——所以别按下标取。环境过滤放到 Sentry 规则里做(第 5 步)。 data.triggered_rule是规则名。当一个频道服务多条规则时,把它放进正文里很有用。
issue 告警的 Sentry-Hook-Resource 请求头是 event_alert。你可以在 Echobell 频道条件里要求它,这样别的东西就没法触发这个频道:
header["sentry-hook-resource"] == "event_alert"
第 5 步 —— 过滤到「值得一通电话」的程度
一个每来新 issue 就响铃的来电频道,比没有这个频道还糟:一周之内你就会把它静音,然后真正要紧的那次它也不会响。过滤要放在两个地方。
在 Sentry 里,用规则自带的 conditions 和 filters:
| 目标 | 规则配置 |
|---|---|
| 只要生产环境 | 把规则的 Environment 设为 production |
| 只要真的坏了 | Filter:The event's level equals fatal(或 error) |
| 别为偶发抖动响 | Condition:The issue is seen more than 25 times in 1 hour |
| 只盯关键路径 | Filter:The event's tags match transaction contains /checkout |
| 只要回归 | Condition:A resolved issue changes state from resolved to unresolved |
在 Echobell 里,把频道条件当兜底,用来表达 Sentry 表达不了的东西,或者用来应付今天改不动的规则:
data.event.level == "fatal" || data.event.level == "error"
严重级别一般还是在 Sentry 规则里筛更好,因为节流也在那儿。放在 Echobell 里更好的场景是:你想用一条 Sentry 规则喂出两档紧急程度。
第 6 步 —— 给警告级别留一扇安静的门
分级的意义在于让「电话」保住它的分量。再建一个 时效性(Time Sensitive) 类型的 Echobell 频道,再加一条门槛更低的 Sentry 规则,指向第二个 internal integration(一个集成只存一个 Webhook URL,所以第二个频道需要第二个集成)。
一套能扛过真实一周的配置大致长这样:
| Sentry 规则 | 级别 / 阈值 | Echobell 频道 | 行为 |
|---|---|---|---|
prod-fatal | fatal,生产 | 来电 | 穿透专注模式响铃 |
prod-error-spike | error,1 小时超 100 次 | 时效性 | 直接上锁屏,不响铃 |
new-issue-digest | 任意新 issue | 普通 | 普通推送,有空再看 |
只在下班时间响
白天你本来就盯着 Sentry。Echobell 给条件提供了 UTC 系统时间变量,所以一个频道不用再加一条 Sentry 规则就能按小时区别对待:
data.event.level == "fatal" && (hour >= 17 || hour < 9)
如果你的周末是真的休息,再加一个星期判断:
data.event.level == "fatal" && (hour >= 17 || hour < 9 || dayOfWeek == 0 || dayOfWeek == 6)
这些全是 UTC,定死数字之前先从你自己的时区换算一遍。完整变量表见条件参考。
两个坑
坑 1:勾了 Webhooks 那几个框。 internal integration 有两条互相独立的 Webhook 路径。Alert Rule Action 开关让这个集成能在告警规则里被选中——这是你要的那条。而 Webhooks 复选框(issue、error、comment)订阅的是该资源的每一个事件:整个组织范围内每次 issue 被创建、解决、指派、归档、忽略。勾上 issue,同事解决一个问题你的电话就会响。全都不勾,就只有你的告警规则会触发 Webhook。
坑 2:用了旧版 Webhooks 插件。 老的按项目配置的 Legacy Integrations → WebHooks 插件还在,也还能用,而且看起来像条捷径——不用建集成就能粘个 URL。但它的载荷结构不一样(更扁平),请求没有签名,Sentry 自己也在把新用户往别处引。如果你用它,上面那些变量路径全都得换。请用 internal integration。
载荷大小、错误风暴与截断
规模上来之前,有三个限制值得先知道:
- 1 MiB 请求体。 超过 1 MiB 的触发请求会被 Echobell 以 HTTP 413 拒绝。Sentry 的载荷带着完整堆栈和请求上下文,通常落在几十 KB,但一个带巨大请求体的事件可能逼近上限。Sentry 那边没有
max_alerts这种旋钮,所以缓解办法是在 SDK 的beforeSend里清洗大的请求体——这件事你出于隐私考虑本来也该做。 - 每个 token 每分钟 120 次请求。 超过之后触发接口会返回
429、RATE_LIMIT_EXCEEDED和一个Retry-After。让你待在线内的正是 Sentry 的 action interval,30 minutes绰绰有余。 - 通知正文 1500 字节。 更长的渲染结果在到达设备前会被截断。
data.event.title加culprit很宽裕;把data.event.exception整个倒进去则不行,而且在锁屏上根本读不了。细节留给链接模板。
和团队共享
一个 Echobell 频道可以被多人订阅,每个订阅者各自选自己的通知类型。所以同一条 Sentry 规则可以让值班工程师的手机响铃,同时对其他人只是一条普通推送——没有按人头计费,也没有排班配置。
它不是升级策略。这里没有「五分钟没人确认就打给下一个人」。真需要那个,你需要一个真正的 on-call 平台;Echobell 覆盖的是它下面那层投递。
这套方案给不了你什么
不如把话说明白:
- 没有确认(ack)。 接起电话不会告诉 Sentry 任何事,也不会让其他订阅者的手机停下来。
- 没有排班和升级。 要么订阅的人都收到,要么都收不到。
- 除 Sentry 之外没有额外去重。 分组和节流都发生在 Sentry 规则里,Echobell 只投递到达的东西。
- 没有双向同步。 在 Sentry 里解决问题不会清掉你手机上的任何东西。
如果这些是硬伤,那这不是对的工具。如果你真正需要的是「结账坏了就把我叫醒」,它大概是拿到这个结果最便宜的可靠方式。
排障
规则触发了但什么都没到。 检查集成里的 Alert Rule Action 是不是开着。如果是关的,这个集成根本不会出现在规则的动作列表里——而在你打开它之前保存过的规则,会保留一个失效的动作。
收到通知但内容是空的。 你的模板在读顶层键。Sentry 把所有东西都嵌在 data.event 下面。
响了些你没预料到的东西。 先查集成上的 Webhooks 复选框(坑 1),再看规则的 environment 是不是留在了 "All Environments"。
同一个错误反复响。 调高 Sentry 规则的 action interval。Echobell 的重试是另一回事——应用设置里的 重试失败来电 是在你漏接时重拨,不是一回事。
连测试都收不到。 先用 curl 触发一次频道,排除 Echobell 这一侧:
curl -X POST https://hook.echobell.one/t/<channel-token> \
-H 'Content-Type: application/json' \
-d '{"data":{"event":{"level":"fatal","title":"Test error","culprit":"manual test","metadata":{"type":"TestError"}}}}'
如果这个响了而 Sentry 不响,问题在集成,不在频道。
常见问题
Sentry 能原生打电话吗?
不能。Sentry 的 issue 告警动作只有通知、建工单,以及和寻呼类产品的集成。语音电话需要外部服务——要么是 PagerDuty 这类寻呼平台,要么是一个会响铃的 Webhook 接收端,比如 Echobell。
Sentry 告警能穿透勿扰模式吗?
只有当它以来电式提醒到达时才能。来电类型的 Echobell 频道行为像一通打进来的电话,iOS 的专注模式和勿扰模式会放行。任何应用的普通推送都不行。
用 Webhook 需要付费的 Sentry 套餐吗?
internal integration 和告警规则动作在 Sentry 的 Developer 套餐及以上都可用。Webhook 本身不额外收费。
为什么我的 Sentry 模板变量是空的?
几乎总是因为路径太短。告警载荷把事件嵌在 data.event 下,所以要写 {{data.event.title}} 而不是 {{title}}。触发一次频道,在应用里查看记录下来的请求体,就能看到你实际收到的结构。
怎么只对某一个环境告警?
设置 Sentry 告警规则上的 Environment 字段。别试图从 data.event.tags 里读——那是一个 [键, 值] 对数组,顺序没有保证。
同一个错误能同时打给两个人吗?
可以。共享频道,让每个人用自己想要的通知类型订阅。因为没有确认机制,所以选了「来电」的人都会被打电话。
过滤应该放在 Sentry 还是 Echobell?
能放 Sentry 就放 Sentry——节流和环境范围也都在规则里。放 Echobell 更合适的情况是:你想从一条规则里分出两档紧急程度、你需要一个按时段的窗口、或者你今天改不动那条规则。
小结
整套东西就四件:一个来电频道、一个打开了 Alert Rule Action 且 Webhooks 复选框全不勾的 internal integration、一条窄到配得上一通电话的告警规则,以及会读 data.event 的模板。这一页上剩下的所有内容,都是为了让它一个月之后还足够窄,让那声铃响仍然有意义。
在 iPhone 上下载 Echobell 或在 Google Play 获取,然后先把上面那条 curl 发一次,再把任何真正重要的事情托付给这条链路。