Telegraf webhooks mandrill 插件:接收 Mandrill 邮件事件 Webhook 并生成监控指标
Telegraf 的 webhooks 输入插件内置了 Mandrill(Mailchimp 旗下事务性邮件服务)的 Webhook 接收器,可以把邮件投递事件(如 send、hard_bounce、open、click 等)实时转换为 mandrill_webhooks 指标。读完本文,你将知道如何在 Mandrill 控制台配置 Webhook、在 Telegraf 中启用该监听端点、理解请求体解析流程(application/x-www-form-urlencoded + mandrill_events 参数),以及最终产出的指标标签与字段结构。
工作原理与总体架构
Mandrill 在消息生命周期发生事件时,会向配置的 URL 发起 HTTP POST 请求。在 Telegraf 中,[[inputs.webhooks]] 是一个 service input:它在启动时开启一个 HTTP 服务(默认监听 :1619),并为每个已配置的 webhook 子模块注册独立的 URL 路径。Mandrill 接收器注册在默认路径 /mandrill 上。
从源码看,整体调用链如下(见 webhooks.go):
Webhooks.Start()创建gorilla/mux路由器,遍历结构体中所有实现了Webhook接口的字段并调用其Register();mandrill.Webhook.Register()(见 mandrill_webhooks.go)把两个处理器挂到同一路径上:HEAD /mandrill→returnOK,仅返回200,用于连通性探测;POST /mandrill→md.eventHandler,真正的事件处理逻辑;
- 事件处理完成后调用
acc.AddFields("mandrill_webhooks", ...),指标即进入 Telegraf 管道,流向已配置的 output。
由于 webhooks 是 service 插件,它不受 interval 驱动,--test、--once 等命令也不会产生输出(参见 webhooks 插件 README)。
在 Mandrill 控制台配置 Webhook
按照 mandrill/README.md 的操作步骤:
- 登录 mandrillapp.com,进入
Settings > Webhooks; - 点击
Add a Webhook; - 勾选全部事件类型(all events);
- 将
URL设置为http://<my_ip>:1619/mandrill(<my_ip>替换为运行 Telegraf 实例的地址,端口为service_address配置的端口); - 点击
Create Webhook。
各事件类型的 JSON 字段格式参考 Mandrill 官方 Message Event Webhook format 文档(原文链接见 mandrill/README.md)。
在 Telegraf 中启用 mandrill webhook
<a href="https://link.gitcode.com/i/ccf6abd9c0005278db3efbb0008e97b9" target="_blank">[inputs.webhooks]] 的完整样例配置(完整版本见 [sample.conf):
# A Webhooks Event collector
[[inputs.webhooks]]
## Address and port to host Webhook listener on
service_address = ":1619"
## Maximum duration before timing out read of the request
# read_timeout = "10s"
## Maximum duration before timing out write of the response
# write_timeout = "10s"
[inputs.webhooks.mandrill]
path = "/mandrill"
## HTTP basic auth
#username = ""
#password = ""
各配置项说明:
| 配置项 | 默认值 | 说明 |
|---|---|---|
service_address |
:1619 |
webhook 服务监听的地址和端口 |
read_timeout |
10s |
读取请求体的最大时长,小于 1 秒的值会被重置为 10 秒(见 webhooks.go 中的 Start() 逻辑) |
write_timeout |
10s |
写出响应的最大时长,同样有最小值保护 |
[inputs.webhooks.mandrill] path |
/mandrill |
Mandrill 事件接收的 URL 路径 |
[inputs.webhooks.mandrill] username / password |
空 | 可选的 HTTP Basic Auth 凭据 |
关于 Basic Auth 的一个细节值得注意:从 basic_auth.go 的实现看,当 username 和 password 都为空时,Verify() 直接返回 true,即不做任何鉴权;只有配置了非空凭据后才对请求执行常量时间比较校验。生产环境中建议在 Mandrill 侧配合使用 Basic Auth 凭据,避免端点被任意第三方调用。
请求解析流程:eventHandler 逐行拆解
Mandrill 发送的 POST 请求体是 application/x-www-form-urlencoded 格式,其中 mandrill_events 参数是一个 JSON 编码的事件数组。源码中的处理顺序(mandrill_webhooks.go):
md.Verify(r)校验 Basic Auth(若配置),失败返回401 Unauthorized;io.ReadAll(r.Body)读取完整请求体,失败返回400 Bad Request;url.ParseQuery(string(body))解析表单,取出mandrill_events参数值,失败返回400;json.Unmarshal将参数值反序列化为[]mandrillEvent,失败返回400;- 遍历事件数组,为每个事件调用
acc.AddFields("mandrill_webhooks", event.fields(), event.tags(), time.Unix(event.TimeStamp, 0))—— 注意时间戳取自事件自身的ts字段(Unix 秒),而非接收时间; - 全部成功后返回
200 OK。
产出的指标:标签与字段
每个 webhook 事件生成一条 mandrill_webhooks 测量,结构与 mandrill/README.md 描述一致:
- 时间戳:事件原始时间(
ts) - Tags:
event= 事件名称(来自事件 JSON 的event字段,如send、hard_bounce)
- Fields:
id= 事件唯一标识(来自event._id字段)
事件结构定义在 mandrill_webhooks_events.go:
type mandrillEvent struct {
EventName string `json:"event"`
TimeStamp int64 `json:"ts"`
ID string `json:"_id"`
}
从源码结构看,接收器只从每个事件中提取 event、ts、_id 三个顶层字段;事件内嵌的 msg 对象(收件人、主题、退信原因 diag、bounce_description 等)虽然会随请求到达,但不直接成为指标字段。因此该插件的定位是事件级监控(发送量、退信次数、打开/点击频次),而非逐封邮件的内容分析;如果需要在查询侧关联邮件详情,可以基于 id 字段与 Mandrill API 查询结果做关联。
用测试用例验证端到端行为
mandrill_webhooks_test.go 提供了三个值得参考的验证场景:
TestHead:确认HEAD /mandrill返回200,可直接用于健康检查;TestSendEvent:模拟一次send事件推送,断言产生id=id1、event=send的指标(测试数据为 testdata/send_event.json);TestMultipleEvents:一次 POST 中同时推送send与hard_bounce两个事件,断言两条指标都被正确生成(数据见 testdata/hard_bounce_event.json)——这印证了 Mandrill 支持批量推送事件数组的行为。
可以手动复刻同样的请求来验证部署是否生效:
curl -X POST "http://<my_ip>:1619/mandrill" \
--data-urlencode 'mandrill_events=[{"event":"send","ts":1384954004,"_id":"test-id-1"}]' \
-I
请求成功后应看到 200,随后在 Telegraf 的 output 中出现一条 mandrill_webhooks 指标。
小结与适用边界
inputs.webhooks 的 mandrill 接收器是一个轻量、无状态的事件到指标转换器:HEAD 探活、POST 解析、Basic Auth 可选、多事件批量处理、按事件自身时间戳打点。配置 path 时若与其他子模块冲突,mux 路由器会按注册的路径分别处理,多个 webhook 子模块可以共存于同一个 :1619 端口;监听地址、超时等全局行为统一由 <a href="https://link.gitcode.com/i/68f0c3aec73527f92be0a5b16acb320f" target="_blank">[inputs.webhooks]] 顶层配置控制,完整参数以 [sample.conf 与 webhooks.go 中的结构体字段为准。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.24 K638- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python670
SlideSCIPPT插件,支持素材库、AI助手、一键添加图片标题,复制粘贴位置、一键图片对齐、一键插入Markdown(加粗、超链接等行内样式、代码块、LaTeX等块级样式)、便捷导出图片!C#230
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python52874
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go22545
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java36351